@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
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @concordance-wiki/nlp
|
|
2
|
+
|
|
3
|
+
Normalisation, Aho-Corasick, n-grams, C-value, MinHash and the language packs.
|
|
4
|
+
|
|
5
|
+
Today: language packs for `en` and `fr` built from data files (`locales/<locale>/pack.yaml`, `stopwords.txt` and the optional `suffixes.txt` of inflected-form endings; the default stopwords are the words that name nothing on their own in any corpus, from the articles to every form of the auxiliaries and light verbs, the adverbs of prose, quantifiers, numerals, time words and the nouns that only count or place, never a word that could be a business term or end a technical compound, which a project lists under `inference.stopwords`), BCP 47 locale resolution with fallback to the language, Unicode word segmentation and collation, a registry for packs shipped by plugins (`loadLanguagePack`, `languagePack`, `registerLanguagePack`, `resolveLocale`, `canonicalLocale`, `loadStopwords`), and text normalisation: the comparison form of a text (lower-cased, accents stripped, apostrophes unified, each word singularised by the pack's suffix rules; `comparisonForm`, `comparisonWords`, `singularize`) and word boundaries from Unicode segmentation (`wordBoundaries`, `isOnWordBoundaries`); and the recognition dictionary: `buildDictionary` keys every title and alias of the entities of a locale by comparison form, with priority to glossary sources (`glossarySources`), leaves out stopwords (`dictionaryStopwords` merges the pack's defaults with the files of `inference.stopwords`) and terms shorter than three characters unless `inference.short_terms` allows them, and flags the forms shared by several entities as homonyms with an `I-TERM-HOMONYM` finding; and the occurrence scan: `tokenize` cuts a text into words in comparison form with their spans, `buildAutomaton`, `scan` and `longestMatches` run a word-level Aho-Corasick over them (one pass per text; an expression contained in a longer recognised one is dropped, while expressions that only partly overlap are all kept), and `scanDocument` turns the matches of a dictionary in the paragraphs of a document into occurrences with file, line, position, the matched text as written, section, an 80-character context, the type announced by a recognised prefix (`type_prefixes`) and a confidence from the `glossary_occurrence` scale (`occurrenceConfidence` gives the per-occurrence increments up to the cap; `compareOccurrences` is their canonical order). The scan reads the units that `scannableText` of the ingestion package produces, so code blocks, inline code, URLs, frontmatter and link targets never yield an occurrence; the visible text of a link does. And the keyword discovery: `extractNgrams` reads the same units and yields every n-gram of one to four words (`keywordOptions` resolves `inference.ngrams`, `inference.candidate_score` and the lock's `rejected_terms`), leaving out those starting or ending with a stopword, made only of digits or shorter than three characters, each with its surface form, position and a 160-character context; `scoreCandidates` groups them by comparison form, drops the dictionary entries and the rejected terms (which still penalise the n-grams they contain), scores each candidate by C-value × IDF and keeps those with three occurrences in two distinct files, best score first with its display form and its mentions (`compareMentions`), each with its confidence in [0, 1] of being a term of the subject rather than a word of the language, the product of five signals rounded to four decimals (`confidenceOf`, `confidenceFactors`, `confidencePenalties`, the measures in `signals` and the lowering signals in `penalties`): spread `df / N`, 1 up to `maxSpread` (0.5) then linear down to 0 for a word in every file, read only in a corpus of `SPREAD_MIN_FILES` (10); burst `occurrences / df`, 1 from `BURST_PER_FILE` (1.5) else `0.5 + (burst − 1)`, read only from `BURST_MIN_FILES` (5); position `POSITION_BASE` (0.8) plus 0.2 times the share of appearances in the prominent texts given as `prominent` n-grams (headings, written links, frontmatter), capped at one; neighbourhood 1 when the expression is, or is a component of, a frequent n-gram that also holds a defined term, `NEIGHBOURHOOD_BASE` (0.9) otherwise; morphology `MORPHOLOGY_PENALTY` (0.8) when a word ends with an inflected-form suffix of the pack (`suffixes.txt`, `loadSuffixes`; a pack without the file penalises no form), 1 otherwise; `undefinedTermFindings` turns the candidates at or above the score threshold into `W-TERM-UNDEFINED` findings; `similarExpressions` picks, among keyed expressions, those of a similar form to a key (`similarForm`: one a contiguous part of the other, or half the distinct words of the longer one shared), the closest first, five at most (`SIMILAR_EXPRESSIONS_LIMIT`), for the leads of a keyword page; `definedExpressions` lists the n-grams the dictionary already defines that reach the publication threshold, the expressions whose keyword page a note took over. And the publication threshold: `publishKeywords` splits the candidates into the pages to generate (`keywords/<slug of the key>`, sorted by identifier; two keys with the same slug take numeric suffixes in score order), the expressions discarded by the counts of `inference.keyword_pages` (`keywordPublicationOptions`: three occurrences in two distinct files by default) and those withheld by its `min_confidence` (one half by default), both staying in the output for the search index without a page; `keywordEntities` turns each page into a `term` entity marked `keyword: true`, located on the first mention of its expression, with its occurrences, files, score and confidence as attributes. The counts of the three lists go into the build summary (`keywords.published`, `keywords.discarded`, `keywords.withheld` in core's `summarize`), printed by the build as `keyword pages`, `expressions under the threshold` and `expressions set aside by confidence` once the build runs the discovery.
|
|
6
|
+
|
|
7
|
+
Part of [Concordance](../../README.md).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Dictionary, DictionarySource } from "./types.js";
|
|
2
|
+
export declare const HOMONYM_CHECK = "I-TERM-HOMONYM";
|
|
3
|
+
export interface BuildDictionaryInput {
|
|
4
|
+
entities: readonly DictionarySource[];
|
|
5
|
+
locale: string;
|
|
6
|
+
/** Names of the sources whose entities take priority. */
|
|
7
|
+
glossarySources: ReadonlySet<string>;
|
|
8
|
+
/** The pack's defaults merged with the configured files; see `dictionaryStopwords`. */
|
|
9
|
+
stopwords: ReadonlySet<string>;
|
|
10
|
+
/** Terms shorter than three characters that stay in the dictionary. */
|
|
11
|
+
shortTerms: ReadonlySet<string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The words to recognise in the texts of a locale: every title and alias of its entities,
|
|
15
|
+
* keyed by comparison form, minus stopwords and short terms. Pure: the same entities give
|
|
16
|
+
* the same dictionary whatever their order.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildDictionary(input: BuildDictionaryInput): Dictionary;
|
|
19
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/dictionary/build.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAmB,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAElG,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAK9C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,uFAAuF;IACvF,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B,uEAAuE;IACvE,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC;AA8BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,UAAU,CAkCvE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { languagePack } from "../locale/registry.js";
|
|
2
|
+
import { comparisonForm } from "../text/comparison-form.js";
|
|
3
|
+
export const HOMONYM_CHECK = "I-TERM-HOMONYM";
|
|
4
|
+
/** Below this length a term is noise unless the configuration allows it. */
|
|
5
|
+
const minimumLength = 3;
|
|
6
|
+
// Code-unit order, not locale order: the output must not depend on the collation data of the runtime.
|
|
7
|
+
function byCodeUnit(a, b) {
|
|
8
|
+
return Number(a > b) - Number(a < b);
|
|
9
|
+
}
|
|
10
|
+
function comparisonSet(forms, pack) {
|
|
11
|
+
return new Set([...forms].map((form) => comparisonForm(form, pack)));
|
|
12
|
+
}
|
|
13
|
+
function homonymFinding(entry) {
|
|
14
|
+
const ids = entry.targets.map((target) => target.id).sort(byCodeUnit);
|
|
15
|
+
return {
|
|
16
|
+
check: HOMONYM_CHECK,
|
|
17
|
+
severity: "info",
|
|
18
|
+
message: `"${entry.key}" is the title or an alias of ${String(ids.length)} entities: ${ids.join(", ")}`,
|
|
19
|
+
remediation: "Occurrences link to each entity at half confidence. Give the entities distinct titles or aliases, or add a `## Not to be confused with` section to each note so that readers tell them apart.",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Identifiers are unique within an entry and keys within the dictionary, so no comparison ties.
|
|
23
|
+
function compareTargets(a, b) {
|
|
24
|
+
return a.priority - b.priority || (a.id < b.id ? -1 : 1);
|
|
25
|
+
}
|
|
26
|
+
function compareKeys([a], [b]) {
|
|
27
|
+
return a < b ? -1 : 1;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The words to recognise in the texts of a locale: every title and alias of its entities,
|
|
31
|
+
* keyed by comparison form, minus stopwords and short terms. Pure: the same entities give
|
|
32
|
+
* the same dictionary whatever their order.
|
|
33
|
+
*/
|
|
34
|
+
export function buildDictionary(input) {
|
|
35
|
+
const pack = languagePack(input.locale);
|
|
36
|
+
const stopwords = comparisonSet(input.stopwords, pack);
|
|
37
|
+
const shortTerms = comparisonSet(input.shortTerms, pack);
|
|
38
|
+
const candidates = new Map();
|
|
39
|
+
const consider = (entity, kind, form) => {
|
|
40
|
+
const key = comparisonForm(form, pack);
|
|
41
|
+
if (key === "")
|
|
42
|
+
return;
|
|
43
|
+
if (key.length < minimumLength && !shortTerms.has(key))
|
|
44
|
+
return;
|
|
45
|
+
if (stopwords.has(key) || key.split(" ").every((word) => stopwords.has(word)))
|
|
46
|
+
return;
|
|
47
|
+
const targets = candidates.get(key) ?? new Map();
|
|
48
|
+
if (!targets.has(entity.id)) {
|
|
49
|
+
const priority = input.glossarySources.has(entity.source) ? 0 : 1;
|
|
50
|
+
targets.set(entity.id, { id: entity.id, kind, form, priority });
|
|
51
|
+
}
|
|
52
|
+
candidates.set(key, targets);
|
|
53
|
+
};
|
|
54
|
+
for (const entity of input.entities) {
|
|
55
|
+
if (entity.locale !== input.locale)
|
|
56
|
+
continue;
|
|
57
|
+
consider(entity, "title", entity.title);
|
|
58
|
+
for (const alias of entity.aliases)
|
|
59
|
+
consider(entity, "alias", alias);
|
|
60
|
+
}
|
|
61
|
+
const entries = new Map();
|
|
62
|
+
const findings = [];
|
|
63
|
+
for (const [key, byEntity] of [...candidates].sort(compareKeys)) {
|
|
64
|
+
const targets = [...byEntity.values()].sort(compareTargets);
|
|
65
|
+
const entry = { key, targets, homonym: targets.length > 1 };
|
|
66
|
+
entries.set(key, entry);
|
|
67
|
+
if (entry.homonym)
|
|
68
|
+
findings.push(homonymFinding(entry));
|
|
69
|
+
}
|
|
70
|
+
return { locale: input.locale, entries, findings };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/dictionary/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Config, FileSystem } from "@concordance-wiki/core";
|
|
2
|
+
export interface DictionaryStopwordsInput {
|
|
3
|
+
locale: string;
|
|
4
|
+
config: Config;
|
|
5
|
+
/** The folder of `concordance.yaml`, against which `inference.stopwords` paths resolve. */
|
|
6
|
+
configDirectory: string;
|
|
7
|
+
fs: FileSystem;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The stopwords excluded from the dictionary of a locale: the pack's defaults plus every
|
|
11
|
+
* file listed under `inference.stopwords`. A missing file is a configuration mistake.
|
|
12
|
+
*/
|
|
13
|
+
export declare function dictionaryStopwords(input: DictionaryStopwordsInput): ReadonlySet<string>;
|
|
14
|
+
/** The sources whose entities take priority: `inference.glossary_sources`, else those with `glossary: true`. */
|
|
15
|
+
export declare function glossarySources(config: Config): ReadonlySet<string>;
|
|
16
|
+
//# sourceMappingURL=stopwords.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stopwords.d.ts","sourceRoot":"","sources":["../../src/dictionary/stopwords.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKjE,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,eAAe,EAAE,MAAM,CAAC;IACxB,EAAE,EAAE,UAAU,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,WAAW,CAAC,MAAM,CAAC,CAUxF;AAED,gHAAgH;AAChH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAInE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { languagePack } from "../locale/registry.js";
|
|
3
|
+
import { loadStopwords } from "../locale/stopwords.js";
|
|
4
|
+
/**
|
|
5
|
+
* The stopwords excluded from the dictionary of a locale: the pack's defaults plus every
|
|
6
|
+
* file listed under `inference.stopwords`. A missing file is a configuration mistake.
|
|
7
|
+
*/
|
|
8
|
+
export function dictionaryStopwords(input) {
|
|
9
|
+
const words = new Set(languagePack(input.locale).stopwords);
|
|
10
|
+
for (const file of input.config.inference?.stopwords ?? []) {
|
|
11
|
+
const path = posix.resolve(input.configDirectory, file);
|
|
12
|
+
if (!input.fs.exists(path)) {
|
|
13
|
+
throw new Error(`stopword file not found: ${path} (inference.stopwords lists "${file}")`);
|
|
14
|
+
}
|
|
15
|
+
for (const word of loadStopwords(input.fs.readText(path)))
|
|
16
|
+
words.add(word);
|
|
17
|
+
}
|
|
18
|
+
return words;
|
|
19
|
+
}
|
|
20
|
+
/** The sources whose entities take priority: `inference.glossary_sources`, else those with `glossary: true`. */
|
|
21
|
+
export function glossarySources(config) {
|
|
22
|
+
const declared = config.inference?.glossary_sources;
|
|
23
|
+
if (declared !== undefined)
|
|
24
|
+
return new Set(declared);
|
|
25
|
+
return new Set(config.sources.filter((source) => source.glossary === true).map((s) => s.name));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=stopwords.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stopwords.js","sourceRoot":"","sources":["../../src/dictionary/stopwords.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIlC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAUvD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA+B;IACjE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;IAC5D,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,gCAAgC,IAAI,IAAI,CAAC,CAAC;QAC5F,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACpD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrD,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Finding } from "@concordance-wiki/core";
|
|
2
|
+
/** What the dictionary needs to know about an entity: a structural view, so that any model fits. */
|
|
3
|
+
export interface DictionarySource {
|
|
4
|
+
id: string;
|
|
5
|
+
source: string;
|
|
6
|
+
type: string;
|
|
7
|
+
title: string;
|
|
8
|
+
aliases: readonly string[];
|
|
9
|
+
locale: string;
|
|
10
|
+
}
|
|
11
|
+
/** One entity reachable from a dictionary entry, through its title or one of its aliases. */
|
|
12
|
+
export interface DictionaryTarget {
|
|
13
|
+
id: string;
|
|
14
|
+
kind: "title" | "alias";
|
|
15
|
+
/** The spelling as written on the entity, kept for display. */
|
|
16
|
+
form: string;
|
|
17
|
+
/** 0 for an entity of a glossary source, 1 otherwise. */
|
|
18
|
+
priority: number;
|
|
19
|
+
}
|
|
20
|
+
export interface DictionaryEntry {
|
|
21
|
+
/** The comparison form the occurrence scan matches on. */
|
|
22
|
+
key: string;
|
|
23
|
+
/** Sorted by priority, then by identifier. */
|
|
24
|
+
targets: DictionaryTarget[];
|
|
25
|
+
/** True when the targets belong to more than one entity. */
|
|
26
|
+
homonym: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface Dictionary {
|
|
29
|
+
locale: string;
|
|
30
|
+
/** Keyed by comparison form, in code unit order of the keys. */
|
|
31
|
+
entries: ReadonlyMap<string, DictionaryEntry>;
|
|
32
|
+
findings: Finding[];
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dictionary/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,oGAAoG;AACpG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dictionary/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { LanguagePackError, loadLanguagePack } from "./locale/load-pack.js";
|
|
2
|
+
export type { LanguagePack, PluralRule, Word } from "./locale/pack.js";
|
|
3
|
+
export { availableLocales, languagePack, registerLanguagePack, resolveLocale, } from "./locale/registry.js";
|
|
4
|
+
export { canonicalLocale } from "./locale/tag.js";
|
|
5
|
+
export { loadStopwords } from "./locale/stopwords.js";
|
|
6
|
+
export { loadSuffixes } from "./locale/suffixes.js";
|
|
7
|
+
export { isOnWordBoundaries, wordBoundaries, type WordBoundary } from "./text/boundaries.js";
|
|
8
|
+
export { comparisonForm, comparisonWords } from "./text/comparison-form.js";
|
|
9
|
+
export { searchTokens } from "./text/search-tokens.js";
|
|
10
|
+
export { singularize } from "./text/singular.js";
|
|
11
|
+
export { buildDictionary, HOMONYM_CHECK, type BuildDictionaryInput } from "./dictionary/build.js";
|
|
12
|
+
export { dictionaryStopwords, glossarySources, type DictionaryStopwordsInput, } from "./dictionary/stopwords.js";
|
|
13
|
+
export type { Dictionary, DictionaryEntry, DictionarySource, DictionaryTarget, } from "./dictionary/types.js";
|
|
14
|
+
export { buildAutomaton, longestMatches, scan, type Automaton, type AutomatonState, type Pattern, type RawMatch, } from "./scan/automaton.js";
|
|
15
|
+
export { tokenize, type Token } from "./scan/tokens.js";
|
|
16
|
+
export { CONTEXT_WIDTH, occurrenceContext, type ElidedCode, type QuotedText, } from "./scan/context.js";
|
|
17
|
+
export { compareOccurrences, occurrenceConfidence, scanDocument, type Occurrence, type OccurrenceScale, type ScanDocumentInput, type ScannedDocument, type ScannedParagraph, } from "./scan/occurrences.js";
|
|
18
|
+
export { extractNgrams, keywordForm, keywordForms, type ExtractNgramsOptions, type KeywordUnit, type NgramOccurrence, } from "./keywords/ngrams.js";
|
|
19
|
+
export { compareMentions, scoreCandidates, type KeywordCandidate, type KeywordMention, type ScoreCandidatesOptions, } from "./keywords/score.js";
|
|
20
|
+
export { BURST_MIN_FILES, BURST_PER_FILE, confidenceDefaults, confidenceFactors, confidenceOf, confidencePenalties, MORPHOLOGY_PENALTY, NEIGHBOURHOOD_BASE, POSITION_BASE, SPREAD_MIN_FILES, type ConfidenceFactors, type ConfidenceInput, type ConfidenceOptions, type ConfidencePenalty, type ConfidenceSignals, } from "./keywords/confidence.js";
|
|
21
|
+
export { UNDEFINED_TERM_CHECK, undefinedTermFindings, type UndefinedTermOptions, } from "./keywords/findings.js";
|
|
22
|
+
export { keywordDefaults, keywordOptions, type KeywordLock, type KeywordOptions, } from "./keywords/options.js";
|
|
23
|
+
export { SIMILAR_EXPRESSIONS_LIMIT, similarExpressions, similarForm, type KeyedExpression, } from "./keywords/similar.js";
|
|
24
|
+
export { definedExpressions, type DefinedExpression, type DefinedExpressionsOptions, } from "./keywords/defined.js";
|
|
25
|
+
export { KEYWORD_TYPE, keywordEntities, keywordPublicationDefaults, keywordPublicationOptions, publishKeywords, type KeywordEntitiesOptions, type KeywordPage, type KeywordPublicationOptions, type PublishedKeywords, } from "./keywords/publish.js";
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { LanguagePackError, loadLanguagePack } from "./locale/load-pack.js";
|
|
2
|
+
export { availableLocales, languagePack, registerLanguagePack, resolveLocale, } from "./locale/registry.js";
|
|
3
|
+
export { canonicalLocale } from "./locale/tag.js";
|
|
4
|
+
export { loadStopwords } from "./locale/stopwords.js";
|
|
5
|
+
export { loadSuffixes } from "./locale/suffixes.js";
|
|
6
|
+
export { isOnWordBoundaries, wordBoundaries } from "./text/boundaries.js";
|
|
7
|
+
export { comparisonForm, comparisonWords } from "./text/comparison-form.js";
|
|
8
|
+
export { searchTokens } from "./text/search-tokens.js";
|
|
9
|
+
export { singularize } from "./text/singular.js";
|
|
10
|
+
export { buildDictionary, HOMONYM_CHECK } from "./dictionary/build.js";
|
|
11
|
+
export { dictionaryStopwords, glossarySources, } from "./dictionary/stopwords.js";
|
|
12
|
+
export { buildAutomaton, longestMatches, scan, } from "./scan/automaton.js";
|
|
13
|
+
export { tokenize } from "./scan/tokens.js";
|
|
14
|
+
export { CONTEXT_WIDTH, occurrenceContext, } from "./scan/context.js";
|
|
15
|
+
export { compareOccurrences, occurrenceConfidence, scanDocument, } from "./scan/occurrences.js";
|
|
16
|
+
export { extractNgrams, keywordForm, keywordForms, } from "./keywords/ngrams.js";
|
|
17
|
+
export { compareMentions, scoreCandidates, } from "./keywords/score.js";
|
|
18
|
+
export { BURST_MIN_FILES, BURST_PER_FILE, confidenceDefaults, confidenceFactors, confidenceOf, confidencePenalties, MORPHOLOGY_PENALTY, NEIGHBOURHOOD_BASE, POSITION_BASE, SPREAD_MIN_FILES, } from "./keywords/confidence.js";
|
|
19
|
+
export { UNDEFINED_TERM_CHECK, undefinedTermFindings, } from "./keywords/findings.js";
|
|
20
|
+
export { keywordDefaults, keywordOptions, } from "./keywords/options.js";
|
|
21
|
+
export { SIMILAR_EXPRESSIONS_LIMIT, similarExpressions, similarForm, } from "./keywords/similar.js";
|
|
22
|
+
export { definedExpressions, } from "./keywords/defined.js";
|
|
23
|
+
export { KEYWORD_TYPE, keywordEntities, keywordPublicationDefaults, keywordPublicationOptions, publishKeywords, } from "./keywords/publish.js";
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE5E,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAqB,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,aAAa,EAA6B,MAAM,uBAAuB,CAAC;AAClG,OAAO,EACL,mBAAmB,EACnB,eAAe,GAEhB,MAAM,2BAA2B,CAAC;AAOnC,OAAO,EACL,cAAc,EACd,cAAc,EACd,IAAI,GAKL,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAc,MAAM,kBAAkB,CAAC;AACxD,OAAO,EACL,aAAa,EACb,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GAMb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,WAAW,EACX,YAAY,GAIb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,eAAe,GAIhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,gBAAgB,GAMjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GAEtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,eAAe,EACf,cAAc,GAGf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,WAAW,GAEZ,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kBAAkB,GAGnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EACZ,eAAe,EACf,0BAA0B,EAC1B,yBAAyB,EACzB,eAAe,GAKhB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { TermPenalty, TermSignals } from "@concordance-wiki/core";
|
|
2
|
+
/**
|
|
3
|
+
* What the confidence of a candidate is read from: five measures of the corpus alone, no
|
|
4
|
+
* learning; `spread` is `df / N`, `burst` is `occurrences / df`, `prominence` the appearances
|
|
5
|
+
* in a heading, a written link or the frontmatter per occurrence, capped at one.
|
|
6
|
+
*/
|
|
7
|
+
export type ConfidenceSignals = TermSignals;
|
|
8
|
+
/** The signals with the counts that decide whether the spread and the burst read: the files of the corpus and of the expression. */
|
|
9
|
+
export interface ConfidenceInput extends ConfidenceSignals {
|
|
10
|
+
/** Files of the corpus. */
|
|
11
|
+
corpus: number;
|
|
12
|
+
/** Distinct files holding the expression. */
|
|
13
|
+
files: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ConfidenceOptions {
|
|
16
|
+
/** Share of the files beyond which the expression belongs to the language rather than the subject. */
|
|
17
|
+
maxSpread: number;
|
|
18
|
+
}
|
|
19
|
+
/** The five factors of the product, each in [0, 1], in the order of the formula. */
|
|
20
|
+
export interface ConfidenceFactors {
|
|
21
|
+
spread: number;
|
|
22
|
+
burst: number;
|
|
23
|
+
position: number;
|
|
24
|
+
neighbourhood: number;
|
|
25
|
+
morphology: number;
|
|
26
|
+
}
|
|
27
|
+
/** A signal that lowered the confidence: what the to-do page words as the reason. */
|
|
28
|
+
export type ConfidencePenalty = TermPenalty;
|
|
29
|
+
export declare const confidenceDefaults: ConfidenceOptions;
|
|
30
|
+
/** Files a corpus must hold before the spread of an expression is read: in a handful, every word is everywhere. */
|
|
31
|
+
export declare const SPREAD_MIN_FILES = 10;
|
|
32
|
+
/** Files an expression must reach before its occurrences per file are read. */
|
|
33
|
+
export declare const BURST_MIN_FILES = 5;
|
|
34
|
+
/** Occurrences per file from which an expression recurs where it is treated. */
|
|
35
|
+
export declare const BURST_PER_FILE = 1.5;
|
|
36
|
+
/** The position factor of an expression never put forward; the bonus fills the rest. */
|
|
37
|
+
export declare const POSITION_BASE = 0.8;
|
|
38
|
+
/** The neighbourhood factor of an expression no defined term accompanies. */
|
|
39
|
+
export declare const NEIGHBOURHOOD_BASE = 0.9;
|
|
40
|
+
/** The morphology factor of an inflected form: a soft penalty, never an elimination. */
|
|
41
|
+
export declare const MORPHOLOGY_PENALTY = 0.8;
|
|
42
|
+
/**
|
|
43
|
+
* The factors of the formula: spread falls linearly from 1 at `maxSpread` to 0 when the
|
|
44
|
+
* expression is in every file, and reads only in a corpus of `SPREAD_MIN_FILES` files; burst
|
|
45
|
+
* rises linearly from 0.5 at one occurrence per file to 1 at `BURST_PER_FILE`, and reads
|
|
46
|
+
* only from `BURST_MIN_FILES` files; position is
|
|
47
|
+
* `POSITION_BASE` plus the prominence share of the rest; neighbourhood is 1 with the bonus,
|
|
48
|
+
* `NEIGHBOURHOOD_BASE` without; morphology is `MORPHOLOGY_PENALTY` for an inflected form, 1
|
|
49
|
+
* otherwise.
|
|
50
|
+
*/
|
|
51
|
+
export declare function confidenceFactors(input: ConfidenceInput, options?: ConfidenceOptions): ConfidenceFactors;
|
|
52
|
+
/** The product of the five factors, rounded to four decimals. */
|
|
53
|
+
export declare function confidenceOf(input: ConfidenceInput, options?: ConfidenceOptions): number;
|
|
54
|
+
/** The signals that lowered the confidence, in the order of the formula; the bonuses never count. */
|
|
55
|
+
export declare function confidencePenalties(input: ConfidenceInput, options?: ConfidenceOptions): ConfidencePenalty[];
|
|
56
|
+
//# sourceMappingURL=confidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence.d.ts","sourceRoot":"","sources":["../../src/keywords/confidence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE5C,oIAAoI;AACpI,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,sGAAsG;IACtG,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE5C,eAAO,MAAM,kBAAkB,EAAE,iBAAsC,CAAC;AAExE,mHAAmH;AACnH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,+EAA+E;AAC/E,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,gFAAgF;AAChF,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,wFAAwF;AACxF,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAMtC;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,OAAO,GAAE,iBAAsC,GAC9C,iBAAiB,CAiBnB;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,OAAO,GAAE,iBAAsC,GAC9C,MAAM,CAKR;AAED,qGAAqG;AACrG,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EACtB,OAAO,GAAE,iBAAsC,GAC9C,iBAAiB,EAAE,CAOrB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const confidenceDefaults = { maxSpread: 0.5 };
|
|
2
|
+
/** Files a corpus must hold before the spread of an expression is read: in a handful, every word is everywhere. */
|
|
3
|
+
export const SPREAD_MIN_FILES = 10;
|
|
4
|
+
/** Files an expression must reach before its occurrences per file are read. */
|
|
5
|
+
export const BURST_MIN_FILES = 5;
|
|
6
|
+
/** Occurrences per file from which an expression recurs where it is treated. */
|
|
7
|
+
export const BURST_PER_FILE = 1.5;
|
|
8
|
+
/** The position factor of an expression never put forward; the bonus fills the rest. */
|
|
9
|
+
export const POSITION_BASE = 0.8;
|
|
10
|
+
/** The neighbourhood factor of an expression no defined term accompanies. */
|
|
11
|
+
export const NEIGHBOURHOOD_BASE = 0.9;
|
|
12
|
+
/** The morphology factor of an inflected form: a soft penalty, never an elimination. */
|
|
13
|
+
export const MORPHOLOGY_PENALTY = 0.8;
|
|
14
|
+
function round(value) {
|
|
15
|
+
return Math.round(value * 10_000) / 10_000;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The factors of the formula: spread falls linearly from 1 at `maxSpread` to 0 when the
|
|
19
|
+
* expression is in every file, and reads only in a corpus of `SPREAD_MIN_FILES` files; burst
|
|
20
|
+
* rises linearly from 0.5 at one occurrence per file to 1 at `BURST_PER_FILE`, and reads
|
|
21
|
+
* only from `BURST_MIN_FILES` files; position is
|
|
22
|
+
* `POSITION_BASE` plus the prominence share of the rest; neighbourhood is 1 with the bonus,
|
|
23
|
+
* `NEIGHBOURHOOD_BASE` without; morphology is `MORPHOLOGY_PENALTY` for an inflected form, 1
|
|
24
|
+
* otherwise.
|
|
25
|
+
*/
|
|
26
|
+
export function confidenceFactors(input, options = confidenceDefaults) {
|
|
27
|
+
const excess = input.corpus < SPREAD_MIN_FILES
|
|
28
|
+
? 0
|
|
29
|
+
: Math.max(0, input.spread - options.maxSpread) / (1 - options.maxSpread);
|
|
30
|
+
// Below `BURST_MIN_FILES` files, once per file says nothing; an expression never occurs less than once per file.
|
|
31
|
+
const burst = input.files < BURST_MIN_FILES
|
|
32
|
+
? 1
|
|
33
|
+
: Math.min(1, 0.5 + (0.5 * (input.burst - 1)) / (BURST_PER_FILE - 1));
|
|
34
|
+
return {
|
|
35
|
+
spread: 1 - excess,
|
|
36
|
+
burst,
|
|
37
|
+
position: POSITION_BASE + (1 - POSITION_BASE) * input.prominence,
|
|
38
|
+
neighbourhood: input.neighbour ? 1 : NEIGHBOURHOOD_BASE,
|
|
39
|
+
morphology: input.inflected ? MORPHOLOGY_PENALTY : 1,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** The product of the five factors, rounded to four decimals. */
|
|
43
|
+
export function confidenceOf(input, options = confidenceDefaults) {
|
|
44
|
+
const factors = confidenceFactors(input, options);
|
|
45
|
+
return round(factors.spread * factors.burst * factors.position * factors.neighbourhood * factors.morphology);
|
|
46
|
+
}
|
|
47
|
+
/** The signals that lowered the confidence, in the order of the formula; the bonuses never count. */
|
|
48
|
+
export function confidencePenalties(input, options = confidenceDefaults) {
|
|
49
|
+
const factors = confidenceFactors(input, options);
|
|
50
|
+
const penalties = [];
|
|
51
|
+
if (factors.spread < 1)
|
|
52
|
+
penalties.push("spread");
|
|
53
|
+
if (factors.burst < 1)
|
|
54
|
+
penalties.push("burst");
|
|
55
|
+
if (factors.morphology < 1)
|
|
56
|
+
penalties.push("morphology");
|
|
57
|
+
return penalties;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=confidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence.js","sourceRoot":"","sources":["../../src/keywords/confidence.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,kBAAkB,GAAsB,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AAExE,mHAAmH;AACnH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAClC,wFAAwF;AACxF,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,wFAAwF;AACxF,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAsB,EACtB,UAA6B,kBAAkB;IAE/C,MAAM,MAAM,GACV,KAAK,CAAC,MAAM,GAAG,gBAAgB;QAC7B,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9E,iHAAiH;IACjH,MAAM,KAAK,GACT,KAAK,CAAC,KAAK,GAAG,eAAe;QAC3B,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO;QACL,MAAM,EAAE,CAAC,GAAG,MAAM;QAClB,KAAK;QACL,QAAQ,EAAE,aAAa,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,KAAK,CAAC,UAAU;QAChE,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB;QACvD,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAC1B,KAAsB,EACtB,UAA6B,kBAAkB;IAE/C,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,KAAK,CACV,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,UAAU,CAC/F,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,mBAAmB,CACjC,KAAsB,EACtB,UAA6B,kBAAkB;IAE/C,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LanguagePack } from "../locale/pack.js";
|
|
2
|
+
import { type NgramOccurrence } from "./ngrams.js";
|
|
3
|
+
/** A recurring expression a note defines: what would be a keyword page, had the note not been written. */
|
|
4
|
+
export interface DefinedExpression {
|
|
5
|
+
/** The comparison form of the dictionary entry, as the n-grams carry it. */
|
|
6
|
+
key: string;
|
|
7
|
+
occurrences: number;
|
|
8
|
+
/** Distinct files the expression appears in. */
|
|
9
|
+
documents: number;
|
|
10
|
+
}
|
|
11
|
+
export interface DefinedExpressionsOptions {
|
|
12
|
+
pack: LanguagePack;
|
|
13
|
+
/** Comparison forms of the dictionary entries. */
|
|
14
|
+
dictionaryKeys: ReadonlySet<string>;
|
|
15
|
+
minOccurrences: number;
|
|
16
|
+
/** Distinct files the expression must appear in. */
|
|
17
|
+
minDocuments: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The n-grams the dictionary already defines that reach the publication threshold, in key
|
|
21
|
+
* order. Such an expression gets no keyword page, its note being the page; the build keeps
|
|
22
|
+
* the address the page would have had, so that a word defined after its page was published
|
|
23
|
+
* keeps its URL.
|
|
24
|
+
*/
|
|
25
|
+
export declare function definedExpressions(occurrences: readonly NgramOccurrence[], options: DefinedExpressionsOptions): DefinedExpression[];
|
|
26
|
+
//# sourceMappingURL=defined.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defined.d.ts","sourceRoot":"","sources":["../../src/keywords/defined.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAEjE,0GAA0G;AAC1G,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,YAAY,CAAC;IACnB,kDAAkD;IAClD,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;CACtB;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,SAAS,eAAe,EAAE,EACvC,OAAO,EAAE,yBAAyB,GACjC,iBAAiB,EAAE,CA4BrB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { keywordForms } from "./ngrams.js";
|
|
2
|
+
/**
|
|
3
|
+
* The n-grams the dictionary already defines that reach the publication threshold, in key
|
|
4
|
+
* order. Such an expression gets no keyword page, its note being the page; the build keeps
|
|
5
|
+
* the address the page would have had, so that a word defined after its page was published
|
|
6
|
+
* keeps its URL.
|
|
7
|
+
*/
|
|
8
|
+
export function definedExpressions(occurrences, options) {
|
|
9
|
+
const defined = keywordForms(options.dictionaryKeys, options.pack);
|
|
10
|
+
const counts = new Map();
|
|
11
|
+
for (const occurrence of occurrences) {
|
|
12
|
+
if (!defined.has(occurrence.key))
|
|
13
|
+
continue;
|
|
14
|
+
let count = counts.get(occurrence.key);
|
|
15
|
+
if (count === undefined) {
|
|
16
|
+
count = { occurrences: 0, documents: new Set() };
|
|
17
|
+
counts.set(occurrence.key, count);
|
|
18
|
+
}
|
|
19
|
+
count.occurrences += 1;
|
|
20
|
+
count.documents.add(`${occurrence.source ?? ""}\n${occurrence.path}`);
|
|
21
|
+
}
|
|
22
|
+
return ([...counts]
|
|
23
|
+
.filter(([, count]) => count.occurrences >= options.minOccurrences &&
|
|
24
|
+
count.documents.size >= options.minDocuments)
|
|
25
|
+
.map(([key, count]) => ({
|
|
26
|
+
key,
|
|
27
|
+
occurrences: count.occurrences,
|
|
28
|
+
documents: count.documents.size,
|
|
29
|
+
}))
|
|
30
|
+
// Keys are distinct: the comparison never meets two equal ones.
|
|
31
|
+
.sort((a, b) => (a.key < b.key ? -1 : 1)));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=defined.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defined.js","sourceRoot":"","sources":["../../src/keywords/defined.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AAyBjE;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAAuC,EACvC,OAAkC;IAElC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3C,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;YACjD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;QACvB,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,IAAI,EAAE,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,CACL,CAAC,GAAG,MAAM,CAAC;SACR,MAAM,CACL,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CACZ,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC,cAAc;QAC3C,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,OAAO,CAAC,YAAY,CAC/C;SACA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,GAAG;QACH,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI;KAChC,CAAC,CAAC;QACH,gEAAgE;SAC/D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Finding } from "@concordance-wiki/core";
|
|
2
|
+
import type { KeywordCandidate } from "./score.js";
|
|
3
|
+
export declare const UNDEFINED_TERM_CHECK = "W-TERM-UNDEFINED";
|
|
4
|
+
export interface UndefinedTermOptions {
|
|
5
|
+
/** Score from which a candidate deserves a finding. */
|
|
6
|
+
minScore: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One `W-TERM-UNDEFINED` per candidate scoring at least `minScore`, placed on its first
|
|
10
|
+
* mention, in canonical order.
|
|
11
|
+
*/
|
|
12
|
+
export declare function undefinedTermFindings(candidates: readonly KeywordCandidate[], options: UndefinedTermOptions): Finding[];
|
|
13
|
+
//# sourceMappingURL=findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../src/keywords/findings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAEnE,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,EAAE,CAcX"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { compareFindings } from "@concordance-wiki/core";
|
|
2
|
+
export const UNDEFINED_TERM_CHECK = "W-TERM-UNDEFINED";
|
|
3
|
+
function plural(count, noun) {
|
|
4
|
+
return `${String(count)} ${noun}${count === 1 ? "" : "s"}`;
|
|
5
|
+
}
|
|
6
|
+
function locationOf(mentions) {
|
|
7
|
+
const [first] = mentions;
|
|
8
|
+
if (first === undefined)
|
|
9
|
+
return {};
|
|
10
|
+
return {
|
|
11
|
+
...(first.source === undefined ? {} : { source: first.source }),
|
|
12
|
+
path: first.path,
|
|
13
|
+
line: first.line,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* One `W-TERM-UNDEFINED` per candidate scoring at least `minScore`, placed on its first
|
|
18
|
+
* mention, in canonical order.
|
|
19
|
+
*/
|
|
20
|
+
export function undefinedTermFindings(candidates, options) {
|
|
21
|
+
const findings = [];
|
|
22
|
+
for (const candidate of candidates) {
|
|
23
|
+
if (candidate.score < options.minScore)
|
|
24
|
+
continue;
|
|
25
|
+
findings.push({
|
|
26
|
+
check: UNDEFINED_TERM_CHECK,
|
|
27
|
+
severity: "warning",
|
|
28
|
+
message: `"${candidate.display}" is used ${plural(candidate.occurrences, "time")} in ${plural(candidate.documents, "file")} (score ${String(candidate.score)}) without a note defining it`,
|
|
29
|
+
remediation: "Create a term note in the glossary, or add the expression to `rejected_terms` in the lock file if it is not a business term.",
|
|
30
|
+
...locationOf(candidate.mentions),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return findings.sort(compareFindings);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/keywords/findings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,wBAAwB,CAAC;AAIvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AAOvD,SAAS,MAAM,CAAC,KAAa,EAAE,IAAY;IACzC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,UAAU,CACjB,QAAmC;IAEnC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IACzB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/D,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAuC,EACvC,OAA6B;IAE7B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ;YAAE,SAAS;QACjD,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,oBAAoB;YAC3B,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,aAAa,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,8BAA8B;YAC1L,WAAW,EACT,8HAA8H;YAChI,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { LanguagePack } from "../locale/pack.js";
|
|
2
|
+
import { type QuotedText } from "../scan/context.js";
|
|
3
|
+
/** A text unit the discovery reads: a scannable unit of a document, with the file it comes from. */
|
|
4
|
+
export interface KeywordUnit extends QuotedText {
|
|
5
|
+
/** Name of the source holding the file; two sources may hold the same path. */
|
|
6
|
+
source?: string;
|
|
7
|
+
path: string;
|
|
8
|
+
line: number;
|
|
9
|
+
/** The text the discovery reads, inline code left out. */
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
export interface NgramOccurrence {
|
|
13
|
+
/** The words in comparison form, joined by a single space. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** The span as written in the text. */
|
|
16
|
+
surface: string;
|
|
17
|
+
source?: string;
|
|
18
|
+
path: string;
|
|
19
|
+
line: number;
|
|
20
|
+
/** Code unit offset of the span in the unit text. */
|
|
21
|
+
position: number;
|
|
22
|
+
/** 160 characters of the unit text as written, inline code included, centred on the span, an ellipsis marking each cut. */
|
|
23
|
+
context: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ExtractNgramsOptions {
|
|
26
|
+
/** Shortest n-gram, in words; 1 by default. */
|
|
27
|
+
minWords?: number;
|
|
28
|
+
/** Longest n-gram, in words. */
|
|
29
|
+
maxWords: number;
|
|
30
|
+
/** Below this length of the key, an n-gram is noise. */
|
|
31
|
+
minLength: number;
|
|
32
|
+
/** The pack's stopwords by default; given as written, compared in comparison form. */
|
|
33
|
+
stopwords?: ReadonlySet<string>;
|
|
34
|
+
}
|
|
35
|
+
/** The comparison form of a term as the n-grams carry it: its words, tokenised like the texts. */
|
|
36
|
+
export declare function keywordForm(text: string, pack: LanguagePack): string;
|
|
37
|
+
/** The comparison forms of a list of terms. */
|
|
38
|
+
export declare function keywordForms(forms: Iterable<string>, pack: LanguagePack): Set<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Every n-gram of `minWords` to `maxWords` words in the units, in unit then text order,
|
|
41
|
+
* except those starting or ending with a stopword, those made only of digits and those
|
|
42
|
+
* whose key is shorter than `minLength`. Words are the tokens of the text: normalised by
|
|
43
|
+
* the pack and singularised, so that "Build summaries" and "build summary"
|
|
44
|
+
* share a key while each keeps its surface form.
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractNgrams(units: readonly KeywordUnit[], pack: LanguagePack, options: ExtractNgramsOptions): NgramOccurrence[];
|
|
47
|
+
//# sourceMappingURL=ngrams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngrams.d.ts","sourceRoot":"","sources":["../../src/keywords/ngrams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGxE,oGAAoG;AACpG,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,2HAA2H;IAC3H,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC;AAKD,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAIpE;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAErF;AA6CD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,oBAAoB,GAC5B,eAAe,EAAE,CAQnB"}
|