Skip to content

Commit ba86e40

Browse files
committed
conjugate before escaping
1 parent f38e47e commit ba86e40

File tree

1 file changed

+82
-62
lines changed

1 file changed

+82
-62
lines changed

dictionary/parser.ts

Lines changed: 82 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function lex<T>(parser: Parser<T>): Parser<T> {
6363
return parser.skip(spaces);
6464
}
6565
const backtick = matchString("`", "backtick");
66-
const word = allAtLeastOnce(
66+
const unescapedWord = allAtLeastOnce(
6767
choiceOnlyOne(
6868
match(WORDS, "word"),
6969
backtick
@@ -76,8 +76,8 @@ const word = allAtLeastOnce(
7676
.map((word) => word.join("").replaceAll(/\s+/g, " ").trim())
7777
.filter((word) =>
7878
word !== "" || throwError(new ArrayResultError("missing word"))
79-
)
80-
.map(escapeHtml);
79+
);
80+
const word = unescapedWord.map(escapeHtml);
8181
const slash = lex(matchString("/", "slash"));
8282
const forms = sequence(word, all(slash.with(word)))
8383
.map(([first, rest]) => [first, ...rest]);
@@ -131,70 +131,90 @@ function detectRepetition(
131131
`"${source.join("/")}" has no repetition pattern found`,
132132
);
133133
}
134-
const nounOnly = sequence(
135-
word,
136-
optionalAll(slash.with(word)),
137-
tag(
138-
keyword("n")
139-
.with(sequence(optionalAll(keyword("gerund")), optionalNumber)),
140-
),
141-
)
142-
.map<NounForms & { gerund: boolean }>(([first, second, [gerund, number]]) => {
143-
let singular: null | string;
144-
let plural: null | string;
145-
switch (number) {
146-
case null: {
147-
if (second == null) {
148-
const sentence = nlp(first);
149-
sentence.tag("Noun");
150-
singular = sentence
151-
.nouns()
152-
.toSingular()
153-
.text();
154-
plural = sentence
155-
.nouns()
156-
.toPlural()
157-
.text();
158-
if (singular === "" || plural === "") {
159-
throw new ArrayResultError(
160-
`no singular or plural form found for "${first}". consider ` +
161-
"providing both singular and plural forms instead",
162-
);
163-
}
164-
if (first !== singular) {
165-
throw new ArrayResultError(
166-
`conjugation error: "${first}" is not "${singular}". ` +
167-
"consider providing both singular and plural forms instead",
168-
);
169-
}
170-
} else {
171-
singular = first;
172-
plural = second;
134+
const nounOnly = choiceOnlyOne(
135+
sequence(
136+
unescapedWord,
137+
tag(
138+
keyword("n")
139+
.with(optionalAll(keyword("gerund"))),
140+
),
141+
)
142+
.map<NounForms & { gerund: boolean }>(
143+
([noun, gerund]) => {
144+
const sentence = nlp(noun);
145+
sentence.tag("Noun");
146+
const singular = sentence
147+
.nouns()
148+
.toSingular()
149+
.text();
150+
const plural = sentence
151+
.nouns()
152+
.toPlural()
153+
.text();
154+
if (singular === "" || plural === "") {
155+
throw new ArrayResultError(
156+
`no singular or plural form found for "${noun}". consider ` +
157+
"providing both singular and plural forms instead",
158+
);
173159
}
174-
break;
175-
}
176-
case "singular":
177-
case "plural":
178-
if (second != null) {
160+
if (noun !== singular) {
179161
throw new ArrayResultError(
180-
"number inside tag may not be provided when two forms of noun " +
181-
"are already provided",
162+
`conjugation error: "${noun}" is not "${singular}". ` +
163+
"consider providing both singular and plural forms instead",
182164
);
183165
}
166+
return {
167+
singular: escapeHtml(singular),
168+
plural: escapeHtml(plural),
169+
gerund: gerund != null,
170+
};
171+
},
172+
),
173+
sequence(
174+
word,
175+
tag(
176+
keyword("n")
177+
.with(sequence(optionalAll(keyword("gerund")), number)),
178+
),
179+
)
180+
.map<NounForms & { gerund: boolean }>(
181+
([noun, [gerund, number]]) => {
182+
let singular: null | string;
183+
let plural: null | string;
184184
switch (number) {
185185
case "singular":
186-
singular = first;
187-
plural = null;
188-
break;
189186
case "plural":
190-
singular = null;
191-
plural = first;
187+
switch (number) {
188+
case "singular":
189+
singular = noun;
190+
plural = null;
191+
break;
192+
case "plural":
193+
singular = null;
194+
plural = noun;
195+
break;
196+
}
192197
break;
193198
}
194-
break;
195-
}
196-
return { singular, plural, gerund: gerund != null };
197-
});
199+
return { singular, plural, gerund: gerund != null };
200+
},
201+
),
202+
sequence(
203+
word,
204+
optionalAll(slash.with(word)),
205+
tag(
206+
keyword("n")
207+
.with(optionalAll(keyword("gerund"))),
208+
),
209+
)
210+
.map<NounForms & { gerund: boolean }>(
211+
([singular, plural, gerund]) => ({
212+
singular,
213+
plural,
214+
gerund: gerund != null,
215+
}),
216+
),
217+
);
198218
const determinerType = choiceOnlyOne(
199219
keyword("article"),
200220
keyword("demonstrative"),
@@ -285,7 +305,7 @@ function verbOnly(tagInside: Parser<unknown>): Parser<VerbForms> {
285305
presentSingular,
286306
past,
287307
})),
288-
word
308+
unescapedWord
289309
.skip(tag(tagInside))
290310
.map((verb) => {
291311
const sentence = nlp(verb);
@@ -308,9 +328,9 @@ function verbOnly(tagInside: Parser<unknown>): Parser<VerbForms> {
308328
);
309329
}
310330
return {
311-
presentPlural: conjugations.Infinitive,
312-
presentSingular: conjugations.PresentTense,
313-
past: conjugations.PastTense,
331+
presentPlural: escapeHtml(conjugations.Infinitive),
332+
presentSingular: escapeHtml(conjugations.PresentTense),
333+
past: escapeHtml(conjugations.PastTense),
314334
};
315335
}),
316336
);

0 commit comments

Comments
 (0)