@concordance-wiki/nlp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +7 -0
- package/dist/dictionary/build.d.ts +19 -0
- package/dist/dictionary/build.d.ts.map +1 -0
- package/dist/dictionary/build.js +72 -0
- package/dist/dictionary/build.js.map +1 -0
- package/dist/dictionary/stopwords.d.ts +16 -0
- package/dist/dictionary/stopwords.d.ts.map +1 -0
- package/dist/dictionary/stopwords.js +27 -0
- package/dist/dictionary/stopwords.js.map +1 -0
- package/dist/dictionary/types.d.ts +34 -0
- package/dist/dictionary/types.d.ts.map +1 -0
- package/dist/dictionary/types.js +2 -0
- package/dist/dictionary/types.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/keywords/confidence.d.ts +56 -0
- package/dist/keywords/confidence.d.ts.map +1 -0
- package/dist/keywords/confidence.js +59 -0
- package/dist/keywords/confidence.js.map +1 -0
- package/dist/keywords/defined.d.ts +26 -0
- package/dist/keywords/defined.d.ts.map +1 -0
- package/dist/keywords/defined.js +33 -0
- package/dist/keywords/defined.js.map +1 -0
- package/dist/keywords/findings.d.ts +13 -0
- package/dist/keywords/findings.d.ts.map +1 -0
- package/dist/keywords/findings.js +35 -0
- package/dist/keywords/findings.js.map +1 -0
- package/dist/keywords/ngrams.d.ts +47 -0
- package/dist/keywords/ngrams.d.ts.map +1 -0
- package/dist/keywords/ngrams.js +64 -0
- package/dist/keywords/ngrams.js.map +1 -0
- package/dist/keywords/options.d.ts +22 -0
- package/dist/keywords/options.d.ts.map +1 -0
- package/dist/keywords/options.js +22 -0
- package/dist/keywords/options.js.map +1 -0
- package/dist/keywords/publish.d.ts +50 -0
- package/dist/keywords/publish.d.ts.map +1 -0
- package/dist/keywords/publish.js +96 -0
- package/dist/keywords/publish.js.map +1 -0
- package/dist/keywords/score.d.ts +60 -0
- package/dist/keywords/score.d.ts.map +1 -0
- package/dist/keywords/score.js +0 -0
- package/dist/keywords/score.js.map +1 -0
- package/dist/keywords/similar.d.ts +19 -0
- package/dist/keywords/similar.d.ts.map +1 -0
- package/dist/keywords/similar.js +52 -0
- package/dist/keywords/similar.js.map +1 -0
- package/dist/locale/load-pack.d.ts +11 -0
- package/dist/locale/load-pack.d.ts.map +1 -0
- package/dist/locale/load-pack.js +82 -0
- package/dist/locale/load-pack.js.map +1 -0
- package/dist/locale/normalize.d.ts +3 -0
- package/dist/locale/normalize.d.ts.map +1 -0
- package/dist/locale/normalize.js +14 -0
- package/dist/locale/normalize.js.map +1 -0
- package/dist/locale/pack.d.ts +34 -0
- package/dist/locale/pack.d.ts.map +1 -0
- package/dist/locale/pack.js +2 -0
- package/dist/locale/pack.js.map +1 -0
- package/dist/locale/registry.d.ts +16 -0
- package/dist/locale/registry.d.ts.map +1 -0
- package/dist/locale/registry.js +35 -0
- package/dist/locale/registry.js.map +1 -0
- package/dist/locale/stopwords.d.ts +3 -0
- package/dist/locale/stopwords.d.ts.map +1 -0
- package/dist/locale/stopwords.js +17 -0
- package/dist/locale/stopwords.js.map +1 -0
- package/dist/locale/suffixes.d.ts +7 -0
- package/dist/locale/suffixes.d.ts.map +1 -0
- package/dist/locale/suffixes.js +21 -0
- package/dist/locale/suffixes.js.map +1 -0
- package/dist/locale/tag.d.ts +4 -0
- package/dist/locale/tag.d.ts.map +1 -0
- package/dist/locale/tag.js +5 -0
- package/dist/locale/tag.js.map +1 -0
- package/dist/scan/automaton.d.ts +46 -0
- package/dist/scan/automaton.d.ts.map +1 -0
- package/dist/scan/automaton.js +92 -0
- package/dist/scan/automaton.js.map +1 -0
- package/dist/scan/context.d.ts +20 -0
- package/dist/scan/context.d.ts.map +1 -0
- package/dist/scan/context.js +26 -0
- package/dist/scan/context.js.map +1 -0
- package/dist/scan/occurrences.d.ts +64 -0
- package/dist/scan/occurrences.d.ts.map +1 -0
- package/dist/scan/occurrences.js +109 -0
- package/dist/scan/occurrences.js.map +1 -0
- package/dist/scan/tokens.d.ts +12 -0
- package/dist/scan/tokens.d.ts.map +1 -0
- package/dist/scan/tokens.js +34 -0
- package/dist/scan/tokens.js.map +1 -0
- package/dist/text/boundaries.d.ts +12 -0
- package/dist/text/boundaries.d.ts.map +1 -0
- package/dist/text/boundaries.js +13 -0
- package/dist/text/boundaries.js.map +1 -0
- package/dist/text/comparison-form.d.ts +9 -0
- package/dist/text/comparison-form.d.ts.map +1 -0
- package/dist/text/comparison-form.js +23 -0
- package/dist/text/comparison-form.js.map +1 -0
- package/dist/text/context.d.ts +6 -0
- package/dist/text/context.d.ts.map +1 -0
- package/dist/text/context.js +12 -0
- package/dist/text/context.js.map +1 -0
- package/dist/text/search-tokens.d.ts +10 -0
- package/dist/text/search-tokens.d.ts.map +1 -0
- package/dist/text/search-tokens.js +29 -0
- package/dist/text/search-tokens.js.map +1 -0
- package/dist/text/singular.d.ts +7 -0
- package/dist/text/singular.d.ts.map +1 -0
- package/dist/text/singular.js +12 -0
- package/dist/text/singular.js.map +1 -0
- package/locales/en/pack.yaml +18 -0
- package/locales/en/stopwords.txt +536 -0
- package/locales/en/suffixes.txt +7 -0
- package/locales/fr/pack.yaml +15 -0
- package/locales/fr/stopwords.txt +1021 -0
- package/locales/fr/suffixes.txt +12 -0
- package/package.json +44 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LanguagePack } from "../locale/pack.js";
|
|
2
|
+
/** A word-like segment of a text, `end` exclusive, in code units of the text as given. */
|
|
3
|
+
export interface WordBoundary {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
word: string;
|
|
7
|
+
}
|
|
8
|
+
/** Every word of a text with its position, in text order, as the pack's segmenter cuts it. */
|
|
9
|
+
export declare function wordBoundaries(text: string, pack: LanguagePack): WordBoundary[];
|
|
10
|
+
/** True when a word starts at `start` and a word ends at `end` (exclusive), possibly different ones. */
|
|
11
|
+
export declare function isOnWordBoundaries(text: string, start: number, end: number, pack: LanguagePack): boolean;
|
|
12
|
+
//# sourceMappingURL=boundaries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.d.ts","sourceRoot":"","sources":["../../src/text/boundaries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,EAAE,CAK/E;AAED,wGAAwG;AACxG,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,YAAY,GACjB,OAAO,CAGT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Every word of a text with its position, in text order, as the pack's segmenter cuts it. */
|
|
2
|
+
export function wordBoundaries(text, pack) {
|
|
3
|
+
return pack
|
|
4
|
+
.segment(text)
|
|
5
|
+
.filter((word) => word.isWordLike)
|
|
6
|
+
.map((word) => ({ start: word.index, end: word.index + word.text.length, word: word.text }));
|
|
7
|
+
}
|
|
8
|
+
/** True when a word starts at `start` and a word ends at `end` (exclusive), possibly different ones. */
|
|
9
|
+
export function isOnWordBoundaries(text, start, end, pack) {
|
|
10
|
+
const words = wordBoundaries(text, pack);
|
|
11
|
+
return words.some((word) => word.start === start) && words.some((word) => word.end === end);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=boundaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.js","sourceRoot":"","sources":["../../src/text/boundaries.ts"],"names":[],"mappings":"AASA,8FAA8F;AAC9F,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAkB;IAC7D,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,CAAC;SACb,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,KAAa,EACb,GAAW,EACX,IAAkB;IAElB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LanguagePack } from "../locale/pack.js";
|
|
2
|
+
/** The words of a text as they are compared: normalised by the pack, then singularised. */
|
|
3
|
+
export declare function comparisonWords(text: string, pack: LanguagePack): string[];
|
|
4
|
+
/**
|
|
5
|
+
* The form two spellings are compared on. The text given is never modified: the caller keeps
|
|
6
|
+
* the original form for display and only compares on the value returned here.
|
|
7
|
+
*/
|
|
8
|
+
export declare function comparisonForm(text: string, pack: LanguagePack): string;
|
|
9
|
+
//# sourceMappingURL=comparison-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparison-form.d.ts","sourceRoot":"","sources":["../../src/text/comparison-form.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWtD,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAM1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAEvE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { singularize } from "./singular.js";
|
|
2
|
+
// Hyphens and apostrophes stay inside a word; each part they join is singularised on its own,
|
|
3
|
+
// so that "couts-benefices" gives "cout-benefice" and "author's" keeps its "s".
|
|
4
|
+
const parts = /[^-']+/gu;
|
|
5
|
+
function singularizeWord(word, pack) {
|
|
6
|
+
return word.replace(parts, (part) => singularize(part, pack.plural));
|
|
7
|
+
}
|
|
8
|
+
/** The words of a text as they are compared: normalised by the pack, then singularised. */
|
|
9
|
+
export function comparisonWords(text, pack) {
|
|
10
|
+
const normalised = pack.normalize(text);
|
|
11
|
+
if (normalised === "") {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
return normalised.split(" ").map((word) => singularizeWord(word, pack));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The form two spellings are compared on. The text given is never modified: the caller keeps
|
|
18
|
+
* the original form for display and only compares on the value returned here.
|
|
19
|
+
*/
|
|
20
|
+
export function comparisonForm(text, pack) {
|
|
21
|
+
return comparisonWords(text, pack).join(" ");
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=comparison-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparison-form.js","sourceRoot":"","sources":["../../src/text/comparison-form.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,8FAA8F;AAC9F,gFAAgF;AAChF,MAAM,KAAK,GAAG,UAAU,CAAC;AAEzB,SAAS,eAAe,CAAC,IAAY,EAAE,IAAkB;IACvD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAkB;IAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAkB;IAC7D,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A window of `width` characters of the text centred on the span `start`–`end`, kept inside
|
|
3
|
+
* the text, an ellipsis marking each cut.
|
|
4
|
+
*/
|
|
5
|
+
export declare function contextAround(text: string, start: number, end: number, width: number): string;
|
|
6
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/text/context.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK7F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const ellipsis = "…";
|
|
2
|
+
/**
|
|
3
|
+
* A window of `width` characters of the text centred on the span `start`–`end`, kept inside
|
|
4
|
+
* the text, an ellipsis marking each cut.
|
|
5
|
+
*/
|
|
6
|
+
export function contextAround(text, start, end, width) {
|
|
7
|
+
const centre = Math.floor((start + end) / 2);
|
|
8
|
+
const from = Math.max(0, Math.min(centre - width / 2, text.length - width));
|
|
9
|
+
const to = Math.min(text.length, from + width);
|
|
10
|
+
return `${from > 0 ? ellipsis : ""}${text.slice(from, to)}${to < text.length ? ellipsis : ""}`;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/text/context.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,GAAG,CAAC;AAErB;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW,EAAE,KAAa;IACnF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IAC5E,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC;IAC/C,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LanguagePack } from "../locale/pack.js";
|
|
2
|
+
/**
|
|
3
|
+
* The tokens of a text as a prefix search index stores them: every word normalised by the pack
|
|
4
|
+
* and its comparison form, then, for a word with a hyphen, an apostrophe or another separator
|
|
5
|
+
* inside, each of its parts and their comparison forms; nothing shorter than `minLength`. A
|
|
6
|
+
* query matches a token by prefix, so both the written and the singular form are there for
|
|
7
|
+
* "checks" and "check" to find the same note.
|
|
8
|
+
*/
|
|
9
|
+
export declare function searchTokens(text: string, pack: LanguagePack, minLength?: number): Set<string>;
|
|
10
|
+
//# sourceMappingURL=search-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-tokens.d.ts","sourceRoot":"","sources":["../../src/text/search-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAQtD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,SAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAazF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { comparisonForm } from "./comparison-form.js";
|
|
2
|
+
// Punctuation at both ends of a word goes; the inside stays, so that a hyphenated word is one token.
|
|
3
|
+
// The trailing run starts right after a letter or digit: retrying inside the run would make the runtime quadratic.
|
|
4
|
+
const edges = /^[^\p{L}\p{N}]+|(?<![^\p{L}\p{N}])[^\p{L}\p{N}]+$/gu;
|
|
5
|
+
const separators = /[^\p{L}\p{N}]+/u;
|
|
6
|
+
/**
|
|
7
|
+
* The tokens of a text as a prefix search index stores them: every word normalised by the pack
|
|
8
|
+
* and its comparison form, then, for a word with a hyphen, an apostrophe or another separator
|
|
9
|
+
* inside, each of its parts and their comparison forms; nothing shorter than `minLength`. A
|
|
10
|
+
* query matches a token by prefix, so both the written and the singular form are there for
|
|
11
|
+
* "checks" and "check" to find the same note.
|
|
12
|
+
*/
|
|
13
|
+
export function searchTokens(text, pack, minLength = 2) {
|
|
14
|
+
const tokens = new Set();
|
|
15
|
+
const add = (word) => {
|
|
16
|
+
for (const form of [word, comparisonForm(word, pack)]) {
|
|
17
|
+
if (Array.from(form).length >= minLength)
|
|
18
|
+
tokens.add(form);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
for (const raw of pack.normalize(text).split(" ")) {
|
|
22
|
+
const word = raw.replace(edges, "");
|
|
23
|
+
// An unsplit word is its own single part; the set keeps it once.
|
|
24
|
+
for (const part of [word, ...word.split(separators)])
|
|
25
|
+
add(part);
|
|
26
|
+
}
|
|
27
|
+
return tokens;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=search-tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-tokens.js","sourceRoot":"","sources":["../../src/text/search-tokens.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,qGAAqG;AACrG,mHAAmH;AACnH,MAAM,KAAK,GAAG,qDAAqD,CAAC;AACpE,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,IAAkB,EAAE,SAAS,GAAG,CAAC;IAC1E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAQ,EAAE;QACjC,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YACtD,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,SAAS;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,iEAAiE;QACjE,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PluralRule } from "../locale/pack.js";
|
|
2
|
+
/**
|
|
3
|
+
* Brings a normalised word (lowercase, no accents) back to its singular: the first rule
|
|
4
|
+
* whose ending the word carries, and whose minimum length the word reaches, applies.
|
|
5
|
+
*/
|
|
6
|
+
export declare function singularize(word: string, rules: readonly PluralRule[]): string;
|
|
7
|
+
//# sourceMappingURL=singular.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"singular.d.ts","sourceRoot":"","sources":["../../src/text/singular.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAQ9E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brings a normalised word (lowercase, no accents) back to its singular: the first rule
|
|
3
|
+
* whose ending the word carries, and whose minimum length the word reaches, applies.
|
|
4
|
+
*/
|
|
5
|
+
export function singularize(word, rules) {
|
|
6
|
+
const rule = rules.find(({ ending, minLength }) => word.length >= minLength && word.endsWith(ending));
|
|
7
|
+
if (rule === undefined) {
|
|
8
|
+
return word;
|
|
9
|
+
}
|
|
10
|
+
return word.slice(0, word.length - rule.ending.length) + rule.singular;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=singular.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"singular.js","sourceRoot":"","sources":["../../src/text/singular.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAA4B;IACpE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACrB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC7E,CAAC;IACF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Language pack: everything the engine needs to know about a language, as data.
|
|
2
|
+
locale: en
|
|
3
|
+
language: English
|
|
4
|
+
# Apostrophe characters unified to the plain one before matching.
|
|
5
|
+
apostrophes: ["’", "ʼ"]
|
|
6
|
+
# Intl.Collator options for every alphabetical order of this locale.
|
|
7
|
+
collation: { sensitivity: base, numeric: true }
|
|
8
|
+
# Suffix rules that bring a plural form back to its singular; the first matching
|
|
9
|
+
# rule wins, `min_length` guards short words. Applied by the occurrence scan.
|
|
10
|
+
plural:
|
|
11
|
+
- { ending: ies, singular: y, min_length: 5 }
|
|
12
|
+
- { ending: sses, singular: ss, min_length: 6 }
|
|
13
|
+
- { ending: shes, singular: sh, min_length: 6 }
|
|
14
|
+
- { ending: ches, singular: ch, min_length: 6 }
|
|
15
|
+
- { ending: xes, singular: x, min_length: 5 }
|
|
16
|
+
# A word in -ss is a singular ("address"): this rule keeps it from the -s rule below.
|
|
17
|
+
- { ending: ss, singular: ss }
|
|
18
|
+
- { ending: s, singular: "", min_length: 4 }
|