From 6e7b84ab2028215f3a567a977f55f4bcc51dfe41 Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Tue, 10 Sep 2024 10:01:01 -0400 Subject: [PATCH 1/8] Move private method under constructor --- src/word.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/word.ts b/src/word.ts index ed799c8..df7973a 100644 --- a/src/word.ts +++ b/src/word.ts @@ -77,6 +77,18 @@ export class Word extends Node { whiteSpaceAfter: string | null; private sylOpts: SylOpts; + constructor(text: string, sylOpts: SylOpts, original?: string) { + super(); + this.value = this; + this.#text = text; + this.#original = original ?? text; + const startMatch = text.match(/^\s*/g); + const endMatch = text.match(/\s*$/g); + this.whiteSpaceBefore = startMatch ? startMatch[0] : null; + this.whiteSpaceAfter = endMatch ? endMatch[0] : null; + this.sylOpts = sylOpts; + } + /** * * @param word the word to be split into Cluster @@ -105,18 +117,6 @@ export class Word extends Node { return word.split(clusterSplitGroup).map((group) => new Cluster(group)); }; - constructor(text: string, sylOpts: SylOpts, original?: string) { - super(); - this.value = this; - this.#text = text; - this.#original = original ?? text; - const startMatch = text.match(/^\s*/g); - const endMatch = text.match(/\s*$/g); - this.whiteSpaceBefore = startMatch ? startMatch[0] : null; - this.whiteSpaceAfter = endMatch ? endMatch[0] : null; - this.sylOpts = sylOpts; - } - /** * Gets all the {@link Char | Characters} in the Word * From a3ff3c19b1f06f4b8958e3b144fb5af00e9008d6 Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Tue, 10 Sep 2024 10:04:24 -0400 Subject: [PATCH 2/8] Update sylopts to private using hash --- src/word.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/word.ts b/src/word.ts index df7973a..8ae6be2 100644 --- a/src/word.ts +++ b/src/word.ts @@ -75,7 +75,7 @@ export class Word extends Node { * ``` */ whiteSpaceAfter: string | null; - private sylOpts: SylOpts; + #sylOpts: SylOpts; constructor(text: string, sylOpts: SylOpts, original?: string) { super(); @@ -86,7 +86,7 @@ export class Word extends Node { const endMatch = text.match(/\s*$/g); this.whiteSpaceBefore = startMatch ? startMatch[0] : null; this.whiteSpaceAfter = endMatch ? endMatch[0] : null; - this.sylOpts = sylOpts; + this.#sylOpts = sylOpts; } /** @@ -376,7 +376,7 @@ export class Word extends Node { return [syl]; } - const syllables = syllabify(this.clusters, this.sylOpts, this.isInConstruct); + const syllables = syllabify(this.clusters, this.#sylOpts, this.isInConstruct); syllables.forEach((syl) => (syl.word = this)); return syllables; From d19f07215c1590f6ad51dd7fa13b35c75e5caf23 Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Tue, 10 Sep 2024 10:09:07 -0400 Subject: [PATCH 3/8] Refactor divine name logic --- src/utils/divineName.ts | 9 --------- src/word.ts | 7 ++++--- 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 src/utils/divineName.ts diff --git a/src/utils/divineName.ts b/src/utils/divineName.ts deleted file mode 100644 index 92644ec..0000000 --- a/src/utils/divineName.ts +++ /dev/null @@ -1,9 +0,0 @@ -const nonChars = /[^\u{05D0}-\u{05F4}]/gu; - -export const isDivineName = (text: string): boolean => { - return text.replace(nonChars, "") === "יהוה"; -}; - -export const hasDivineName = (text: string): boolean => { - return /יהוה/.test(text.replace(nonChars, "")); -}; diff --git a/src/word.ts b/src/word.ts index 8ae6be2..76aa7c8 100644 --- a/src/word.ts +++ b/src/word.ts @@ -5,7 +5,6 @@ import type { SyllableVowelName } from "./syllable"; import { Syllable } from "./syllable"; import { SylOpts } from "./text"; import type { ConsonantName, TaamimName } from "./utils/charMap"; -import { hasDivineName, isDivineName } from "./utils/divineName"; import { clusterSplitGroup, jerusalemTest } from "./utils/regularExpressions"; import { syllabify } from "./utils/syllabifier"; @@ -13,6 +12,8 @@ import { syllabify } from "./utils/syllabifier"; * A subunit of a {@link Text} consisting of words, which are strings are text separated by spaces or maqqefs. */ export class Word extends Node { + /** A regex for removing anything that is not a character */ + #nonCharacters = /[^\u{05D0}-\u{05F4}]/gu; #text: string; #original: string; /** @@ -231,7 +232,7 @@ export class Word extends Node { * ``` */ get hasDivineName(): boolean { - return hasDivineName(this.text); + return /יהוה/.test(this.text.replace(this.#nonCharacters, "")); } /** @@ -297,7 +298,7 @@ export class Word extends Node { * ``` */ get isDivineName(): boolean { - return isDivineName(this.text); + return this.text.replace(this.#nonCharacters, "") === "יהוה"; } /** From 109a947d0b169696aa27e7f40114a01543382b5e Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Tue, 10 Sep 2024 10:26:31 -0400 Subject: [PATCH 4/8] Update private fields to use hash instead of keyword --- src/char.ts | 55 ++++++++++++++++++++--------------------- src/cluster.ts | 37 +++++++++++++-------------- src/syllable.ts | 4 +-- src/text.ts | 66 ++++++++++++++++++++++++------------------------- src/word.ts | 4 +-- 5 files changed, 81 insertions(+), 85 deletions(-) diff --git a/src/char.ts b/src/char.ts index 2fada4c..1d85443 100644 --- a/src/char.ts +++ b/src/char.ts @@ -10,73 +10,72 @@ export class Char { #text: string; #cluster: Cluster | null = null; #sequencePosition: number; + #isCharKeyOfCharToNameMap = isHebrewCharacter; constructor(char: string) { this.#text = char; - this.#sequencePosition = this.findPos(); + this.#sequencePosition = this.#findPos(); } - private findPos(): number { + #findPos(): number { const char = this.text; - if (Char.consonants.test(char)) { + if (Char.#consonants.test(char)) { return 0; } - if (Char.ligatures.test(char)) { + if (Char.#ligatures.test(char)) { return 1; } - if (Char.dagesh.test(char)) { + if (Char.#dagesh.test(char)) { return 2; } - if (Char.rafe.test(char)) { + if (Char.#rafe.test(char)) { return 2; } - if (Char.vowels.test(char)) { + if (Char.#vowels.test(char)) { return 3; } - if (Char.sheva.test(char)) { + if (Char.#sheva.test(char)) { return 3; } - if (Char.taamim.test(char)) { + if (Char.#taamim.test(char)) { return 4; } - if (Char.meteg.test(char)) { + if (Char.#meteg.test(char)) { return 4; } // i.e. any non-hebrew char return 10; } - private isCharKeyOfCharToNameMap = isHebrewCharacter; - - private static get consonants() { + static get #consonants() { return consonants; } - private static get dagesh() { + static get #dagesh() { return dagesh; } - private static get ligatures() { + static get #ligatures() { return ligatures; } - private static get meteg() { + static get #meteg() { return meteg; } - private static get rafe() { + static get #rafe() { return rafe; } - private static get sheva() { + static get #sheva() { return sheva; } - private static get taamim() { + static get #taamim() { return taamim; } - private static get vowels() { + static get #vowels() { return vowels; } @@ -127,7 +126,7 @@ export class Char { * ``` */ get isConsonant(): boolean { - return Char.consonants.test(this.#text); + return Char.#consonants.test(this.#text); } /** @@ -141,7 +140,7 @@ export class Char { * ``` */ get isLigature(): boolean { - return Char.ligatures.test(this.#text); + return Char.#ligatures.test(this.#text); } /** @@ -155,7 +154,7 @@ export class Char { * ``` */ get isDagesh(): boolean { - return Char.dagesh.test(this.#text); + return Char.#dagesh.test(this.#text); } /** @@ -169,7 +168,7 @@ export class Char { * ``` */ get isRafe(): boolean { - return Char.rafe.test(this.#text); + return Char.#rafe.test(this.#text); } /** @@ -183,7 +182,7 @@ export class Char { * ``` */ get isSheva(): boolean { - return Char.sheva.test(this.#text); + return Char.#sheva.test(this.#text); } /** @@ -197,7 +196,7 @@ export class Char { * ``` */ get isVowel(): boolean { - return Char.vowels.test(this.#text); + return Char.#vowels.test(this.#text); } /** @@ -211,7 +210,7 @@ export class Char { * ``` */ get isTaamim(): boolean { - return Char.taamim.test(this.#text); + return Char.#taamim.test(this.#text); } /** @@ -240,7 +239,7 @@ export class Char { */ get characterName(): CharToNameMap[keyof CharToNameMap] | null { const text = this.#text; - if (this.isCharKeyOfCharToNameMap(text)) { + if (this.#isCharKeyOfCharToNameMap(text)) { return charToNameMap[text]; } return null; diff --git a/src/cluster.ts b/src/cluster.ts index 7db786a..73ff97d 100644 --- a/src/cluster.ts +++ b/src/cluster.ts @@ -36,6 +36,9 @@ export class Cluster extends Node { #vowelsCache: Vowel[] | null = null; #vowelNamesCache: VowelName[] | null = null; #taamimNamesCache: TaamimName[] | null = null; + #isCharConsonant = isCharConsonant; + #isCharTaam = isCharTaam; + #isCharVowel = isCharVowel; /** * Creates a new cluster @@ -55,26 +58,20 @@ export class Cluster extends Node { super(); this.value = this; this.#original = cluster; - this.#sequenced = this.sequence(noSequence); + this.#sequenced = this.#sequence(noSequence); this.#sequenced.forEach((char) => (char.cluster = this)); } - private sequence(noSequence: boolean = false): Char[] { + #sequence(noSequence: boolean = false): Char[] { const chars = [...this.original].map((char) => new Char(char)); return noSequence ? chars : chars.sort((a, b) => a.sequencePosition - b.sequencePosition); } - private isCharConsonant = isCharConsonant; - - private isCharTaam = isCharTaam; - - private isCharVowel = isCharVowel; - - private get hasMetegCharacter(): boolean { - return Cluster.meteg.test(this.text); + get #hasMetegCharacter(): boolean { + return Cluster.#meteg.test(this.text); } - private static get meteg() { + static get #meteg() { return meteg; } @@ -120,7 +117,7 @@ export class Cluster extends Node { const consonants = this.chars.reduce((a, char) => { const text = char.text; - if (char.isConsonant && this.isCharConsonant(text)) { + if (char.isConsonant && this.#isCharConsonant(text)) { a.push(text); } return a; @@ -152,7 +149,7 @@ export class Cluster extends Node { const consonantNames = this.chars.reduce((a, char) => { const text = char.text; - if (char.isConsonant && this.isCharConsonant(text)) { + if (char.isConsonant && this.#isCharConsonant(text)) { a.push(charToNameMap[text]); } return a; @@ -270,7 +267,7 @@ export class Cluster extends Node { * - \u{05BD} METEG */ get hasMeteg(): boolean { - if (!this.hasMetegCharacter) { + if (!this.#hasMetegCharacter) { return false; } let next = this.next; @@ -278,7 +275,7 @@ export class Cluster extends Node { if (next instanceof Cluster) { const nextText = next.text; const sofPassuq = /\u{05C3}/u; - if (Cluster.meteg.test(nextText)) { + if (Cluster.#meteg.test(nextText)) { return true; } if (sofPassuq.test(nextText)) { @@ -379,7 +376,7 @@ export class Cluster extends Node { * - \u{05BD} METEG */ get hasSilluq(): boolean { - if (this.hasMetegCharacter && !this.hasMeteg) { + if (this.#hasMetegCharacter && !this.hasMeteg) { // if it has a meteg character, but the character is not a meteg // then infer it is silluq return true; @@ -672,7 +669,7 @@ export class Cluster extends Node { } const taamimChars = this.chars.reduce((a, char) => { - if (char.isTaamim && this.isCharTaam(char.text)) { + if (char.isTaamim && this.#isCharTaam(char.text)) { a.push(char.text); } @@ -700,7 +697,7 @@ export class Cluster extends Node { const taaminNames = this.chars.reduce((a, char) => { const text = char.text; - if (char.isTaamim && this.isCharTaam(text)) { + if (char.isTaamim && this.#isCharTaam(text)) { a.push(charToNameMap[text]); } @@ -758,7 +755,7 @@ export class Cluster extends Node { } const vowelNames = this.chars.reduce((a, char) => { - if (char.isVowel && this.isCharVowel(char.text)) { + if (char.isVowel && this.#isCharVowel(char.text)) { a.push(charToNameMap[char.text]); } @@ -794,7 +791,7 @@ export class Cluster extends Node { const vowels = this.chars.reduce((a, char) => { const text = char.text; - if (char.isVowel && this.isCharVowel(text)) { + if (char.isVowel && this.#isCharVowel(text)) { a.push(text); } return a; diff --git a/src/syllable.ts b/src/syllable.ts index 8ce2f4f..f7fe6c0 100644 --- a/src/syllable.ts +++ b/src/syllable.ts @@ -70,7 +70,7 @@ export class Syllable extends Node { this.#isFinal = isFinal; } - private isCharKeyOfSyllableVowelCharToNameMap(char: string): char is keyof SyllableVowelCharToNameMap { + #isCharKeyOfSyllableVowelCharToNameMap(char: string): char is keyof SyllableVowelCharToNameMap { return char in sylVowelCharToNameMap; } @@ -653,7 +653,7 @@ export class Syllable extends Node { .replace(shureq, shureqPresentation) .split("") .reduce((a, v) => { - if (this.isCharKeyOfSyllableVowelCharToNameMap(v)) { + if (this.#isCharKeyOfSyllableVowelCharToNameMap(v)) { a.push(v); } if (v === shureqPresentation) { diff --git a/src/text.ts b/src/text.ts index e473f27..fd92224 100644 --- a/src/text.ts +++ b/src/text.ts @@ -346,7 +346,7 @@ export interface SylOpts { */ export class Text { #original: string; - private options: SylOpts; + #options: SylOpts; /** * Cache for {@link SylOpts.ketivQeres} * @@ -363,7 +363,7 @@ export class Text { * * The cache will miss because `הִוא֙` and `הִֽוא׃` are not exact matches, even though `ignoreTaamim` is `true`. */ - private ketivQereCache: { [k: string]: string } = {}; + #ketivQereCache: { [k: string]: string } = {}; /** * `Text` requires an input string, @@ -374,11 +374,11 @@ export class Text { * @param options syllabification options */ constructor(text: string, options: SylOpts = {}) { - this.options = this.setOptions(options); - this.#original = this.options.allowNoNiqqud ? text : this.validateInput(text); + this.#options = this.#setOptions(options); + this.#original = this.#options.allowNoNiqqud ? text : this.#validateInput(text); } - private applyKetivQere = (text: string, kq: KetivQere) => { + #applyKetivQere = (text: string, kq: KetivQere) => { if (kq.input instanceof RegExp) { const match = text.match(kq.input); if (match) { @@ -393,35 +393,35 @@ export class Text { return null; }; - private captureTaamim = (text: string) => { - return text.matchAll(Text.taamimCaptureGroup); + #captureTaamim = (text: string): IterableIterator => { + return text.matchAll(Text.#taamimCaptureGroup); }; - private processKetivQeres = (text: string) => { - if (this.ketivQereCache[text]) { - return this.ketivQereCache[text]; + #processKetivQeres = (text: string) => { + if (this.#ketivQereCache[text]) { + return this.#ketivQereCache[text]; } - const ketivQeres = this.options.ketivQeres; + const ketivQeres = this.#options.ketivQeres; if (!ketivQeres?.length) { return text; } for (const ketivQere of ketivQeres) { - const textWithoutTaamim = ketivQere.ignoreTaamim ? this.removeTaamim(text) : text; + const textWithoutTaamim = ketivQere.ignoreTaamim ? this.#removeTaamim(text) : text; - const appliedKetivQere = this.applyKetivQere(textWithoutTaamim, ketivQere); + const appliedKetivQere = this.#applyKetivQere(textWithoutTaamim, ketivQere); if (!appliedKetivQere) { return text; } - const taamimChars = ketivQere.captureTaamim ? this.captureTaamim(text) : null; + const taamimChars = ketivQere.captureTaamim ? this.#captureTaamim(text) : null; - const newText = taamimChars ? this.setTaamim(appliedKetivQere, taamimChars) : appliedKetivQere; + const newText = taamimChars ? this.#setTaamim(appliedKetivQere, taamimChars) : appliedKetivQere; - this.ketivQereCache[text] = newText; + this.#ketivQereCache[text] = newText; return newText; } @@ -429,7 +429,7 @@ export class Text { return text; }; - private validateInput(text: string): string { + #validateInput(text: string): string { const niqqud = /[\u{05B0}-\u{05BC}\u{05C7}]/u; if (!niqqud.test(text)) { throw new Error("Text must contain niqqud"); @@ -437,7 +437,7 @@ export class Text { return text; } - private validateKetivQeres(ketivQeres: SylOpts["ketivQeres"]) { + #validateKetivQeres(ketivQeres: SylOpts["ketivQeres"]) { // if it's undefined, it's fine if (!ketivQeres) { return true; @@ -480,7 +480,7 @@ export class Text { return true; } - private validateOptions(options: SylOpts): SylOpts { + #validateOptions(options: SylOpts): SylOpts { const validOpts = [ "allowNoNiqqud", "article", @@ -499,7 +499,7 @@ export class Text { throw new Error(`${k} is not a valid option`); } if (k === "ketivQeres") { - this.validateKetivQeres(v as SylOpts["ketivQeres"]); + this.#validateKetivQeres(v as SylOpts["ketivQeres"]); continue; } if (k === "holemHaser" && !["update", "preserve", "remove"].includes(String(v))) { @@ -512,12 +512,12 @@ export class Text { return options; } - private removeTaamim = (text: string) => { + #removeTaamim = (text: string) => { return text.replace(taamim, ""); }; - private setOptions(options: SylOpts): SylOpts { - const validOpts = this.validateOptions(options); + #setOptions(options: SylOpts): SylOpts { + const validOpts = this.#validateOptions(options); return { allowNoNiqqud: validOpts.allowNoNiqqud ?? false, article: validOpts.article ?? true, @@ -538,28 +538,28 @@ export class Text { }; } - private setTaamim(newText: string, taamimCapture: ReturnType) { + #setTaamim(newText: string, taamimCapture: IterableIterator) { return [...taamimCapture].reduce((text, group) => { return text.slice(0, group.index) + group[1] + text.slice(group.index); }, newText); } - private static get taamimCaptureGroup() { + static get #taamimCaptureGroup() { return taamimCaptureGroup; } - private get normalized(): string { + get #normalized(): string { return this.original.normalize("NFKD"); } - private get sanitized(): string { - const text = this.normalized.trim(); + get #sanitized(): string { + const text = this.#normalized.trim(); const sequencedChar = sequence(text).flat(); const sequencedText = sequencedChar.reduce((a, c) => a + c.text, ""); // split text at spaces and maqqef, spaces are added to the array as separate entries const textArr = sequencedText.split(splitGroup).filter((group) => group); - const mapQQatan = this.options.qametsQatan ? textArr.map(convertsQametsQatan) : textArr; - const mapHolemWaw = mapQQatan.map((w) => holemWaw(w, this.options)); + const mapQQatan = this.#options.qametsQatan ? textArr.map(convertsQametsQatan) : textArr; + const mapHolemWaw = mapQQatan.map((w) => holemWaw(w, this.#options)); return mapHolemWaw.join(""); } @@ -661,11 +661,11 @@ export class Text { * ``` */ get words(): Word[] { - const split = this.sanitized.split(splitGroup); + const split = this.#sanitized.split(splitGroup); const groups = split.filter((group) => group); const words = groups.map((original) => { - const word = this.processKetivQeres(original); - return new Word(word, this.options, word !== original ? original : undefined); + const word = this.#processKetivQeres(original); + return new Word(word, this.#options, word !== original ? original : undefined); }); const [first, ...rest] = words; first.siblings = rest; diff --git a/src/word.ts b/src/word.ts index 76aa7c8..cb6da23 100644 --- a/src/word.ts +++ b/src/word.ts @@ -97,7 +97,7 @@ export class Word extends Node { * @remarks * Splits a word at each consonant or the punctuation character, Sof Pasuq and Nun Hafukha */ - private makeClusters = (word: string): Cluster[] => { + #makeClusters = (word: string): Cluster[] => { const match = word.match(jerusalemTest); /** * The Masoretic spelling of Jerusalem contains some idiosyncrasies, @@ -159,7 +159,7 @@ export class Word extends Node { * ``` */ get clusters(): Cluster[] { - const clusters = this.makeClusters(this.text); + const clusters = this.#makeClusters(this.text); const firstCluster = clusters[0]; const remainder = clusters.slice(1); firstCluster.siblings = remainder; From e5e95959e943fe95b7be5e858ac0f93663be3c5b Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Tue, 10 Sep 2024 20:47:26 -0400 Subject: [PATCH 5/8] Remove explicit return types --- src/char.ts | 26 ++++++++++----------- src/cluster.ts | 60 ++++++++++++++++++++++++------------------------- src/syllable.ts | 32 +++++++++++++------------- src/text.ts | 22 +++++++++--------- src/word.ts | 20 ++++++++--------- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/char.ts b/src/char.ts index 1d85443..49d2ec9 100644 --- a/src/char.ts +++ b/src/char.ts @@ -17,7 +17,7 @@ export class Char { this.#sequencePosition = this.#findPos(); } - #findPos(): number { + #findPos() { const char = this.text; if (Char.#consonants.test(char)) { return 0; @@ -92,7 +92,7 @@ export class Char { * // "דָּ" * ``` */ - get cluster(): Cluster | null { + get cluster() { return this.#cluster; } @@ -105,7 +105,7 @@ export class Char { * * @param name a character name */ - isCharacterName(name: keyof NameToCharMap): boolean { + isCharacterName(name: keyof NameToCharMap) { if (!nameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -125,7 +125,7 @@ export class Char { * // true * ``` */ - get isConsonant(): boolean { + get isConsonant() { return Char.#consonants.test(this.#text); } @@ -139,7 +139,7 @@ export class Char { * // true * ``` */ - get isLigature(): boolean { + get isLigature() { return Char.#ligatures.test(this.#text); } @@ -153,7 +153,7 @@ export class Char { * // true * ``` */ - get isDagesh(): boolean { + get isDagesh() { return Char.#dagesh.test(this.#text); } @@ -167,7 +167,7 @@ export class Char { * // true * ``` */ - get isRafe(): boolean { + get isRafe() { return Char.#rafe.test(this.#text); } @@ -181,7 +181,7 @@ export class Char { * // true * ``` */ - get isSheva(): boolean { + get isSheva() { return Char.#sheva.test(this.#text); } @@ -195,7 +195,7 @@ export class Char { * // true * ``` */ - get isVowel(): boolean { + get isVowel() { return Char.#vowels.test(this.#text); } @@ -209,7 +209,7 @@ export class Char { * // true * ``` */ - get isTaamim(): boolean { + get isTaamim() { return Char.#taamim.test(this.#text); } @@ -223,7 +223,7 @@ export class Char { * // true * ``` */ - get isNotHebrew(): boolean { + get isNotHebrew() { return this.sequencePosition === 10; } @@ -264,7 +264,7 @@ export class Char { * // 3 * ``` */ - get sequencePosition(): number { + get sequencePosition() { return this.#sequencePosition; } @@ -280,7 +280,7 @@ export class Char { * // "א" * ``` */ - get text(): string { + get text() { return this.#text; } } diff --git a/src/cluster.ts b/src/cluster.ts index 73ff97d..cdef1a1 100644 --- a/src/cluster.ts +++ b/src/cluster.ts @@ -62,12 +62,12 @@ export class Cluster extends Node { this.#sequenced.forEach((char) => (char.cluster = this)); } - #sequence(noSequence: boolean = false): Char[] { + #sequence(noSequence: boolean = false) { const chars = [...this.original].map((char) => new Char(char)); return noSequence ? chars : chars.sort((a, b) => a.sequencePosition - b.sequencePosition); } - get #hasMetegCharacter(): boolean { + get #hasMetegCharacter() { return Cluster.#meteg.test(this.text); } @@ -90,7 +90,7 @@ export class Cluster extends Node { * // ] * ``` */ - get chars(): Char[] { + get chars() { return this.#sequenced; } @@ -110,7 +110,7 @@ export class Cluster extends Node { * This can only every return one consonant, as a `Cluster` is defined by having only one consonant. * Though it is impossible to have two consonants in a cluster, this api is meant for consistency with `vowels` and `taamim` */ - get consonants(): Consonant[] { + get consonants() { if (this.#consonantsCache) { return this.#consonantsCache; } @@ -142,7 +142,7 @@ export class Cluster extends Node { * This can only every return one consonant, as a `Cluster` is defined by having only one consonant. * Though it is impossible to have two consonants in a cluster, this api is meant for consistency with `vowelNames` and `taamimNames` */ - get consonantNames(): ConsonantName[] { + get consonantNames() { if (this.#consonantNameCache) { return this.#consonantNameCache; } @@ -172,7 +172,7 @@ export class Cluster extends Node { * // false * ``` */ - hasConsonantName(name: ConsonantName): boolean { + hasConsonantName(name: ConsonantName) { if (!consonantNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -200,7 +200,7 @@ export class Cluster extends Node { * - \u{05B2} HATAF PATAH * - \u{05B3} HATAF QAMATS */ - get hasHalfVowel(): boolean { + get hasHalfVowel() { return /[\u{05B1}-\u{05B3}]/u.test(this.text); } @@ -225,7 +225,7 @@ export class Cluster extends Node { * - \u{05B9} HOLAM * - \u{05BA} HOLAM HASER FOR VAV */ - get hasLongVowel(): boolean { + get hasLongVowel() { return /[\u{05B5}\u{05B8}\u{05B9}\u{05BA}]/u.test(this.text); } @@ -247,7 +247,7 @@ export class Cluster extends Node { * Checks if the following character is present and a _sof pasuq_ does not follow it: * - \u{05BD} METEG */ - get hasMetheg(): boolean { + get hasMetheg() { return this.hasMeteg; } @@ -266,7 +266,7 @@ export class Cluster extends Node { * Checks if the following character is present and a _sof pasuq_ does not follow it: * - \u{05BD} METEG */ - get hasMeteg(): boolean { + get hasMeteg() { if (!this.#hasMetegCharacter) { return false; } @@ -305,7 +305,7 @@ export class Cluster extends Node { * Checks if the following character is present: * - \u{05B0} SHEVA */ - get hasSheva(): boolean { + get hasSheva() { return /\u{05B0}/u.test(this.text); } @@ -329,7 +329,7 @@ export class Cluster extends Node { * Checks if the following character is present: * - \u{05B0} SHEVA */ - get hasShewa(): boolean { + get hasShewa() { return this.hasSheva; } @@ -355,7 +355,7 @@ export class Cluster extends Node { * - \u{05BB} QUBUTS * - \u{05C7} QAMATS QATAN */ - get hasShortVowel(): boolean { + get hasShortVowel() { return /[\u{05B4}\u{05B6}\u{05B7}\u{05BB}\u{05C7}]/u.test(this.text); } @@ -375,7 +375,7 @@ export class Cluster extends Node { * Checks if the following character is present and a _sof pasuq_ follows it: * - \u{05BD} METEG */ - get hasSilluq(): boolean { + get hasSilluq() { if (this.#hasMetegCharacter && !this.hasMeteg) { // if it has a meteg character, but the character is not a meteg // then infer it is silluq @@ -400,7 +400,7 @@ export class Cluster extends Node { * Note: it only checks according to the character name, not its semantic meaning. * E.g. "כֵֽן׃" would be `true` when checking for `"METEG"`, not silluq */ - hasTaamName(name: TaamimName): boolean { + hasTaamName(name: TaamimName) { if (!taamimNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -425,7 +425,7 @@ export class Cluster extends Node { * The following characters are considered taamim: * - \u{0591}-\u{05AF}\u{05BF}\u{05C0}\u{05C3}-\u{05C6}\u{05F3}\u{05F4} */ - get hasTaamim(): boolean { + get hasTaamim() { return taamim.test(this.text); } @@ -447,7 +447,7 @@ export class Cluster extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Because `Cluster` is concerned with orthography, a sheva is **not** a vowel character. */ - get hasVowel(): boolean { + get hasVowel() { return this.hasLongVowel || this.hasShortVowel || this.hasHalfVowel; } @@ -469,7 +469,7 @@ export class Cluster extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Because `Cluster` is concerned with orthography, a sheva is **not** a vowel character. */ - hasVowelName(name: VowelName): boolean { + hasVowelName(name: VowelName) { if (!vowelNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -501,7 +501,7 @@ export class Cluster extends Node { * There are potentially other instances when a consonant may be a _mater_ (e.g. a silent aleph), but these are the most common. * Though a shureq is a _mater_ letter, it is also a vowel itself, and thus separate from `isMater`. */ - get isMater(): boolean { + get isMater() { const nxtIsShureq = this.next instanceof Cluster ? this.next.isShureq : false; if (!this.hasVowel && !this.isShureq && !this.hasSheva && !nxtIsShureq) { const text = this.text; @@ -535,7 +535,7 @@ export class Cluster extends Node { * // true * ``` */ - get isNotHebrew(): boolean { + get isNotHebrew() { return !hebChars.test(this.text); } @@ -558,7 +558,7 @@ export class Cluster extends Node { * - \u{05C3} HEBREW PUNCTUATION SOF PASUQ ׃ * - \u{05C6} HEBREW PUNCTUATION NUN HAFUKHA ׆ */ - get isPunctuation(): boolean { + get isPunctuation() { const punctuationOnly = new RegExp(`^${punctuation.source}+$`, "u"); return punctuationOnly.test(this.text); } @@ -582,7 +582,7 @@ export class Cluster extends Node { * A shureq is a vowel itself, but contains no vowel characters (hence why `hasVowel` cannot be `true`). * This allows for easier syllabification. */ - get isShureq(): boolean { + get isShureq() { const shureq = /\u{05D5}\u{05BC}/u; const prvHasVowel = this.prev?.value?.hasVowel ?? false; return !this.hasVowel && !this.hasSheva && !prvHasVowel ? shureq.test(this.text) : false; @@ -609,7 +609,7 @@ export class Cluster extends Node { * - \u{05C6} HEBREW PUNCTUATION NUN HAFUKHA ׆ * */ - get isTaam(): boolean { + get isTaam() { return this.isPunctuation; } @@ -621,7 +621,7 @@ export class Cluster extends Node { * @description * The original string passed to the constructor that has not been normalized or sequenced. See {@link text} */ - get original(): string { + get original() { return this.#original; } @@ -640,7 +640,7 @@ export class Cluster extends Node { * @description * If created via the `Text` class, there should always be a syllable. */ - get syllable(): Syllable | null { + get syllable() { return this.#syllable; } @@ -663,7 +663,7 @@ export class Cluster extends Node { * // ["֑", "֔"] * ``` */ - get taamim(): Taam[] { + get taamim() { if (this.#taamimCache) { return this.#taamimCache; } @@ -690,7 +690,7 @@ export class Cluster extends Node { * // ['ETNAHTA', 'ZAQEF_QATAN' ] * ``` */ - get taamimNames(): TaamimName[] { + get taamimNames() { if (this.#taamimNamesCache) { return this.#taamimNamesCache; } @@ -728,7 +728,7 @@ export class Cluster extends Node { * @description * The text has been normalized and sequenced — see {@link original} for text passed in the constructor. */ - get text(): string { + get text() { return this.chars.reduce((init, char) => init + char.text, ""); } @@ -749,7 +749,7 @@ export class Cluster extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Because `Cluster` is concerned with orthography, a sheva is **not** a vowel character */ - get vowelNames(): VowelName[] { + get vowelNames() { if (this.#vowelNamesCache) { return this.#vowelNamesCache; } @@ -784,7 +784,7 @@ export class Cluster extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Because `Cluster` is concerned with orthography, a sheva is **not** a vowel character */ - get vowels(): Vowel[] { + get vowels() { if (this.#vowelsCache) { return this.#vowelsCache; } diff --git a/src/syllable.ts b/src/syllable.ts index f7fe6c0..9417da1 100644 --- a/src/syllable.ts +++ b/src/syllable.ts @@ -91,7 +91,7 @@ export class Syllable extends Node { * // ] * ``` */ - get chars(): Char[] { + get chars() { return this.clusters.map((cluster) => cluster.chars).flat(); } @@ -110,7 +110,7 @@ export class Syllable extends Node { * // ] * ``` */ - get clusters(): Cluster[] { + get clusters() { return this.#clusters; } @@ -126,7 +126,7 @@ export class Syllable extends Node { * // "ם" * ``` */ - get coda(): string { + get coda() { return this.structure()[2]; } @@ -144,7 +144,7 @@ export class Syllable extends Node { * // "" * ``` */ - get codaWithGemination(): string { + get codaWithGemination() { return this.structure(true)[2]; } @@ -207,7 +207,7 @@ export class Syllable extends Node { * @remarks * This checks if the syllable contains the given consonant name, even if the character is not a phonemic consonant. */ - hasConsonantName(name: ConsonantName): boolean { + hasConsonantName(name: ConsonantName) { if (!consonantNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -242,7 +242,7 @@ export class Syllable extends Node { * Unlike `Cluster`, a `Syllable` is concerned with linguistics, so a sheva **is** a vowel character. * It returns `true` for "SHEVA" only when the sheva is the vowel (i.e. a vocal sheva or sheva na'). */ - hasVowelName(name: SyllableVowelName): boolean { + hasVowelName(name: SyllableVowelName) { if (!sylVowelNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -266,7 +266,7 @@ export class Syllable extends Node { * Note: it only checks according to the character name, not its semantic meaning. * E.g. "כֵֽן׃" would be `true` when checking for `"METEG"`, not silluq */ - hasTaamName(name: TaamimName): boolean { + hasTaamName(name: TaamimName) { if (!taamimNameToCharMap[name]) { throw new Error(`${name} is not a valid value`); } @@ -290,7 +290,7 @@ export class Syllable extends Node { * @remarks * An accented syllable receives stress, and is typically indicated by the presence of a taam character */ - get isAccented(): boolean { + get isAccented() { return this.#isAccented; } @@ -321,7 +321,7 @@ export class Syllable extends Node { * @remarks * A closed syllable in Hebrew is a CVC or CVCC type, a mater letter does not close a syllable */ - get isClosed(): boolean { + get isClosed() { return this.#isClosed; } @@ -349,7 +349,7 @@ export class Syllable extends Node { * // true * ``` */ - get isFinal(): boolean { + get isFinal() { return this.#isFinal; } @@ -376,7 +376,7 @@ export class Syllable extends Node { * @remarks * The nucleus is the vowel of the syllable - present in every syllable and containing its {@link vowel} (with any materes lecticonis) or a shureq. */ - get nucleus(): string { + get nucleus() { return this.structure()[1]; } @@ -394,7 +394,7 @@ export class Syllable extends Node { * @remarks * The onset is any initial consonant of the syllable - present in every syllable except those containing a except word-initial shureq or a furtive patah. */ - get onset(): string { + get onset() { return this.structure()[0]; } @@ -581,7 +581,7 @@ export class Syllable extends Node { * @remarks * This returns a string that has been built up from the .text of its constituent Clusters. */ - get text(): string { + get text() { return this.clusters.map((c) => c.text).join(""); } @@ -604,7 +604,7 @@ export class Syllable extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Unlike `Cluster`, a `Syllable` is concerned with linguistics, so a sheva **is** a vowel character. */ - get vowelNames(): SyllableVowelName[] { + get vowelNames() { if (this.#vowelNamesCache) { return this.#vowelNamesCache; } @@ -640,7 +640,7 @@ export class Syllable extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * Unlike `Cluster`, a `Syllable` is concerned with linguistics, so a sheva **is** a vowel character */ - get vowels(): SyllableVowel[] { + get vowels() { if (this.#vowelsCache) { return this.#vowelsCache; } @@ -679,7 +679,7 @@ export class Syllable extends Node { * // } * ``` */ - get word(): Word | null { + get word() { return this.#word; } diff --git a/src/text.ts b/src/text.ts index fd92224..b978479 100644 --- a/src/text.ts +++ b/src/text.ts @@ -429,7 +429,7 @@ export class Text { return text; }; - #validateInput(text: string): string { + #validateInput(text: string) { const niqqud = /[\u{05B0}-\u{05BC}\u{05C7}]/u; if (!niqqud.test(text)) { throw new Error("Text must contain niqqud"); @@ -480,7 +480,7 @@ export class Text { return true; } - #validateOptions(options: SylOpts): SylOpts { + #validateOptions(options: SylOpts) { const validOpts = [ "allowNoNiqqud", "article", @@ -516,7 +516,7 @@ export class Text { return text.replace(taamim, ""); }; - #setOptions(options: SylOpts): SylOpts { + #setOptions(options: SylOpts) { const validOpts = this.#validateOptions(options); return { allowNoNiqqud: validOpts.allowNoNiqqud ?? false, @@ -548,11 +548,11 @@ export class Text { return taamimCaptureGroup; } - get #normalized(): string { + get #normalized() { return this.original.normalize("NFKD"); } - get #sanitized(): string { + get #sanitized() { const text = this.#normalized.trim(); const sequencedChar = sequence(text).flat(); const sequencedText = sequencedChar.reduce((a, c) => a + c.text, ""); @@ -578,7 +578,7 @@ export class Text { * // ] * ``` */ - get chars(): Char[] { + get chars() { return this.clusters.map((cluster) => cluster.chars).flat(); } @@ -596,7 +596,7 @@ export class Text { * // ] * ``` */ - get clusters(): Cluster[] { + get clusters() { return this.syllables.map((syllable) => syllable.clusters).flat(); } @@ -608,7 +608,7 @@ export class Text { * @remarks * The original string passed to the constructor that has not been normalized or sequenced. See {@link text} */ - get original(): string { + get original() { return this.#original; } @@ -627,7 +627,7 @@ export class Text { * // ] * ``` */ - get syllables(): Syllable[] { + get syllables() { return this.words.map((word) => word.syllables).flat(); } @@ -644,7 +644,7 @@ export class Text { * // וַתָּשׇׁב * ``` */ - get text(): string { + get text() { return this.words.reduce((a, c) => `${a}${c.text}${c.whiteSpaceAfter ?? ""}`, ""); } @@ -660,7 +660,7 @@ export class Text { * // [ Word { original: "הֲבָרֹות" } ] * ``` */ - get words(): Word[] { + get words() { const split = this.#sanitized.split(splitGroup); const groups = split.filter((group) => group); const words = groups.map((original) => { diff --git a/src/word.ts b/src/word.ts index cb6da23..20f4cb5 100644 --- a/src/word.ts +++ b/src/word.ts @@ -137,7 +137,7 @@ export class Word extends Node { * // ] * ``` */ - get chars(): Char[] { + get chars() { return this.clusters.map((cluster) => cluster.chars).flat(); } @@ -158,7 +158,7 @@ export class Word extends Node { * // ] * ``` */ - get clusters(): Cluster[] { + get clusters() { const clusters = this.#makeClusters(this.text); const firstCluster = clusters[0]; const remainder = clusters.slice(1); @@ -231,7 +231,7 @@ export class Word extends Node { * // true * ``` */ - get hasDivineName(): boolean { + get hasDivineName() { return /יהוה/.test(this.text.replace(this.#nonCharacters, "")); } @@ -251,7 +251,7 @@ export class Word extends Node { * Note: it only checks according to the character name, not its semantic meaning. * E.g. "כֵֽן׃" would be `true` when checking for `"METEG"`, not silluq */ - hasTaamName(name: TaamimName): boolean { + hasTaamName(name: TaamimName) { return this.syllables.some((syllable) => syllable.hasTaamName(name)); } @@ -281,7 +281,7 @@ export class Word extends Node { * According to [Syllabification](/guides/syllabification), a sheva is a vowel and serves as the nucleus of a syllable. * It returns `true` for "SHEVA" only when the sheva is the vowel (i.e. a vocal sheva or sheva na'). */ - hasVowelName(name: SyllableVowelName): boolean { + hasVowelName(name: SyllableVowelName) { return this.syllables.some((syllable) => syllable.hasVowelName(name)); } @@ -297,7 +297,7 @@ export class Word extends Node { * // true * ``` */ - get isDivineName(): boolean { + get isDivineName() { return this.text.replace(this.#nonCharacters, "") === "יהוה"; } @@ -316,7 +316,7 @@ export class Word extends Node { * @remarks * If the word contains non-Hebrew characters, it is not considered Hebrew because syllabification is likely not correct. */ - get isNotHebrew(): boolean { + get isNotHebrew() { return !this.clusters.map((c) => c.isNotHebrew).includes(false); } @@ -335,7 +335,7 @@ export class Word extends Node { * @remarks * The construct state is indicated by the presence of a maqqef (U+05BE) character */ - get isInConstruct(): boolean { + get isInConstruct() { // if word has a maqqef, it is in construct return this.text.includes("\u05BE"); } @@ -370,7 +370,7 @@ export class Word extends Node { * // ] * ``` */ - get syllables(): Syllable[] { + get syllables() { if (/\w/.test(this.text) || this.isDivineName || this.isNotHebrew) { const syl = new Syllable(this.clusters); syl.word = this; @@ -432,7 +432,7 @@ export class Word extends Node { * // ] * ``` */ - get text(): string { + get text() { return this.#text.trim(); } From 609768e1a8bc2cd9e19fa24f2b0774f046eb2744 Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Wed, 11 Sep 2024 10:44:43 -0400 Subject: [PATCH 6/8] Change arrow functions to regular functions --- src/text.ts | 16 ++++++++-------- src/word.ts | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/text.ts b/src/text.ts index b978479..571cfdf 100644 --- a/src/text.ts +++ b/src/text.ts @@ -378,7 +378,7 @@ export class Text { this.#original = this.#options.allowNoNiqqud ? text : this.#validateInput(text); } - #applyKetivQere = (text: string, kq: KetivQere) => { + #applyKetivQere(text: string, kq: KetivQere) { if (kq.input instanceof RegExp) { const match = text.match(kq.input); if (match) { @@ -391,13 +391,13 @@ export class Text { } return null; - }; + } - #captureTaamim = (text: string): IterableIterator => { + #captureTaamim(text: string): IterableIterator { return text.matchAll(Text.#taamimCaptureGroup); - }; + } - #processKetivQeres = (text: string) => { + #processKetivQeres(text: string) { if (this.#ketivQereCache[text]) { return this.#ketivQereCache[text]; } @@ -427,7 +427,7 @@ export class Text { } return text; - }; + } #validateInput(text: string) { const niqqud = /[\u{05B0}-\u{05BC}\u{05C7}]/u; @@ -512,9 +512,9 @@ export class Text { return options; } - #removeTaamim = (text: string) => { + #removeTaamim(text: string) { return text.replace(taamim, ""); - }; + } #setOptions(options: SylOpts) { const validOpts = this.#validateOptions(options); diff --git a/src/word.ts b/src/word.ts index 20f4cb5..2406f00 100644 --- a/src/word.ts +++ b/src/word.ts @@ -97,7 +97,7 @@ export class Word extends Node { * @remarks * Splits a word at each consonant or the punctuation character, Sof Pasuq and Nun Hafukha */ - #makeClusters = (word: string): Cluster[] => { + #makeClusters(word: string) { const match = word.match(jerusalemTest); /** * The Masoretic spelling of Jerusalem contains some idiosyncrasies, @@ -116,7 +116,7 @@ export class Word extends Node { }); } return word.split(clusterSplitGroup).map((group) => new Cluster(group)); - }; + } /** * Gets all the {@link Char | Characters} in the Word From 44dfaf23879852dad1802c0b9f41aeacf9155e3d Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Wed, 11 Sep 2024 10:49:03 -0400 Subject: [PATCH 7/8] Update docs workflow --- .github/workflows/main.yml | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 99090ba..4f386fd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,8 @@ -# This is a basic workflow to help you get started with Actions - name: Build docs on version update # Controls when the action will run. on: - # Triggers the workflow on push or pull request events but only for the master branch + # Triggers the workflow on push or pull request events but only for the main branch push: tags: - "*" @@ -15,7 +13,6 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: build-and-deploy: - # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: @@ -24,11 +21,30 @@ jobs: uses: actions/checkout@v2 - name: Install and Build - # use force because typedoc doesn't support current version of TS, but it still build run: | npm install npm run docs + - name: Check for changes + id: git-check + run: | + git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT + + - name: Commit changes + if: steps.git-check.outputs.changes == 'true' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add -A + git commit -m "Auto-update documentation" + + - name: Push changes + if: steps.git-check.outputs.changes == 'true' + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: main + - name: Deploy uses: JamesIves/github-pages-deploy-action@4.1.4 with: From b5eeeecdaa1728a2e4b8347f181d4e0a12eba4dd Mon Sep 17 00:00:00 2001 From: charlesLoder Date: Wed, 11 Sep 2024 10:55:03 -0400 Subject: [PATCH 8/8] Remove unused imports --- src/syllable.ts | 1 - src/text.ts | 3 --- src/word.ts | 1 - 3 files changed, 5 deletions(-) diff --git a/src/syllable.ts b/src/syllable.ts index 9417da1..7dd5713 100644 --- a/src/syllable.ts +++ b/src/syllable.ts @@ -1,4 +1,3 @@ -import { Char } from "./char"; import { Cluster } from "./cluster"; import { Node } from "./node"; import type { ConsonantName, Flip, TaamimName } from "./utils/charMap"; diff --git a/src/text.ts b/src/text.ts index 571cfdf..ab6d470 100644 --- a/src/text.ts +++ b/src/text.ts @@ -1,6 +1,3 @@ -import { Char } from "./char"; -import { Cluster } from "./cluster"; -import { Syllable } from "./syllable"; import { holemWaw } from "./utils/holemWaw"; import { convertsQametsQatan } from "./utils/qametsQatan"; import { splitGroup, taamim, taamimCaptureGroup } from "./utils/regularExpressions"; diff --git a/src/word.ts b/src/word.ts index 2406f00..99e7296 100644 --- a/src/word.ts +++ b/src/word.ts @@ -1,4 +1,3 @@ -import { Char } from "./char"; import { Cluster } from "./cluster"; import { Node } from "./node"; import type { SyllableVowelName } from "./syllable";