2020-10-28 06:18:24 -07:00
|
|
|
import {buildDict, buildList, capitalise} from "./helpers";
|
2020-11-10 15:47:44 -08:00
|
|
|
import MORPHEMES from '../data/pronouns/morphemes';
|
2020-07-26 04:14:25 -07:00
|
|
|
|
2020-11-28 07:52:48 -08:00
|
|
|
const config = process.env.CONFIG || global.config;
|
|
|
|
|
2020-07-22 13:19:23 -07:00
|
|
|
export class ExamplePart {
|
|
|
|
constructor(variable, str) {
|
|
|
|
this.variable = variable;
|
|
|
|
this.str = str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Example {
|
2020-07-25 10:21:52 -07:00
|
|
|
constructor(singularParts, pluralParts, isHonorific = false) {
|
|
|
|
this.singularParts = singularParts;
|
|
|
|
this.pluralParts = pluralParts;
|
|
|
|
this.isHonorific = isHonorific;
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static parse(str) {
|
|
|
|
const parts = [];
|
|
|
|
let lastPosition = 0;
|
|
|
|
|
2020-10-28 06:18:24 -07:00
|
|
|
for (let m of str.matchAll(/{('?[a-z_]+)}/g)) {
|
2020-07-22 13:19:23 -07:00
|
|
|
const textBefore = str.substr(lastPosition, m.index - lastPosition);
|
|
|
|
if (textBefore.length) {
|
|
|
|
parts.push(new ExamplePart(false, textBefore));
|
|
|
|
}
|
|
|
|
parts.push(new ExamplePart(true, m[0].substr(1, m[0].length - 2)));
|
|
|
|
lastPosition = m.index + m[0].length;
|
|
|
|
}
|
|
|
|
|
|
|
|
const textAfter = str.substr(lastPosition);
|
|
|
|
if (textAfter.length) {
|
|
|
|
parts.push(new ExamplePart(false, textAfter));
|
|
|
|
}
|
|
|
|
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
2020-11-10 14:41:56 -08:00
|
|
|
format(pronoun) {
|
|
|
|
const plural = this.isHonorific ? pronoun.pluralHonorific[0] : pronoun.plural[0];
|
2020-07-22 13:19:23 -07:00
|
|
|
|
2020-11-10 14:41:56 -08:00
|
|
|
return capitalise(this[plural ? 'pluralParts' : 'singularParts'].map(part => {
|
|
|
|
return part.variable ? pronoun.getMorpheme(part.str) : part.str;
|
|
|
|
}).join(''));
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
2020-11-28 07:52:48 -08:00
|
|
|
|
|
|
|
pronounce(pronoun) {
|
|
|
|
const plural = this.isHonorific ? pronoun.pluralHonorific[0] : pronoun.plural[0];
|
|
|
|
|
|
|
|
let interchangable = false;
|
|
|
|
|
|
|
|
const buildPronunciation = m => {
|
|
|
|
if (pronoun.isInterchangable(m)) {
|
|
|
|
interchangable = true;
|
|
|
|
}
|
|
|
|
const pronunciation = pronoun.getPronunciation(m);
|
|
|
|
const morpheme = pronoun.getMorpheme(m);
|
|
|
|
|
|
|
|
return pronunciation
|
|
|
|
? `<phoneme alphabet="ipa" ph="${pronunciation}">${morpheme}</phoneme>`
|
|
|
|
: morpheme;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ssml = '<speak>' + this[plural ? 'pluralParts' : 'singularParts'].map(part => {
|
|
|
|
return part.variable
|
|
|
|
? buildPronunciation(part.str)
|
|
|
|
: part.str;
|
|
|
|
}).join('') + '</speak>';
|
|
|
|
|
|
|
|
if (interchangable) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ssml;
|
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.singularParts.map(part => part.variable ? '{' + part.str + '}' : part.str).join('')
|
|
|
|
+ '|'
|
|
|
|
+ this.pluralParts.map(part => part.variable ? '{' + part.str + '}' : part.str).join('')
|
|
|
|
+ '|'
|
|
|
|
+ (this.isHonorific ? '1' : '0');
|
|
|
|
}
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function clone(mainObject) {
|
|
|
|
let objectCopy = {};
|
|
|
|
for (let key in mainObject) {
|
|
|
|
if (mainObject.hasOwnProperty(key)) {
|
|
|
|
objectCopy[key] = mainObject[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return objectCopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Source {
|
2020-12-04 13:09:57 -08:00
|
|
|
constructor ({id, pronouns, type, author, title, extra, year, fragments = '', comment = null, link = null, submitter = null, approved, base_id = null,}) {
|
|
|
|
this.id = id;
|
|
|
|
this.pronouns = pronouns ? pronouns.split(';') : [];
|
2020-07-25 10:21:52 -07:00
|
|
|
this.type = type;
|
2020-07-22 13:19:23 -07:00
|
|
|
this.author = author;
|
|
|
|
this.title = title;
|
|
|
|
this.extra = extra;
|
|
|
|
this.year = year;
|
2020-12-04 13:09:57 -08:00
|
|
|
this.fragments = fragments ? fragments.replace(/\|/g, '\n').split('@') : [];
|
2020-07-22 13:19:23 -07:00
|
|
|
this.comment = comment;
|
|
|
|
this.link = link;
|
2020-12-03 06:01:26 -08:00
|
|
|
this.submitter = submitter;
|
2020-12-04 13:09:57 -08:00
|
|
|
this.approved = approved;
|
|
|
|
this.base_id = base_id;
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
2020-07-27 10:06:41 -07:00
|
|
|
static get TYPES() {
|
|
|
|
return {
|
2020-09-28 08:51:26 -07:00
|
|
|
'': 'clipboard-list',
|
|
|
|
Book: 'book-open',
|
|
|
|
Article: 'newspaper',
|
2020-12-02 11:58:05 -08:00
|
|
|
Movie: 'film',
|
2020-09-28 08:51:26 -07:00
|
|
|
Series: 'tv',
|
|
|
|
Song: 'music',
|
|
|
|
Poetry: 'scroll',
|
|
|
|
Other: 'comment-alt-lines',
|
2020-07-27 10:06:41 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-09 11:11:47 -08:00
|
|
|
static get TYPES_PRIORITIES() {
|
|
|
|
return {
|
|
|
|
Book: 1,
|
|
|
|
Article: 2,
|
|
|
|
Movie: 3,
|
|
|
|
Series: 3,
|
|
|
|
Song: 0,
|
|
|
|
Poetry: 0,
|
|
|
|
Other: 4,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 13:19:23 -07:00
|
|
|
icon() {
|
2020-09-30 12:59:41 -07:00
|
|
|
return Source.TYPES[this.type];
|
2020-07-24 04:25:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-04 13:09:57 -08:00
|
|
|
|
|
|
|
export class SourceLibrary {
|
|
|
|
constructor(rawSources) {
|
|
|
|
this.sources = rawSources.map(s => new Source(s));
|
|
|
|
this.map = {};
|
|
|
|
const multiple = new Set();
|
|
|
|
const pronouns = new Set();
|
2020-12-05 11:37:10 -08:00
|
|
|
this.countApproved = 0;
|
|
|
|
this.countPending = 0;
|
2020-12-04 13:09:57 -08:00
|
|
|
|
|
|
|
for (let source of this.sources) {
|
2020-12-05 11:37:10 -08:00
|
|
|
this[source.approved ? 'countApproved' : 'countPending']++;
|
|
|
|
|
2020-12-04 13:09:57 -08:00
|
|
|
if (!source.pronouns.length) {
|
|
|
|
if (this.map[''] === undefined) { this.map[''] = []; }
|
|
|
|
this.map[''].push(source);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (let pronoun of source.pronouns) {
|
|
|
|
if (this.map[pronoun] === undefined) { this.map[pronoun] = []; }
|
|
|
|
this.map[pronoun].push(source);
|
|
|
|
|
|
|
|
pronouns.add(pronoun);
|
|
|
|
if (pronoun.includes('&')) {
|
|
|
|
multiple.add(pronoun);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.pronouns = [...pronouns];
|
|
|
|
this.multiple = [...multiple];
|
|
|
|
this.cache = {}
|
|
|
|
}
|
|
|
|
|
2020-12-05 11:54:36 -08:00
|
|
|
getForPronoun(pronoun, pronounLibrary = null) {
|
2020-12-04 13:09:57 -08:00
|
|
|
if (this.cache[pronoun] === undefined) {
|
|
|
|
let sources = this.map[pronoun] || [];
|
|
|
|
|
|
|
|
if (pronoun === '') {
|
|
|
|
for (let p of this.pronouns) {
|
2020-12-05 11:54:36 -08:00
|
|
|
if (!pronounLibrary.isCanonical(p)) {
|
2020-12-04 13:09:57 -08:00
|
|
|
sources = [...sources, ...this.map[p]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.cache[pronoun] = sources
|
|
|
|
.map(s => this.addMetaData(s))
|
|
|
|
.sort((a, b) => {
|
|
|
|
if (a.typePriority !== b.typePriority) {
|
|
|
|
return b.typePriority - a.typePriority;
|
|
|
|
}
|
|
|
|
|
|
|
|
return a.sortString.localeCompare(b.sortString);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.cache[pronoun];
|
|
|
|
}
|
|
|
|
|
|
|
|
getForPronounExtended(pronoun) {
|
|
|
|
let sources = {};
|
|
|
|
const s = this.getForPronoun(pronoun);
|
|
|
|
sources[pronoun] = s.length ? s : undefined;
|
|
|
|
|
|
|
|
if (pronoun.includes('&')) {
|
|
|
|
for (let option of pronoun.split('&')) {
|
|
|
|
const s = this.getForPronoun(option);
|
|
|
|
sources[option] = s.length ? s : undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sources;
|
|
|
|
}
|
|
|
|
|
|
|
|
addMetaData(source) {
|
|
|
|
source.typePriority = Source.TYPES_PRIORITIES[source.type];
|
|
|
|
|
|
|
|
source.sortString = source.author || 'ZZZZZ' + source.title; // if no author, put on the end
|
|
|
|
if (source.sortString.includes('^')) {
|
|
|
|
const index = source.sortString.indexOf('^');
|
|
|
|
source.sortString = source.sortString.substring(index + 1) + ' ' + source.sortString.substring(0, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
source.index = [
|
|
|
|
(source.author || '').replace('^', ''),
|
|
|
|
source.title,
|
|
|
|
source.extra,
|
|
|
|
source.year,
|
|
|
|
//...source.fragments,
|
|
|
|
source.comment,
|
|
|
|
source.link,
|
2020-12-05 11:37:10 -08:00
|
|
|
source.approved ? '' : '__awaiting__',
|
2020-12-04 13:09:57 -08:00
|
|
|
].join(' ').toLowerCase().replace(/<\/?[^>]+(>|$)/g, '');
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-22 13:19:23 -07:00
|
|
|
const escape = s => {
|
2020-07-26 04:14:25 -07:00
|
|
|
if (Array.isArray(s)) {
|
|
|
|
s = s.join('&');
|
|
|
|
}
|
2020-07-22 13:19:23 -07:00
|
|
|
return (s || '')
|
2020-07-24 13:11:34 -07:00
|
|
|
.replace(/,/g, '')
|
|
|
|
.replace(/!/g, '')
|
|
|
|
.replace(/\./g, '')
|
|
|
|
//.replace(/\/', '%2F')
|
|
|
|
.replace(/#/g, '%23')
|
2020-07-26 04:14:25 -07:00
|
|
|
.replace(/\?/g, '%3F');
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
export class Pronoun {
|
2020-12-10 07:23:39 -08:00
|
|
|
constructor (canonicalName, description, normative, morphemes, plural, pluralHonorific, aliases = [], history = '', pronounceable = true, thirdForm = null, smallForm = null, sourcesInfo = null) {
|
2020-09-05 12:45:30 -07:00
|
|
|
this.canonicalName = canonicalName;
|
2020-07-22 13:19:23 -07:00
|
|
|
this.description = description;
|
2020-09-16 13:31:57 -07:00
|
|
|
this.normative = normative;
|
2020-11-28 07:52:48 -08:00
|
|
|
this.morphemes = {}
|
|
|
|
this.pronunciations = {}
|
|
|
|
for (let m in morphemes) {
|
|
|
|
if (!morphemes.hasOwnProperty(m)) { continue; }
|
|
|
|
const [morpheme, pronunciation] = morphemes[m] ? morphemes[m].split('|') : [null, null];
|
|
|
|
this.morphemes[m] = morpheme;
|
|
|
|
this.pronunciations[m] = pronunciation;
|
|
|
|
}
|
2020-07-22 13:19:23 -07:00
|
|
|
this.plural = plural;
|
2020-07-25 10:21:52 -07:00
|
|
|
this.pluralHonorific = pluralHonorific;
|
2020-07-24 07:26:03 -07:00
|
|
|
this.aliases = aliases;
|
2020-07-24 11:21:30 -07:00
|
|
|
this.history = history;
|
2020-11-28 07:52:48 -08:00
|
|
|
this.pronounceable = pronounceable;
|
2020-12-10 07:23:39 -08:00
|
|
|
this.thirdForm = thirdForm;
|
|
|
|
this.smallForm = smallForm;
|
|
|
|
this.sourcesInfo = sourcesInfo;
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pronoun() {
|
2020-09-29 06:36:49 -07:00
|
|
|
return this.morphemes[MORPHEMES[0]];
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
2020-07-26 04:14:25 -07:00
|
|
|
nameOptions() {
|
|
|
|
const options = new Set();
|
2020-09-29 06:36:49 -07:00
|
|
|
const optionsN = this.morphemes[MORPHEMES[0]].split('&');
|
2020-11-15 05:13:14 -08:00
|
|
|
const optionsG = this.morphemes[MORPHEMES[1]] === this.morphemes[MORPHEMES[0]]
|
|
|
|
? this.morphemes[MORPHEMES[2]].split('&')
|
|
|
|
: this.morphemes[MORPHEMES[1]].split('&');
|
2020-07-26 04:14:25 -07:00
|
|
|
for (let i in optionsN) {
|
2020-12-04 13:39:02 -08:00
|
|
|
let nameOption = optionsN[i] + '/' + optionsG[i < optionsG.length - 1 ? i : optionsG.length - 1];
|
2020-12-10 07:23:39 -08:00
|
|
|
if (this.thirdForm) {
|
|
|
|
nameOption += '/' + this.morphemes[this.thirdForm].split('&')[i];
|
2020-12-04 13:39:02 -08:00
|
|
|
}
|
2020-12-10 07:23:39 -08:00
|
|
|
|
2020-12-04 13:39:02 -08:00
|
|
|
options.add(nameOption);
|
2020-07-26 04:14:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return [...options]
|
|
|
|
}
|
|
|
|
|
2020-09-28 08:51:26 -07:00
|
|
|
name(glue) {
|
2020-07-26 04:14:25 -07:00
|
|
|
return this.nameOptions().join(glue)
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
clone() {
|
2020-12-04 13:09:57 -08:00
|
|
|
return new Pronoun(
|
|
|
|
this.canonicalName,
|
|
|
|
this.description,
|
|
|
|
this.normative,
|
|
|
|
clone(this.morphemes),
|
|
|
|
[...this.plural],
|
|
|
|
[...this.pluralHonorific],
|
|
|
|
[...this.aliases],
|
|
|
|
this.history,
|
|
|
|
this.pronounceable
|
|
|
|
);
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
equals(other) {
|
|
|
|
return this.toString() === other.toString();
|
|
|
|
}
|
|
|
|
|
2020-07-26 04:14:25 -07:00
|
|
|
merge(other) {
|
2020-11-10 15:47:44 -08:00
|
|
|
return new Pronoun(
|
2020-09-05 12:45:30 -07:00
|
|
|
this.canonicalName + '&' + other.canonicalName,
|
2020-07-26 04:14:25 -07:00
|
|
|
Array.isArray(this.description) ? [...this.description, other.description] : [this.description, other.description],
|
2020-09-16 13:46:15 -07:00
|
|
|
this.normative && other.normative,
|
2020-07-26 04:14:25 -07:00
|
|
|
buildDict(function* (that, other) {
|
|
|
|
for (let morpheme of MORPHEMES) {
|
|
|
|
yield [morpheme, (that.morphemes[morpheme] || '') + '&' + (other.morphemes[morpheme] || '')]
|
2020-10-12 14:28:26 -07:00
|
|
|
//yield [morpheme, buildMorpheme(that.morphemes[morpheme], that.plural) + '&' + buildMorpheme(other.morphemes[morpheme], other.plural)]
|
2020-07-26 04:14:25 -07:00
|
|
|
}
|
|
|
|
}, this, other),
|
2020-10-12 14:28:26 -07:00
|
|
|
[...this.plural, ...other.plural],
|
|
|
|
[...this.pluralHonorific, ...other.pluralHonorific],
|
2020-12-04 13:09:57 -08:00
|
|
|
[],
|
|
|
|
'',
|
2020-11-28 07:52:48 -08:00
|
|
|
false,
|
2020-07-26 04:14:25 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
getMorpheme(morpheme, counter = 0) {
|
2020-10-28 06:18:24 -07:00
|
|
|
let capital = false;
|
|
|
|
if (morpheme.startsWith("'")) {
|
|
|
|
capital = true;
|
|
|
|
morpheme = morpheme.substring(1);
|
|
|
|
}
|
|
|
|
|
2020-07-26 04:14:25 -07:00
|
|
|
if (!this.morphemes[morpheme]) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const options = this.morphemes[morpheme].split('&');
|
|
|
|
|
2020-10-28 06:18:24 -07:00
|
|
|
const result = options[counter % options.length];
|
|
|
|
|
|
|
|
return capital ? capitalise(result) : result;
|
2020-07-26 04:14:25 -07:00
|
|
|
}
|
|
|
|
|
2020-11-28 07:52:48 -08:00
|
|
|
getPronunciation(morpheme, counter = 0) {
|
2020-12-05 11:14:55 -08:00
|
|
|
if (morpheme.startsWith("'")) {
|
|
|
|
morpheme = morpheme.substring(1);
|
|
|
|
}
|
|
|
|
|
2020-11-28 07:52:48 -08:00
|
|
|
if (!this.pronunciations[morpheme]) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const options = this.pronunciations[morpheme].split('&');
|
|
|
|
|
|
|
|
return options[counter % options.length];
|
|
|
|
}
|
|
|
|
|
|
|
|
isInterchangable(morpheme) {
|
|
|
|
return (this.morphemes[morpheme.replace(/^'/, '')] || '').includes('&');
|
|
|
|
}
|
|
|
|
|
2020-10-12 14:28:26 -07:00
|
|
|
isPlural(counter = 0) {
|
|
|
|
return this.plural[counter % this.plural.length]
|
|
|
|
}
|
|
|
|
|
|
|
|
isPluralHonorific(counter = 0) {
|
|
|
|
return this.pluralHonorific[counter % this.pluralHonorific.length]
|
|
|
|
}
|
|
|
|
|
2020-12-08 14:14:40 -08:00
|
|
|
format(str) {
|
|
|
|
return str.replace(/{[^}]+}/g, m => this.morphemes[m.substring(1, m.length - 1)]);
|
|
|
|
}
|
|
|
|
|
2020-07-22 13:19:23 -07:00
|
|
|
toArray() {
|
2020-11-15 00:39:26 -08:00
|
|
|
const elements = Object.values(this.morphemes).map(s => escape(s));
|
2020-11-28 07:52:48 -08:00
|
|
|
Object.values(this.pronunciations).forEach((p, i) => {
|
|
|
|
if (p) {
|
|
|
|
elements[i] += '|' + escape(p);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (config.pronouns.plurals) {
|
2020-11-15 00:39:26 -08:00
|
|
|
elements.push(this.plural.map(p => p ? 1 : 0).join(''));
|
2020-11-28 07:52:48 -08:00
|
|
|
if (config.pronouns.honorifics) {
|
2020-11-15 00:39:26 -08:00
|
|
|
elements.push(this.pluralHonorific.map(p => p ? 1 : 0).join(''));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elements.push(escape(this.description));
|
|
|
|
return elements;
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
return this.toArray().join(',');
|
|
|
|
}
|
|
|
|
|
|
|
|
static from(data) {
|
2020-11-15 00:39:26 -08:00
|
|
|
let extraFields = 1; // description
|
|
|
|
|
2020-11-28 07:52:48 -08:00
|
|
|
if (config.pronouns.plurals) {
|
2020-11-15 00:39:26 -08:00
|
|
|
extraFields += 1;
|
|
|
|
if (![0, 1].includes(parseInt(data[MORPHEMES.length]))) {
|
|
|
|
return null;
|
|
|
|
}
|
2020-11-28 07:52:48 -08:00
|
|
|
if (config.pronouns.honorifics) {
|
2020-11-15 00:39:26 -08:00
|
|
|
extraFields += 1;
|
|
|
|
if (![0, 1].includes(parseInt(data[MORPHEMES.length + 1]))) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.length === MORPHEMES.length + extraFields - 1) {
|
2020-07-24 11:29:27 -07:00
|
|
|
data.push('');
|
|
|
|
}
|
|
|
|
|
2020-11-15 00:39:26 -08:00
|
|
|
if (data.length !== MORPHEMES.length + extraFields
|
2020-07-22 13:19:23 -07:00
|
|
|
|| data[0].length === 0
|
|
|
|
|| data[data.length - 1].length > 48
|
2020-11-28 07:52:48 -08:00
|
|
|
|| data.slice(1, data.length - extraFields).filter(s => s.length > 24).length
|
2020-07-22 13:19:23 -07:00
|
|
|
) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const m = {}
|
2020-07-25 10:21:52 -07:00
|
|
|
for (let i in MORPHEMES) {
|
|
|
|
m[MORPHEMES[parseInt(i)]] = data[parseInt(i)];
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
return new Pronoun(
|
2020-10-12 14:28:26 -07:00
|
|
|
m[MORPHEMES[0]],
|
|
|
|
data[data.length - 1],
|
|
|
|
false,
|
|
|
|
m,
|
|
|
|
data[MORPHEMES.length].split('').map(p => parseInt(p) === 1),
|
|
|
|
data[MORPHEMES.length + 1].split('').map(p => parseInt(p) === 1),
|
2020-12-04 13:09:57 -08:00
|
|
|
[],
|
|
|
|
null,
|
2020-11-28 07:52:48 -08:00
|
|
|
false,
|
2020-10-12 14:28:26 -07:00
|
|
|
)
|
2020-07-22 13:19:23 -07:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 07:15:41 -07:00
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
export class PronounGroup {
|
|
|
|
constructor(name, pronouns, description = null) {
|
2020-09-08 09:10:04 -07:00
|
|
|
this.name = name;
|
2020-11-10 15:47:44 -08:00
|
|
|
this.pronouns = pronouns;
|
2020-09-08 09:10:04 -07:00
|
|
|
this.description = description;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
export class PronounLibrary {
|
|
|
|
constructor(groups, pronouns) {
|
2020-09-08 09:10:04 -07:00
|
|
|
this.groups = groups;
|
2020-11-10 15:47:44 -08:00
|
|
|
this.pronouns = pronouns;
|
2020-12-05 11:37:10 -08:00
|
|
|
this.canonicalNames = Object.keys(this.pronouns);
|
2020-09-08 09:10:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
*split(filter = null, includeOthers = true) {
|
2020-11-10 15:47:44 -08:00
|
|
|
let pronounsLeft = Object.keys(this.pronouns);
|
2020-09-08 09:10:04 -07:00
|
|
|
const that = this;
|
|
|
|
|
|
|
|
for (let g of this.groups) {
|
|
|
|
yield [g, buildList(function* () {
|
2020-11-10 15:47:44 -08:00
|
|
|
for (let t of g.pronouns) {
|
|
|
|
pronounsLeft = pronounsLeft.filter(i => i !== t);
|
|
|
|
const pronoun = that.pronouns[t] || t;
|
|
|
|
if (!filter || filter(pronoun)) {
|
|
|
|
yield pronoun;
|
2020-09-08 09:10:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})];
|
|
|
|
}
|
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
if (!pronounsLeft.length || !includeOthers) {
|
2020-09-08 09:10:04 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
yield [
|
2020-11-28 07:52:48 -08:00
|
|
|
new PronounGroup(config.pronouns.others, pronounsLeft),
|
2020-09-08 09:10:04 -07:00
|
|
|
buildList(function* () {
|
2020-11-10 15:47:44 -08:00
|
|
|
for (let t of pronounsLeft) {
|
|
|
|
if (!filter || filter(that.pronouns[t])) {
|
|
|
|
yield that.pronouns[t];
|
2020-09-08 09:10:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
}
|
2020-10-05 05:57:17 -07:00
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
find(pronoun) {
|
|
|
|
if (!pronoun) {
|
2020-10-09 15:39:34 -07:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-11-10 15:47:44 -08:00
|
|
|
for (let [group, groupPronouns] of this.split()) {
|
|
|
|
for (let t of groupPronouns) {
|
|
|
|
if (t.canonicalName === pronoun.canonicalName) {
|
|
|
|
return {group, groupPronouns};
|
2020-10-05 05:57:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2020-12-05 11:37:10 -08:00
|
|
|
|
|
|
|
isCanonical(pronoun) {
|
|
|
|
for (let p of pronoun.split('&')) {
|
|
|
|
if (!this.canonicalNames.includes(p)) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-09-08 09:10:04 -07:00
|
|
|
}
|
|
|
|
|
2020-08-04 07:15:41 -07:00
|
|
|
export class Noun {
|
2020-12-03 06:01:26 -08:00
|
|
|
constructor({id, masc, fem, neutr, mascPl, femPl, neutrPl, approved = true, base_id = null, author = null}) {
|
2020-08-04 07:15:41 -07:00
|
|
|
this.id = id;
|
|
|
|
this.masc = masc.split('|');
|
|
|
|
this.fem = fem.split('|');
|
|
|
|
this.neutr = neutr.split('|');
|
2020-11-25 15:05:39 -08:00
|
|
|
this.mascPl = mascPl ? mascPl.split('|') : [];
|
|
|
|
this.femPl = femPl ? femPl.split('|') : [];
|
|
|
|
this.neutrPl = neutrPl ? neutrPl.split('|') : [];
|
2020-08-04 07:15:41 -07:00
|
|
|
this.approved = !!approved;
|
|
|
|
this.base = base_id;
|
2020-12-03 06:01:26 -08:00
|
|
|
this.author = author;
|
2020-08-04 07:15:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
matches(filter) {
|
|
|
|
if (!filter) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let field of ['masc', 'fem', 'neutr', 'mascPl', 'femPl', 'neutrPl']) {
|
|
|
|
for (let value of this[field]) {
|
2020-09-29 08:59:23 -07:00
|
|
|
if (value.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
|
2020-08-04 07:15:41 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class NounTemplate {
|
|
|
|
constructor(masc, fem, neutr, mascPl, femPl, neutrPl) {
|
|
|
|
this.masc = masc;
|
|
|
|
this.fem = fem;
|
|
|
|
this.neutr = neutr;
|
|
|
|
this.mascPl = mascPl;
|
|
|
|
this.femPl = femPl;
|
|
|
|
this.neutrPl = neutrPl;
|
|
|
|
}
|
|
|
|
|
|
|
|
fill(stem) {
|
|
|
|
return {
|
|
|
|
masc: this.masc.map(e => stem + e),
|
|
|
|
fem: this.fem.map(e => stem + e),
|
|
|
|
neutr: this.neutr.map(e => stem + e),
|
|
|
|
mascPl: this.mascPl.map(e => stem + e),
|
|
|
|
femPl: this.femPl.map(e => stem + e),
|
|
|
|
neutrPl: this.neutrPl.map(e => stem + e),
|
|
|
|
base: null,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
return Object.values(this)
|
|
|
|
.map(es => es.map(e => '-' + e).join('/'))
|
|
|
|
.join(', ')
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
2020-09-29 08:59:23 -07:00
|
|
|
|
2020-10-11 05:50:33 -07:00
|
|
|
|
|
|
|
export class NounDeclension {
|
|
|
|
constructor(endings) {
|
|
|
|
this.singular = {}
|
|
|
|
this.plural = {}
|
|
|
|
for (let k in endings) {
|
|
|
|
if (!endings.hasOwnProperty(k)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const value = endings[k] ? endings[k].split('/') : null;
|
|
|
|
if (k.endsWith('_pl')) {
|
|
|
|
this.plural[k.substr(0, k.length - 3)] = value;
|
|
|
|
} else {
|
|
|
|
this.singular[k] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
matches(word, plural) {
|
|
|
|
const plurality = plural ? 'plural' : 'singular';
|
|
|
|
const rep = Object.keys(this[plurality])[0];
|
|
|
|
for (let ending of this[plurality][rep] || []) {
|
|
|
|
if (word.endsWith(ending)) {
|
|
|
|
return ending.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
hasSingular() {
|
|
|
|
return Object.values(this.singular).filter(x => x !== null).length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
hasPlural() {
|
|
|
|
return Object.values(this.plural).filter(x => x !== null).length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
decline(word, plural) {
|
|
|
|
const plurality = plural ? 'plural' : 'singular';
|
|
|
|
const rep = Object.keys(this[plurality])[0];
|
|
|
|
const base = word.substring(0, word.length - this.matches(word, plural));
|
|
|
|
const options = this[plurality];
|
|
|
|
|
|
|
|
return buildDict(function*() {
|
|
|
|
for (let k in options) {
|
|
|
|
if (!options.hasOwnProperty(k)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
yield [
|
|
|
|
k,
|
|
|
|
options[k].map(o => base + o),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-17 10:21:49 -08:00
|
|
|
export class InclusiveEntry {
|
2020-12-03 06:01:26 -08:00
|
|
|
constructor({id, insteadOf, say, because, approved = true, base_id = null, categories = '', links = '[]'}) {
|
2020-11-17 10:21:49 -08:00
|
|
|
this.id = id;
|
|
|
|
this.insteadOf = insteadOf.split('|');
|
|
|
|
this.say = say.split('|');
|
|
|
|
this.because = because;
|
|
|
|
this.approved = !!approved;
|
|
|
|
this.base = base_id;
|
2020-12-03 06:01:26 -08:00
|
|
|
this.categories = categories ? categories.split(',') : [];
|
|
|
|
this.links = JSON.parse(links);
|
2020-11-17 10:21:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
matches(filter) {
|
|
|
|
if (!filter) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let field of ['insteadOf', 'say']) {
|
|
|
|
for (let value of this[field]) {
|
|
|
|
if (value.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 08:59:23 -07:00
|
|
|
export class Name {
|
|
|
|
constructor(name, origin, meaning, usage, legally, pros, cons, notablePeople, count, links) {
|
|
|
|
this.name = name;
|
|
|
|
this.origin = origin;
|
|
|
|
this.meaning = meaning;
|
|
|
|
this.usage = usage;
|
|
|
|
this.legally = legally;
|
|
|
|
this.pros = pros;
|
|
|
|
this.cons = cons;
|
|
|
|
this.notablePeople = notablePeople;
|
|
|
|
this.count = count; // TODO
|
|
|
|
this.links = links.filter(l => l.trim().length);
|
|
|
|
}
|
|
|
|
|
|
|
|
matches(filter) {
|
|
|
|
if (!filter) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let field of ['name', 'meaning']) {
|
|
|
|
if ((this[field] || '').toLowerCase().indexOf(filter.toLowerCase()) > -1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-09-29 10:11:46 -07:00
|
|
|
|
|
|
|
|
|
|
|
export class Person {
|
|
|
|
constructor(name, description, pronouns, sources = []) {
|
|
|
|
this.name = name;
|
|
|
|
this.description = description;
|
|
|
|
this.pronouns = {};
|
|
|
|
for (let p of pronouns) {
|
|
|
|
const [language, display, link] = p.split(':');
|
|
|
|
if (this.pronouns[language] === undefined) {
|
|
|
|
this.pronouns[language] = [];
|
|
|
|
}
|
|
|
|
this.pronouns[language].push({display: display, link: link});
|
|
|
|
}
|
|
|
|
this.sources = sources;
|
|
|
|
}
|
|
|
|
}
|