chaffjs 0.23.0 → 0.25.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/dist/detectors/bare-comparative.d.ts +26 -0
- package/dist/detectors/bare-comparative.d.ts.map +1 -0
- package/dist/detectors/bare-comparative.js +117 -0
- package/dist/detectors/bare-comparative.js.map +1 -0
- package/dist/detectors/chat-citation.d.ts +6 -0
- package/dist/detectors/chat-citation.d.ts.map +1 -1
- package/dist/detectors/chat-citation.js +26 -1
- package/dist/detectors/chat-citation.js.map +1 -1
- package/dist/detectors/clause-shape.d.ts.map +1 -1
- package/dist/detectors/clause-shape.js +19 -5
- package/dist/detectors/clause-shape.js.map +1 -1
- package/dist/detectors/connective-hierarchy.d.ts +16 -0
- package/dist/detectors/connective-hierarchy.d.ts.map +1 -0
- package/dist/detectors/connective-hierarchy.js +68 -0
- package/dist/detectors/connective-hierarchy.js.map +1 -0
- package/dist/detectors/definition-use.d.ts.map +1 -1
- package/dist/detectors/definition-use.js +4 -2
- package/dist/detectors/definition-use.js.map +1 -1
- package/dist/detectors/generic-heading.d.ts +8 -0
- package/dist/detectors/generic-heading.d.ts.map +1 -0
- package/dist/detectors/generic-heading.js +26 -0
- package/dist/detectors/generic-heading.js.map +1 -0
- package/dist/detectors/ime-residue.d.ts +13 -0
- package/dist/detectors/ime-residue.d.ts.map +1 -0
- package/dist/detectors/ime-residue.js +27 -0
- package/dist/detectors/ime-residue.js.map +1 -0
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +9 -2
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/lookalike-character.d.ts +18 -0
- package/dist/detectors/lookalike-character.d.ts.map +1 -0
- package/dist/detectors/lookalike-character.js +50 -0
- package/dist/detectors/lookalike-character.js.map +1 -0
- package/dist/detectors/lowercase-name.d.ts +9 -0
- package/dist/detectors/lowercase-name.d.ts.map +1 -0
- package/dist/detectors/lowercase-name.js +40 -0
- package/dist/detectors/lowercase-name.js.map +1 -0
- package/dist/detectors/missing-final-period.d.ts +17 -0
- package/dist/detectors/missing-final-period.d.ts.map +1 -0
- package/dist/detectors/missing-final-period.js +62 -0
- package/dist/detectors/missing-final-period.js.map +1 -0
- package/dist/detectors/missing-space-after-comma.d.ts +10 -0
- package/dist/detectors/missing-space-after-comma.d.ts.map +1 -0
- package/dist/detectors/missing-space-after-comma.js +42 -0
- package/dist/detectors/missing-space-after-comma.js.map +1 -0
- package/dist/detectors/registry/bare-comparative.d.ts +3 -0
- package/dist/detectors/registry/bare-comparative.d.ts.map +1 -0
- package/dist/detectors/registry/bare-comparative.js +3 -0
- package/dist/detectors/registry/bare-comparative.js.map +1 -0
- package/dist/detectors/registry/calendar-name-case.d.ts +3 -0
- package/dist/detectors/registry/calendar-name-case.d.ts.map +1 -0
- package/dist/detectors/registry/calendar-name-case.js +3 -0
- package/dist/detectors/registry/calendar-name-case.js.map +1 -0
- package/dist/detectors/registry/connective-hierarchy.d.ts +3 -0
- package/dist/detectors/registry/connective-hierarchy.d.ts.map +1 -0
- package/dist/detectors/registry/connective-hierarchy.js +3 -0
- package/dist/detectors/registry/connective-hierarchy.js.map +1 -0
- package/dist/detectors/registry/generic-heading.d.ts +3 -0
- package/dist/detectors/registry/generic-heading.d.ts.map +1 -0
- package/dist/detectors/registry/generic-heading.js +3 -0
- package/dist/detectors/registry/generic-heading.js.map +1 -0
- package/dist/detectors/registry/ime-residue.d.ts +3 -0
- package/dist/detectors/registry/ime-residue.d.ts.map +1 -0
- package/dist/detectors/registry/ime-residue.js +3 -0
- package/dist/detectors/registry/ime-residue.js.map +1 -0
- package/dist/detectors/registry/lookalike-character.d.ts +3 -0
- package/dist/detectors/registry/lookalike-character.d.ts.map +1 -0
- package/dist/detectors/registry/lookalike-character.js +3 -0
- package/dist/detectors/registry/lookalike-character.js.map +1 -0
- package/dist/detectors/registry/missing-final-period.d.ts +3 -0
- package/dist/detectors/registry/missing-final-period.d.ts.map +1 -0
- package/dist/detectors/registry/missing-final-period.js +3 -0
- package/dist/detectors/registry/missing-final-period.js.map +1 -0
- package/dist/detectors/registry/missing-space-after-comma.d.ts +3 -0
- package/dist/detectors/registry/missing-space-after-comma.d.ts.map +1 -0
- package/dist/detectors/registry/missing-space-after-comma.js +3 -0
- package/dist/detectors/registry/missing-space-after-comma.js.map +1 -0
- package/dist/detectors/registry/unit-spacing-consistency.d.ts +3 -0
- package/dist/detectors/registry/unit-spacing-consistency.d.ts.map +1 -0
- package/dist/detectors/registry/unit-spacing-consistency.js +3 -0
- package/dist/detectors/registry/unit-spacing-consistency.js.map +1 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +8 -4
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +32 -7
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/technical-docs.d.ts.map +1 -1
- package/dist/detectors/technical-docs.js +14 -0
- package/dist/detectors/technical-docs.js.map +1 -1
- package/dist/detectors/unit-spacing.d.ts +25 -0
- package/dist/detectors/unit-spacing.d.ts.map +1 -0
- package/dist/detectors/unit-spacing.js +50 -0
- package/dist/detectors/unit-spacing.js.map +1 -0
- package/dist/quoted-span.d.ts +7 -0
- package/dist/quoted-span.d.ts.map +1 -1
- package/dist/quoted-span.js +20 -0
- package/dist/quoted-span.js.map +1 -1
- package/dist/structure/definition-use.d.ts +14 -4
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +29 -9
- package/dist/structure/definition-use.js.map +1 -1
- package/package.json +3 -3
- package/rules/calendar-name-case.yaml +55 -0
- package/rules/comparative-without-baseline.yaml +71 -0
- package/rules/connective-hierarchy.yaml +62 -0
- package/rules/cross-doc-broken-link.yaml +1 -1
- package/rules/cross-doc-duplicate-definition.yaml +1 -1
- package/rules/cross-doc-fact-conflict.yaml +1 -1
- package/rules/cross-doc-term-variant.yaml +5 -3
- package/rules/ime-residue.yaml +55 -0
- package/rules/lookalike-character.yaml +82 -0
- package/rules/missing-final-period.yaml +76 -0
- package/rules/missing-space-after-comma.yaml +57 -0
- package/rules/numbered-generic-heading.yaml +111 -0
- package/rules/undefined-acronym.yaml +1 -0
- package/rules/unit-spacing-consistency.yaml +74 -0
- package/skills/chaff/SKILL.md +20 -3
- package/src/detectors/bare-comparative.ts +152 -0
- package/src/detectors/chat-citation.ts +28 -1
- package/src/detectors/clause-shape.ts +20 -6
- package/src/detectors/connective-hierarchy.ts +99 -0
- package/src/detectors/definition-use.ts +13 -3
- package/src/detectors/generic-heading.ts +30 -0
- package/src/detectors/ime-residue.ts +37 -0
- package/src/detectors/lexicon.ts +11 -2
- package/src/detectors/lookalike-character.ts +75 -0
- package/src/detectors/lowercase-name.ts +58 -0
- package/src/detectors/missing-final-period.ts +79 -0
- package/src/detectors/missing-space-after-comma.ts +54 -0
- package/src/detectors/registry/bare-comparative.ts +4 -0
- package/src/detectors/registry/calendar-name-case.ts +4 -0
- package/src/detectors/registry/connective-hierarchy.ts +4 -0
- package/src/detectors/registry/generic-heading.ts +4 -0
- package/src/detectors/registry/ime-residue.ts +4 -0
- package/src/detectors/registry/lookalike-character.ts +4 -0
- package/src/detectors/registry/missing-final-period.ts +4 -0
- package/src/detectors/registry/missing-space-after-comma.ts +4 -0
- package/src/detectors/registry/unit-spacing-consistency.ts +4 -0
- package/src/detectors/signals.ts +9 -5
- package/src/detectors/structure-tree.ts +55 -30
- package/src/detectors/technical-docs.ts +13 -0
- package/src/detectors/unit-spacing.ts +71 -0
- package/src/quoted-span.ts +25 -0
- package/src/structure/definition-use.ts +42 -10
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// shell-prompt lexicons.
|
|
5
5
|
import { codeFences, codeSpans, type CodeFence } from "./code-fences.ts";
|
|
6
6
|
import { quoteAt } from "./structure-tree.ts";
|
|
7
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
7
8
|
import type { Detector, Finding, ProseDocument, Span, Token } from "../plugin.ts";
|
|
8
9
|
|
|
9
10
|
const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
|
|
@@ -112,10 +113,22 @@ export const commandsIn = (heading: string): string[] => {
|
|
|
112
113
|
const collapse = (text: string): string => text.replace(/\s+/gu, " ");
|
|
113
114
|
const OPTION_CHAR = /[A-Za-z0-9_-]/u;
|
|
114
115
|
|
|
116
|
+
/**
|
|
117
|
+
* A command with arguments whose program the code runs under its package's name: chaff grade as npx chaffjs grade,
|
|
118
|
+
* python -m venv as python3 -m venv. The arguments must follow as written.
|
|
119
|
+
*/
|
|
120
|
+
const showsUnderPackageName = (text: string, wanted: string): boolean => {
|
|
121
|
+
const [program = "", ...rest] = wanted.split(" ");
|
|
122
|
+
if (rest.length === 0) return false;
|
|
123
|
+
const pattern = `(?<![A-Za-z0-9_.-])${escapeRegExp(program)}[A-Za-z0-9_.-]* ${rest.map(escapeRegExp).join(" ")}(?![A-Za-z0-9_-])`;
|
|
124
|
+
return new RegExp(pattern, "u").test(text);
|
|
125
|
+
};
|
|
126
|
+
|
|
115
127
|
/** Whether the code holds the command as a whole word: --force is not --force-with-lease, init is not initial. */
|
|
116
128
|
export const showsCommand = (code: string, command: string): boolean => {
|
|
117
129
|
const text = collapse(code);
|
|
118
130
|
const wanted = collapse(command.trim());
|
|
131
|
+
if (showsUnderPackageName(text, wanted)) return true;
|
|
119
132
|
const state = { at: text.indexOf(wanted) };
|
|
120
133
|
while (state.at !== -1) {
|
|
121
134
|
const before = text.charAt(state.at - 1);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
2
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
3
|
+
import { formMinority } from "./form-minority.ts";
|
|
4
|
+
import { quoteAround } from "./quote-around.ts";
|
|
5
|
+
|
|
6
|
+
// One document writing a number and a unit symbol both with a space between them ("5 GB") and without ("5GB"). Neither is
|
|
7
|
+
// called right; per unit, the less common way is reported. The symbols come from each language's lexicon "unit-symbol".
|
|
8
|
+
|
|
9
|
+
/** A number and its unit as written. form is "spaced" or "touching". */
|
|
10
|
+
export type WrittenQuantity = { readonly offset: number; readonly written: string; readonly unit: string; readonly form: string };
|
|
11
|
+
|
|
12
|
+
/** The less common way for one unit, with an example of the usual way and how many quantities of that unit there are. */
|
|
13
|
+
export type UnitMinority = { readonly odd: WrittenQuantity; readonly usual: string; readonly count: number; readonly of: number };
|
|
14
|
+
|
|
15
|
+
// Grouping commas, then at most one decimal point: 1.2.3 is a version, not a number.
|
|
16
|
+
const NUMBER = "[0-9]+(?:,[0-9]{3})*(?:\\.[0-9]+)?";
|
|
17
|
+
// A plain space, a no-break space or a narrow no-break space (the SI brochure's thin space between number and unit).
|
|
18
|
+
const GAP = "[ \\u00A0\\u202F]?";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Numbers followed by a unit symbol, at most one space between. The number must not be part of a word, a version or an
|
|
22
|
+
* address (v1.2GB, x86, 1.2.3GB), nor follow a hyphen: "10-8 cm" is as often a lost exponent as a range (5–10 GB, with
|
|
23
|
+
* an en dash, is read). The symbol must not run on into a word, a rate or a file name (5 GBit, 5 GB/s, 5GB.zip).
|
|
24
|
+
*/
|
|
25
|
+
export const quantitiesIn = (text: string, symbols: readonly string[]): WrittenQuantity[] => {
|
|
26
|
+
if (symbols.length === 0) return [];
|
|
27
|
+
const units = symbols
|
|
28
|
+
.toSorted((left, right) => right.length - left.length)
|
|
29
|
+
.map(escapeRegExp)
|
|
30
|
+
.join("|");
|
|
31
|
+
const pattern = new RegExp(`(?<![A-Za-z0-9_.,/:#-])${NUMBER}(?<gap>${GAP})(?<unit>${units})(?![A-Za-z0-9_/]|\\.[A-Za-z0-9_])`, "gu");
|
|
32
|
+
return [...text.matchAll(pattern)].map((match) => ({
|
|
33
|
+
offset: match.index,
|
|
34
|
+
written: match[0],
|
|
35
|
+
unit: match.groups?.["unit"] ?? "",
|
|
36
|
+
form: match.groups?.["gap"] === "" ? "touching" : "spaced",
|
|
37
|
+
}));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const minorityOf = (ofUnit: readonly WrittenQuantity[], limit: number): UnitMinority[] => {
|
|
41
|
+
const minority = formMinority(ofUnit, limit);
|
|
42
|
+
if (minority === undefined) return [];
|
|
43
|
+
return minority.odd.map((quantity) => ({ odd: quantity, usual: minority.usual.written, count: minority.odd.length, of: ofUnit.length }));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Per unit, the quantities written the less common way. "5 GB" and "500ms" in one document are two units, each consistent. */
|
|
47
|
+
export const unitMinorities = (quantities: readonly WrittenQuantity[], limit: number): UnitMinority[] =>
|
|
48
|
+
[...new Set(quantities.map((quantity) => quantity.unit))]
|
|
49
|
+
.flatMap((unit) =>
|
|
50
|
+
minorityOf(
|
|
51
|
+
quantities.filter((quantity) => quantity.unit === unit),
|
|
52
|
+
limit,
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
.toSorted((left, right) => left.odd.offset - right.odd.offset);
|
|
56
|
+
|
|
57
|
+
export const unitSpacing: Detector = (doc, options): Finding[] => {
|
|
58
|
+
const text = doc.prose ?? doc.source;
|
|
59
|
+
const quantities = quantitiesIn(
|
|
60
|
+
text,
|
|
61
|
+
(doc.lexicons["unit-symbol"] ?? []).map((entry) => entry.pattern),
|
|
62
|
+
);
|
|
63
|
+
return unitMinorities(quantities, options.limit).map(({ odd, usual, count, of }) => ({
|
|
64
|
+
rule: "",
|
|
65
|
+
severity: "info",
|
|
66
|
+
line: 0,
|
|
67
|
+
column: 0,
|
|
68
|
+
quote: quoteAround(text, odd.offset, odd.offset + odd.written.length),
|
|
69
|
+
values: { written: odd.written, usual, count, of, offset: odd.offset },
|
|
70
|
+
}));
|
|
71
|
+
};
|
package/src/quoted-span.ts
CHANGED
|
@@ -41,5 +41,30 @@ export const quotedSpans = (text: string, marks: Marks = KAGI_MARKS): Span[] =>
|
|
|
41
41
|
export const quotedIn = (sentence: Sentence, marks: Marks = KAGI_MARKS): Span[] =>
|
|
42
42
|
quotedSpans(sentence.text, marks).map((span) => ({ start: sentence.span.start + span.start - 1, end: sentence.span.start + span.end + 1 }));
|
|
43
43
|
|
|
44
|
+
const MARKS = /[\s\p{P}]+/u;
|
|
45
|
+
const LETTERS = /^\p{L}+$/u;
|
|
46
|
+
|
|
47
|
+
/** 記号と空白のあいだに残る語が、字だけの語で、多くとも allowed 個か。 */
|
|
48
|
+
const holdsAtMost = (text: string, allowed: number): boolean => {
|
|
49
|
+
const words = text.split(MARKS).filter((word) => word !== "");
|
|
50
|
+
return words.length <= allowed && words.every((word) => LETTERS.test(word));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* span だけを引いた引用符("delves"、"?utm_source=chatgpt.com"、"October 26, 2026 – October 19, 2026")の中か。
|
|
55
|
+
* 引用符が語だけを囲めば、その語は使ったのではなく例として挙げたもの。周りの記号と空白は語の一部に数えない。
|
|
56
|
+
* wordsBesides は、span のほかに引用符の中にあってよい語の数(日付なら曜日の一語)。
|
|
57
|
+
* 話した言葉の引用("We ship on Monday, October 26," she said.)は語のほかの字を持つので当たらない。引用は一行の中だけを見る。
|
|
58
|
+
*/
|
|
59
|
+
export const isQuotedAlone = (text: string, span: Span, wordsBesides = 0): boolean => {
|
|
60
|
+
const lineStart = text.lastIndexOf("\n", span.start - 1) + 1;
|
|
61
|
+
const newline = text.indexOf("\n", span.end);
|
|
62
|
+
const line = text.slice(lineStart, newline === -1 ? text.length : newline);
|
|
63
|
+
const [start, end] = [span.start - lineStart, span.end - lineStart];
|
|
64
|
+
return quotedSpans(line, QUOTATION_MARKS).some(
|
|
65
|
+
(quoted) => quoted.start <= start && end <= quoted.end && holdsAtMost(`${line.slice(quoted.start, start)} ${line.slice(end, quoted.end)}`, wordsBesides),
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
44
69
|
/** inner が、spans のどれかにまるごと入っているか。 */
|
|
45
70
|
export const isWithinAny = (spans: readonly Span[], inner: Span): boolean => spans.some((span) => inner.start >= span.start && inner.end <= span.end);
|
|
@@ -4,7 +4,13 @@ import { inDocumentOrder } from "./issues.ts";
|
|
|
4
4
|
|
|
5
5
|
// 定義した語が本文で使われているか、定義より前に使われていないか。どちらも木の定義と、本文の文の字面だけで決まる。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** bare は、定義の語(means・以下…という・the)の無い括弧の引用(("Seller"))。例を引く括弧と同じ形。 */
|
|
8
|
+
export type DefinedTerm = { readonly term: string; readonly span: Span; readonly line: number; readonly inline: boolean; readonly bare?: boolean };
|
|
9
|
+
|
|
10
|
+
/** 文書の位置 [start, end) の語が、使ったのではなく引用符で例として挙げただけか。 */
|
|
11
|
+
export type Mentioned = (start: number, end: number) => boolean;
|
|
12
|
+
|
|
13
|
+
const NEVER_MENTIONED: Mentioned = () => false;
|
|
8
14
|
|
|
9
15
|
/** 本文の一続き(文)。start は文書の中の位置。 */
|
|
10
16
|
export type BodyText = { readonly start: number; readonly text: string };
|
|
@@ -30,7 +36,8 @@ export const definedTerms = (tree: StructureNode): DefinedTerm[] =>
|
|
|
30
36
|
.replaceAll(EMPHASIS_MARKS, "")
|
|
31
37
|
.trim()
|
|
32
38
|
: "";
|
|
33
|
-
|
|
39
|
+
const bare = node.attrs["form"] === "bare" ? { bare: true } : {};
|
|
40
|
+
return isTerm(term) ? [{ term, span: node.span, line: node.line, inline: node.attrs["placement"] === "inline", ...bare }] : [];
|
|
34
41
|
});
|
|
35
42
|
|
|
36
43
|
const LATIN_EDGE = /^[\p{Script=Latin}\p{N}]|[\p{Script=Latin}\p{N}]$/u;
|
|
@@ -56,11 +63,23 @@ const termPattern = (term: string, caseMatch: CaseMatch): RegExp => {
|
|
|
56
63
|
|
|
57
64
|
const inside = (offset: number, spans: readonly Span[]): boolean => spans.some((span) => span.start <= offset && offset < span.end);
|
|
58
65
|
|
|
59
|
-
/**
|
|
60
|
-
|
|
66
|
+
/**
|
|
67
|
+
* 語の現れ(文書の中の位置)を順に。定義そのもの("Seller" means、(the "Seller"))の中の現れは使用に数えない。
|
|
68
|
+
* mentioned が言う現れ(引用符で例として挙げただけ)も数えない。
|
|
69
|
+
*/
|
|
70
|
+
export const usesOf = (
|
|
71
|
+
term: string,
|
|
72
|
+
texts: readonly BodyText[],
|
|
73
|
+
definitionSpans: readonly Span[],
|
|
74
|
+
caseMatch: CaseMatch = "loose",
|
|
75
|
+
mentioned: Mentioned = NEVER_MENTIONED,
|
|
76
|
+
): number[] => {
|
|
61
77
|
const pattern = termPattern(term, caseMatch);
|
|
62
78
|
return texts.flatMap((body) =>
|
|
63
|
-
[...body.text.matchAll(pattern)]
|
|
79
|
+
[...body.text.matchAll(pattern)]
|
|
80
|
+
.filter((match) => !mentioned(body.start + match.index, body.start + match.index + match[0].length))
|
|
81
|
+
.map((match) => body.start + match.index)
|
|
82
|
+
.filter((offset) => !inside(offset, definitionSpans)),
|
|
64
83
|
);
|
|
65
84
|
};
|
|
66
85
|
|
|
@@ -78,10 +97,20 @@ const groupsOf = (terms: readonly DefinedTerm[]): TermGroup[] => {
|
|
|
78
97
|
};
|
|
79
98
|
|
|
80
99
|
/** 定義したのに、定義の外で一度も使っていない語。同じ語の定義が二つあれば、最初の一つだけを言う(二つ目は duplicate-definition)。 */
|
|
81
|
-
export const unusedDefinitions = (terms: readonly DefinedTerm[], texts: readonly BodyText[]): DefinedTerm[] =>
|
|
82
|
-
groupsOf(terms)
|
|
83
|
-
|
|
100
|
+
export const unusedDefinitions = (terms: readonly DefinedTerm[], texts: readonly BodyText[], mentioned: Mentioned = NEVER_MENTIONED): DefinedTerm[] => {
|
|
101
|
+
const groups = groupsOf(terms);
|
|
102
|
+
const examples = quotesExamples(groups, texts, mentioned);
|
|
103
|
+
return groups
|
|
104
|
+
.filter((group) => !(examples && group.first.bare === true) && usesOf(group.first.term, texts, group.spans).length === 0)
|
|
84
105
|
.map((group) => group.first);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 定義の語の無い括弧の引用(("Seller"))を、文書が一つも本文で使っていなければ、それは定義ではなく例の引用
|
|
110
|
+
* (Plain verbs, not metaphors ("silently fails"))。引用符で挙げただけの現れは使用に数えない。
|
|
111
|
+
*/
|
|
112
|
+
const quotesExamples = (groups: readonly TermGroup[], texts: readonly BodyText[], mentioned: Mentioned): boolean =>
|
|
113
|
+
!groups.some((group) => group.first.bare === true && usesOf(group.first.term, texts, group.spans, "loose", mentioned).length > 0);
|
|
85
114
|
|
|
86
115
|
/** offset を含む文。texts は start の昇順で、二分探索で引く。 */
|
|
87
116
|
const sentenceAt = (texts: readonly BodyText[], offset: number): BodyText | undefined => {
|
|
@@ -118,13 +147,16 @@ const isDistinctive = (term: string): boolean => CAPITAL_OR_NON_LATIN.test(term)
|
|
|
118
147
|
* 文の途中で括弧に入れて定義した語((the "Seller")、以下「甲」という)を、その定義の文より前で使っている所。最初の一つだけ。
|
|
119
148
|
* 定義の文の中の現れ(株式会社GovTech東京(以下「GovTech東京」という。))は、定義する名前そのものなので数えない。札の文も数えない。
|
|
120
149
|
* 定義の条("Seller" means、「甲」とは)は条の並びの頭にも終わりにも置く書き方があるので、前で使っても言わない。
|
|
150
|
+
* 定義の語の無い括弧の引用(("The key point is"))は例の引用と同じ形なので、その語を引用符で挙げただけの現れ
|
|
151
|
+
* (Its sentences open with "The key point is")は使用ではない。定義の語のある定義((the "Seller")、以下「買主」という)は、
|
|
152
|
+
* 引用符に入れた現れ(The "Seller" ships)も使用。
|
|
121
153
|
*/
|
|
122
|
-
export const usesBeforeDefinition = (terms: readonly DefinedTerm[], texts: readonly BodyText[]): TermUse[] =>
|
|
154
|
+
export const usesBeforeDefinition = (terms: readonly DefinedTerm[], texts: readonly BodyText[], mentioned: Mentioned = NEVER_MENTIONED): TermUse[] =>
|
|
123
155
|
groupsOf(terms)
|
|
124
156
|
.filter((group) => group.first.inline && isDistinctive(group.first.term))
|
|
125
157
|
.flatMap(({ first: defined, spans }) => {
|
|
126
158
|
const defining = sentenceAt(texts, defined.span.start)?.start ?? defined.span.start;
|
|
127
|
-
const uses = usesOf(defined.term, texts, spans, "exact");
|
|
159
|
+
const uses = usesOf(defined.term, texts, spans, "exact", defined.bare === true ? mentioned : NEVER_MENTIONED);
|
|
128
160
|
const first = uses.find((offset) => !isLabel(sentenceAt(texts, offset), defined.term));
|
|
129
161
|
return first !== undefined && first < defining ? [{ term: defined, offset: first }] : [];
|
|
130
162
|
});
|