@polycode-projects/the-mechanical-code-talker 5.0.1 → 5.0.2
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/package.json +1 -2
- package/src/domain/inflect.mjs +67 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/the-mechanical-code-talker",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The Mechanical Code Talker (tmct) — a tolerant, offline, $0 chat surface that guides you toward precision queries about a software repository. ELIZA/PARRY-style but domain-obsessed with code. No model calls; indexes a repo on request (tmct index) or reads any producer's graph.",
|
|
@@ -57,7 +57,6 @@
|
|
|
57
57
|
"src/",
|
|
58
58
|
"!src/adapters/pii-scan.mjs",
|
|
59
59
|
"!src/domain/corpus-matrix.mjs",
|
|
60
|
-
"!src/domain/inflect.mjs",
|
|
61
60
|
"!src/domain/licences.mjs",
|
|
62
61
|
"!src/domain/markdown-links.mjs",
|
|
63
62
|
"!src/domain/pack-manifest.mjs",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// inflect.mjs — the regular English -s/-ed/-ing rules, applied to a lemma.
|
|
2
|
+
//
|
|
3
|
+
// WordNet carries lemmas only ("rest" is present, "rests" is absent), and it is
|
|
4
|
+
// the inflected forms that collide with the fuzzy repair tier's targets —
|
|
5
|
+
// "rests" is one edit from "tests". So the real-word collision table expands
|
|
6
|
+
// every lemma through these rules before it looks for collisions.
|
|
7
|
+
//
|
|
8
|
+
// These are the REGULAR rules and nothing else. No irregular table, no stress
|
|
9
|
+
// model: pastOf("run") is "runned" and pastOf("make") is "maked". That is the
|
|
10
|
+
// intended shape. The table's job is to name words the repair tier must not
|
|
11
|
+
// rewrite, and inflectionsOf is generous on purpose (see below) — an extra form
|
|
12
|
+
// costs one repair we decline to make, and the sentence misses honestly, while
|
|
13
|
+
// a missing form costs a real word rewritten into a different question,
|
|
14
|
+
// answered with confidence. The first is the cheaper mistake.
|
|
15
|
+
|
|
16
|
+
import { STOPWORDS } from "./interpret/normalize.mjs";
|
|
17
|
+
import {
|
|
18
|
+
FUZZY_TARGET_WORDS, FUZZY_REPAIR_MIN_LENGTH, fuzzyMatchInSet, fuzzyBound,
|
|
19
|
+
} from "./interpret/fuzzy.mjs";
|
|
20
|
+
|
|
21
|
+
const VOWELS = new Set(["a", "e", "i", "o", "u"]);
|
|
22
|
+
const isVowel = (c) => VOWELS.has(c);
|
|
23
|
+
|
|
24
|
+
/** A single final consonant after a single vowel doubles before -ed/-ing
|
|
25
|
+
* ("run" -> "running"). w, x and y never double. Stress is not modelled, so a
|
|
26
|
+
* second syllable doubles too ("visit" -> "visitting"). */
|
|
27
|
+
export function doublesFinalConsonant(w) {
|
|
28
|
+
const [c3, c2, c1] = [w.at(-3), w.at(-2), w.at(-1)];
|
|
29
|
+
if (!c3 || isVowel(c1) || "wxy".includes(c1)) return false;
|
|
30
|
+
return isVowel(c2) && !isVowel(c3);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function pluralOf(w) {
|
|
34
|
+
if (/(?:s|x|z|ch|sh)$/.test(w)) return `${w}es`;
|
|
35
|
+
if (/[^aeiou]y$/.test(w)) return `${w.slice(0, -1)}ies`;
|
|
36
|
+
return `${w}s`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function pastOf(w) {
|
|
40
|
+
if (w.endsWith("e")) return `${w}d`;
|
|
41
|
+
if (/[^aeiou]y$/.test(w)) return `${w.slice(0, -1)}ied`;
|
|
42
|
+
if (doublesFinalConsonant(w)) return `${w}${w.at(-1)}ed`;
|
|
43
|
+
return `${w}ed`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function gerundOf(w) {
|
|
47
|
+
if (w.endsWith("ie")) return `${w.slice(0, -2)}ying`;
|
|
48
|
+
if (w.endsWith("e") && !/(?:ee|oe|ye)$/.test(w)) return `${w.slice(0, -1)}ing`;
|
|
49
|
+
if (doublesFinalConsonant(w)) return `${w}${w.at(-1)}ing`;
|
|
50
|
+
return `${w}ing`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Every surface form of `w` the collision table counts as real English. */
|
|
54
|
+
export const inflectionsOf = (w) => [w, pluralOf(w), pastOf(w), gerundOf(w)];
|
|
55
|
+
|
|
56
|
+
/** The words in `realWords` that the repair tier would rewrite onto one of its
|
|
57
|
+
* targets: long enough to reach the tier, not a stopword, not a target itself,
|
|
58
|
+
* and within the fuzzy bound of some target. Sorted, so the table it feeds is
|
|
59
|
+
* reproducible. */
|
|
60
|
+
export function collisionsFrom(realWords) {
|
|
61
|
+
return [...realWords]
|
|
62
|
+
.filter((w) => w.length >= FUZZY_REPAIR_MIN_LENGTH)
|
|
63
|
+
.filter((w) => !STOPWORDS.has(w))
|
|
64
|
+
.filter((w) => !FUZZY_TARGET_WORDS.includes(w))
|
|
65
|
+
.filter((w) => fuzzyMatchInSet(w, FUZZY_TARGET_WORDS, fuzzyBound(w)) !== null)
|
|
66
|
+
.sort();
|
|
67
|
+
}
|