Skip to content
This repository has been archived by the owner on Apr 2, 2023. It is now read-only.

Parsing improvements #7

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Bug fixes, updated demo, moved docs to wiki
Reese Jacobson committed Sep 2, 2020
commit 7b3d0df3b1eb888ea498ad8c2755c0fb76761450
11 changes: 3 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ personal pronoun helper module. fork of [pronoun.is](https://github.com/witch-ho

`pronouns.js` aims to be an easy way to handle numerous personal pronouns in English. It remains open-ended to allow for myriad use cases. One possible application could be in a social media service in which users can add their pronoun(s) and the interface can refer to them properly.

Play the demo [here](https://katacarbix.github.io/pronouns.js/demo/index.html).
Check out the demo [here](https://katacarbix.github.io/pronouns.js/demo/index.html).

## Basic usage

@@ -44,15 +44,10 @@ they | them | their | theirs | themself

**`index.js`** is the main program. `pronouns` is both a function you can call with a string parameter, and an object with references to the table and a few methods.

All of the following are valid inputs to the `pronouns` function:

* she
* he/him
* ze/hir or they/.../themselves
* she/her, they/them, it/its, or sie/hir

**`util.js`** has most of what was translated from the original Clojure code. These functions are mostly meant for accessing rows in a table or formatting strings and is not needed for typical users, but is exposed nonetheless as `pronouns.util`.

For further documentation, check out [the wiki](https://github.com/katacarbix/pronouns.js/wiki).

## Tests

The `test/` directory contains unit tests for `index.js` and `util.js`. Please run the tests and confirm that everything passes before merging changes, and please include tests with any new logic you introduce in a PR!
96 changes: 56 additions & 40 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -2,23 +2,32 @@
<html lang="en" dir="ltr">
<head>
<title>pronouns.js demo</title>

<!-- Meta -->
<meta charset="utf-8">
<meta name="description" content="Enter your pronouns and watch as forms and examples are automatically generated.">
<meta name="robots" content="noindex, nofollow">

<!--Let browser know website is optimized for mobile-->
<meta name="robots" content="noarchive">
<meta name="theme-color" content="#e83e8c">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<!-- Font Awesome icon font -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/brands.min.css" integrity="sha512-AMDXrE+qaoUHsd0DXQJr5dL4m5xmpkGLxXZQik2TvR2VCVKT/XRPQ4e/LTnwl84mCv+eFm92UG6ErWDtGM/Q5Q==" crossorigin="anonymous" />
<!-- Social media cards -->
<meta property="og:title" content="pronouns.js">
<meta property="og:description" content="Enter your pronouns and watch as forms and examples are automatically generated.">
<meta property="og:image" content="thumbnail.png">
<meta property="og:url" content="https://katacarbix.github.io/pronouns.js/demo/">

<meta name="twitter:title" content="pronouns.js">
<meta name="twitter:description" content="Enter your pronouns and watch as forms and examples are automatically generated.">
<meta name="twitter:image" content="thumbnail.png">
<meta name="twitter:card" content="summary_large_image">

<!-- Stylesheets -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha256-Ww++W3rXBfapN8SZitAvc9jw2Xb+Ixt0rvDsmWmQyTo=" crossorigin="anonymous">

<!-- Compiled and minified JavaScript -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/xcash/[email protected]/dist/latest/bootstrap-autocomplete.min.js"></script>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js" integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha256-ecWZ3XYM7AwWIaGvSdmipJ2l1F4bN9RXW6zgpeAiZYI=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/latest/bootstrap-autocomplete.min.js" integrity="sha256-45Sn5xV9Nf28PJXGyykcRK7M3fM7oSQwwVI9+FZEAGs=" crossorigin="anonymous"></script>
</head>
<body class="d-flex flex-column" style="overflow-y:scroll;min-height:100vh;">
<main class="py-3 flex-grow-1 flex-shrink-0">
@@ -42,17 +51,8 @@ <h1 class="display-4">pronouns.js</h1>
<div class="row overflow-auto">
<div class="col">
<table class="table table-bordered">
<thead class="thead-light">
<tr>
<th scope="col">Subject</th>
<th scope="col">Object</th>
<th scope="col">Determiner</th>
<th scope="col">Possessive</th>
<th scope="col">Reflexive</th>
</tr>
</thead>
<tbody>
</tbody>
<thead class="thead-light"></thead>
<tbody></tbody>
</table>
</div>
</div>
@@ -72,7 +72,7 @@ <h1 class="display-4">pronouns.js</h1>
<footer class="bg-light border-top" style="">
<div class="container py-3 text-muted small">
Written with ❤ by <a href="https://github.com/katacarbix" target="_blank">Reese Jacobson</a>, whose <a href="https://pronoun.is/they/.../themself" target="_blank">pronoun.is/they</a>.<br>
Pronouns.js is a fork of <a href="https://github.com/witch-house/pronoun.is" target="_blank">pronoun.is</a> and is free software under the <a href="https://github.com/katacarbix/pronouns.js/blob/master/LICENSE" target="_blank">AGPLv3</a>.
Pronouns.js is a fork of <a href="https://github.com/witch-house/pronoun.is" target="_blank">Pronoun Island</a> and is free software under the <a href="https://github.com/katacarbix/pronouns.js/blob/master/LICENSE" target="_blank">AGPLv3</a>.
</div>
</footer>

@@ -92,28 +92,44 @@ <h1 class="display-4">pronouns.js</h1>
});

$('#pronouns').on('input autocomplete.select', function(){
var p = pronouns(this.value);
var p = pronouns(this.value, {log:false});
var rows = ``;
var examples = ``;
var url = p.toUrl();

if (p.pronouns.length > 0) $('thead').html(`
<tr>
<th scope="col">Subject</th>
<th scope="col">Object</th>
<th scope="col">Determiner</th>
<th scope="col">Possessive</th>
<th scope="col">Reflexive</th>
</tr>`);
else $('thead').html(``);

if (p.any) examples += `
<li class="list-group-item overflow-auto">
Any pronouns are acceptable.
</li>`;
for (var i = 0, row; row = p.pronouns[i]; i++){
if (!pronouns.util.rowsEqual(row,['','','','',''])){
rows += `
<tr>
<td scope="row">${row[0]}</td>
<td>${row[1]}</td>
<td>${row[2]}</td>
<td>${row[3]}</td>
<td>${row[4]}</td>
</tr>`;
if (!row.includes('')) examples += `
<li class="list-group-item overflow-auto">
${p.examples[i].join('<br>').replace(/\*(\w+)\*/g, "<strong>$1</strong>")}
</li>`;
}
rows += `
<tr>
<td scope="row">${row[0]}</td>
<td>${row[1]}</td>
<td>${row[2]}</td>
<td>${row[3]}</td>
<td>${row[4]}</td>
</tr>`;
examples += `
<li class="list-group-item overflow-auto">
${p.examples_html[i].join('<br>')}
</li>`;
}

$('tbody').html(rows);
$('#examples').html(examples);
$('#pronoun-island-link').html(`<a href="${p.toUrl()}" target="_blank" class="btn btn-outline-primary">${p.toUrl()}</a>`);
if (url.length > 19) $('#pronoun-island-link').html(`<a href="${url}" target="_blank" class="btn btn-outline-primary">${url}</a>`);
else $('#pronoun-island-link').html(``);
});

</script>
Binary file added demo/thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 28 additions & 20 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -139,6 +139,9 @@ module.exports = {
sanitizeSet: function(p, table){
var out = [];
for (var row of p){
if (row.length < 1) continue;
if (row.length == 1 && row[0].match(/\b(or|and)\b/)) continue;

var match = this.tableLookup(row, table);
if (!match){
var expansions = [];
@@ -156,12 +159,7 @@ module.exports = {
else expansions.push(match);
}
if (!badMatch){
out = out.concat(expansions.filter(e => {
for (var p of out){
if (util.rowsEqual(p,e)) return false;
}
return true;
}));
out = out.concat(expansions);
continue;
}

@@ -171,20 +169,25 @@ module.exports = {
}

if (this.logging) console.warn(`Unrecognized pronoun(s) "${row.join('/')}". This may lead to unexpected behavior.`);
while (row.length < 5){
row.push('');
}
if (row.length > 5){
row = row.slice(0,5);
if (row.length >= 5){
if (row.length > 5){
row = row.slice(0,5);
}
if (!row.includes('')) out.push(row);
}
out.push(row);
} else out.push(match);
}
out = out.filter((row,i) => {
for (var p of out.slice(0,i)){
if (this.rowsEqual(p,row)) return false;
}
return true;
});
return out;
},

expandString: function(str, table){
return this.sanitizeSet(str.trim().split(' ').filter(p => !p.match(/[Oo][Rr]/g)).map(p => p.replace(/[^a-zA-Z\/'.]/, '').toLowerCase().split('/')), table);
return this.sanitizeSet(str.trim().split(' ').map(p => p.replace(/[^a-zA-Z\/'.]/, '').toLowerCase().split('/')), table);
},

// wrap a value <x> in an array if it is not already in one.
@@ -225,8 +228,14 @@ class Pronouns {
return util.expandString(input, table); // passed a string, most common case.
}
else if (typeof input === "object"){
if (input.pronouns && Array.isArray(input.pronouns)) return util.sanitizeSet(input.pronouns, table); // passed a pronouns-like object.
else if (Array.isArray(input)) return util.sanitizeSet(input, table); // passed an array representing some pronouns.
if (Array.isArray(input.pronouns)){ // passed a Pronouns-like object.
if (input.any) this.any = input.any;
return util.sanitizeSet(input.pronouns, table);
}
else if (Array.isArray(input)){ // passed an array representing some pronouns.
if (!this.hasOwnProperty('any') || !this.any) this.any = input.flat().some(p => p.match(/(\b(any(thing)?|all)\b|\*)/));
return util.sanitizeSet(input, table);
}
}
if (logging) console.warn("Unrecognized input. Defaulting to they/them.");
return util.tableLookup(['they'], table);
@@ -302,9 +311,8 @@ class Pronouns {
}
}

module.exports = (input, log) => {
logging = !!log; // convert it to a boolean value
util.logging = logging;
module.exports = (input, options) => {
logging = util.logging = (typeof options === "object" && options.hasOwnProperty('log')) ? !!options.log : logging;
return new Pronouns(input);
}
module.exports.complete = (input) => {
@@ -314,8 +322,8 @@ module.exports.complete = (input) => {
// Generate list of matching rows
var matches = [];
if (last.length == 0){
matches = table.slice(); // Clones the table so it doesn't get changed
if (!rest.match(/[Oo][Rr]\s$/g)) matches.unshift(['or']);
matches = table.slice(); // Clone the table so it doesn't get changed
if (!rest.match(/(^|or|and)\s*?$/)) matches.unshift(['or']);
} else {
var parts = last.split('/');
var end = parts.pop();
49 changes: 0 additions & 49 deletions docs/completion.md

This file was deleted.

87 changes: 0 additions & 87 deletions docs/documentation.md

This file was deleted.

19 changes: 12 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -15,8 +15,14 @@ class Pronouns {
return util.expandString(input, table); // passed a string, most common case.
}
else if (typeof input === "object"){
if (input.pronouns && Array.isArray(input.pronouns)) return util.sanitizeSet(input.pronouns, table); // passed a pronouns-like object.
else if (Array.isArray(input)) return util.sanitizeSet(input, table); // passed an array representing some pronouns.
if (Array.isArray(input.pronouns)){ // passed a Pronouns-like object.
if (input.any) this.any = input.any;
return util.sanitizeSet(input.pronouns, table);
}
else if (Array.isArray(input)){ // passed an array representing some pronouns.
if (!this.hasOwnProperty('any') || !this.any) this.any = input.flat().some(p => p.match(/(\b(any(thing)?|all)\b|\*)/));
return util.sanitizeSet(input, table);
}
}
if (logging) console.warn("Unrecognized input. Defaulting to they/them.");
return util.tableLookup(['they'], table);
@@ -92,9 +98,8 @@ class Pronouns {
}
}

module.exports = (input, log) => {
logging = !!log; // convert it to a boolean value
util.logging = logging;
module.exports = (input, options) => {
logging = util.logging = (typeof options === "object" && options.hasOwnProperty('log')) ? !!options.log : logging;
return new Pronouns(input);
}
module.exports.complete = (input) => {
@@ -104,8 +109,8 @@ module.exports.complete = (input) => {
// Generate list of matching rows
var matches = [];
if (last.length == 0){
matches = table.slice(); // Clones the table so it doesn't get changed
if (!rest.match(/[Oo][Rr]\s$/g)) matches.unshift(['or']);
matches = table.slice(); // Clone the table so it doesn't get changed
if (!rest.match(/(^|or|and)\s*?$/)) matches.unshift(['or']);
} else {
var parts = last.split('/');
var end = parts.pop();
29 changes: 16 additions & 13 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -94,6 +94,9 @@ module.exports = {
sanitizeSet: function(p, table){
var out = [];
for (var row of p){
if (row.length < 1) continue;
if (row.length == 1 && row[0].match(/\b(or|and)\b/)) continue;

var match = this.tableLookup(row, table);
if (!match){
var expansions = [];
@@ -111,12 +114,7 @@ module.exports = {
else expansions.push(match);
}
if (!badMatch){
out = out.concat(expansions.filter(e => {
for (var p of out){
if (util.rowsEqual(p,e)) return false;
}
return true;
}));
out = out.concat(expansions);
continue;
}

@@ -126,20 +124,25 @@ module.exports = {
}

if (this.logging) console.warn(`Unrecognized pronoun(s) "${row.join('/')}". This may lead to unexpected behavior.`);
while (row.length < 5){
row.push('');
}
if (row.length > 5){
row = row.slice(0,5);
if (row.length >= 5){
if (row.length > 5){
row = row.slice(0,5);
}
if (!row.includes('')) out.push(row);
}
out.push(row);
} else out.push(match);
}
out = out.filter((row,i) => {
for (var p of out.slice(0,i)){
if (this.rowsEqual(p,row)) return false;
}
return true;
});
return out;
},

expandString: function(str, table){
return this.sanitizeSet(str.trim().split(' ').filter(p => !p.match(/[Oo][Rr]/g)).map(p => p.replace(/[^a-zA-Z\/'.]/, '').toLowerCase().split('/')), table);
return this.sanitizeSet(str.trim().split(' ').map(p => p.replace(/[^a-zA-Z\/'.]/, '').toLowerCase().split('/')), table);
},

// wrap a value <x> in an array if it is not already in one.
2 changes: 1 addition & 1 deletion test/utilTests.js
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ const listAbbr = require('./abbreviatedList.json');
assert.deepStrictEqual( util.sanitizeSet([['she', 'they']], list), sample3_Expected );
assert.deepStrictEqual( util.sanitizeSet([['her', 'them']], list), sample3_Expected );
assert.deepStrictEqual( util.sanitizeSet([['any']], list), [] );
assert.deepStrictEqual( util.sanitizeSet([['a', 'b'], ['a', 'b', 'c', 'd', 'e', 'f', 'g']], list), [['a', 'b', '', '', ''], ['a', 'b', 'c', 'd', 'e']] );
assert.deepStrictEqual( util.sanitizeSet([['a', 'b'], ['a', 'b', 'c', 'd', 'e', 'f', 'g']], list), [['a', 'b', 'c', 'd', 'e']] );

assert.deepStrictEqual( util.expandString(sample3_String, list), sample3_Expected );