chaffjs 0.13.0 → 0.15.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/address-chain.d.ts +4 -1
- package/dist/address-chain.d.ts.map +1 -1
- package/dist/address-chain.js +5 -2
- package/dist/address-chain.js.map +1 -1
- package/dist/cli-text.d.ts +4 -1
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +14 -2
- package/dist/cli-text.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +21 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/eval.d.ts +4 -0
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +20 -6
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +2 -1
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +3 -2
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/tree.d.ts.map +1 -1
- package/dist/commands/tree.js +2 -1
- package/dist/commands/tree.js.map +1 -1
- package/dist/detectors/acronym-compound.d.ts +8 -0
- package/dist/detectors/acronym-compound.d.ts.map +1 -0
- package/dist/detectors/acronym-compound.js +8 -0
- package/dist/detectors/acronym-compound.js.map +1 -0
- package/dist/detectors/acronym-context.d.ts +6 -0
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +24 -1
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-expansion.d.ts +10 -0
- package/dist/detectors/acronym-expansion.d.ts.map +1 -1
- package/dist/detectors/acronym-expansion.js +63 -5
- package/dist/detectors/acronym-expansion.js.map +1 -1
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +38 -16
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/citation-key.d.ts +13 -0
- package/dist/detectors/citation-key.d.ts.map +1 -0
- package/dist/detectors/citation-key.js +9 -0
- package/dist/detectors/citation-key.js.map +1 -0
- package/dist/detectors/cited-name.d.ts +11 -0
- package/dist/detectors/cited-name.d.ts.map +1 -0
- package/dist/detectors/cited-name.js +15 -0
- package/dist/detectors/cited-name.js.map +1 -0
- package/dist/detectors/concrete-evidence.d.ts +7 -0
- package/dist/detectors/concrete-evidence.d.ts.map +1 -0
- package/dist/detectors/concrete-evidence.js +21 -0
- package/dist/detectors/concrete-evidence.js.map +1 -0
- package/dist/detectors/conjugated-form.d.ts +3 -0
- package/dist/detectors/conjugated-form.d.ts.map +1 -0
- package/dist/detectors/conjugated-form.js +29 -0
- package/dist/detectors/conjugated-form.js.map +1 -0
- package/dist/detectors/counter-edge.d.ts +8 -0
- package/dist/detectors/counter-edge.d.ts.map +1 -0
- package/dist/detectors/counter-edge.js +27 -0
- package/dist/detectors/counter-edge.js.map +1 -0
- package/dist/detectors/dotted-name.d.ts +13 -0
- package/dist/detectors/dotted-name.d.ts.map +1 -0
- package/dist/detectors/dotted-name.js +10 -0
- package/dist/detectors/dotted-name.js.map +1 -0
- package/dist/detectors/doubled-word.d.ts +6 -1
- package/dist/detectors/doubled-word.d.ts.map +1 -1
- package/dist/detectors/doubled-word.js +22 -2
- package/dist/detectors/doubled-word.js.map +1 -1
- package/dist/detectors/en-shape.d.ts +1 -1
- package/dist/detectors/en-shape.d.ts.map +1 -1
- package/dist/detectors/en-shape.js +11 -22
- package/dist/detectors/en-shape.js.map +1 -1
- package/dist/detectors/enumerated-runs.d.ts +22 -0
- package/dist/detectors/enumerated-runs.d.ts.map +1 -0
- package/dist/detectors/enumerated-runs.js +53 -0
- package/dist/detectors/enumerated-runs.js.map +1 -0
- package/dist/detectors/gram-place.d.ts +0 -4
- package/dist/detectors/gram-place.d.ts.map +1 -1
- package/dist/detectors/gram-place.js +6 -1
- package/dist/detectors/gram-place.js.map +1 -1
- package/dist/detectors/gram-predicate.d.ts +7 -0
- package/dist/detectors/gram-predicate.d.ts.map +1 -0
- package/dist/detectors/gram-predicate.js +44 -0
- package/dist/detectors/gram-predicate.js.map +1 -0
- package/dist/detectors/heading-case.d.ts +21 -0
- package/dist/detectors/heading-case.d.ts.map +1 -0
- package/dist/detectors/heading-case.js +38 -0
- package/dist/detectors/heading-case.js.map +1 -0
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +4 -1
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +7 -4
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/middle-dot.d.ts +6 -0
- package/dist/detectors/middle-dot.d.ts.map +1 -0
- package/dist/detectors/middle-dot.js +9 -0
- package/dist/detectors/middle-dot.js.map +1 -0
- package/dist/detectors/name-numeral.d.ts +16 -0
- package/dist/detectors/name-numeral.d.ts.map +1 -0
- package/dist/detectors/name-numeral.js +30 -0
- package/dist/detectors/name-numeral.js.map +1 -0
- package/dist/detectors/name-part.d.ts +8 -0
- package/dist/detectors/name-part.d.ts.map +1 -0
- package/dist/detectors/name-part.js +20 -0
- package/dist/detectors/name-part.js.map +1 -0
- package/dist/detectors/name-run.d.ts +8 -0
- package/dist/detectors/name-run.d.ts.map +1 -0
- package/dist/detectors/name-run.js +13 -0
- package/dist/detectors/name-run.js.map +1 -0
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +18 -6
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/placeholder.d.ts +14 -0
- package/dist/detectors/placeholder.d.ts.map +1 -0
- package/dist/detectors/placeholder.js +24 -0
- package/dist/detectors/placeholder.js.map +1 -0
- package/dist/detectors/polite-word.d.ts +4 -0
- package/dist/detectors/polite-word.d.ts.map +1 -0
- package/dist/detectors/polite-word.js +10 -0
- package/dist/detectors/polite-word.js.map +1 -0
- package/dist/detectors/quoted-variant.d.ts +7 -0
- package/dist/detectors/quoted-variant.d.ts.map +1 -0
- package/dist/detectors/quoted-variant.js +18 -0
- package/dist/detectors/quoted-variant.js.map +1 -0
- package/dist/detectors/register.d.ts +7 -5
- package/dist/detectors/register.d.ts.map +1 -1
- package/dist/detectors/register.js +6 -4
- package/dist/detectors/register.js.map +1 -1
- package/dist/detectors/roman-numeral.d.ts +6 -0
- package/dist/detectors/roman-numeral.d.ts.map +1 -0
- package/dist/detectors/roman-numeral.js +6 -0
- package/dist/detectors/roman-numeral.js.map +1 -0
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +14 -4
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/series-label.d.ts +13 -0
- package/dist/detectors/series-label.d.ts.map +1 -0
- package/dist/detectors/series-label.js +26 -0
- package/dist/detectors/series-label.js.map +1 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +37 -25
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.js +1 -1
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +2 -1
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/superlative-name.d.ts +9 -0
- package/dist/detectors/superlative-name.d.ts.map +1 -0
- package/dist/detectors/superlative-name.js +24 -0
- package/dist/detectors/superlative-name.js.map +1 -0
- package/dist/detectors/token-shape.d.ts.map +1 -1
- package/dist/detectors/token-shape.js +10 -2
- package/dist/detectors/token-shape.js.map +1 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +10 -4
- package/dist/document.js.map +1 -1
- package/dist/genre-check.d.ts +34 -0
- package/dist/genre-check.d.ts.map +1 -0
- package/dist/genre-check.js +21 -0
- package/dist/genre-check.js.map +1 -0
- package/dist/genre.d.ts +8 -1
- package/dist/genre.d.ts.map +1 -1
- package/dist/genre.js +29 -5
- package/dist/genre.js.map +1 -1
- package/dist/init.d.ts +0 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +0 -12
- package/dist/init.js.map +1 -1
- package/dist/joined-view.d.ts +25 -0
- package/dist/joined-view.d.ts.map +1 -0
- package/dist/joined-view.js +76 -0
- package/dist/joined-view.js.map +1 -0
- package/dist/line-continues.d.ts +6 -0
- package/dist/line-continues.d.ts.map +1 -0
- package/dist/line-continues.js +33 -0
- package/dist/line-continues.js.map +1 -0
- package/dist/measure.d.ts +1 -0
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +5 -1
- package/dist/measure.js.map +1 -1
- package/dist/number-name.d.ts +7 -3
- package/dist/number-name.d.ts.map +1 -1
- package/dist/number-name.js +51 -15
- package/dist/number-name.js.map +1 -1
- package/dist/orthography.d.ts +4 -0
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +11 -9
- package/dist/orthography.js.map +1 -1
- package/dist/plain-source.d.ts +6 -0
- package/dist/plain-source.d.ts.map +1 -0
- package/dist/plain-source.js +6 -0
- package/dist/plain-source.js.map +1 -0
- package/dist/plugin.d.ts +18 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/preamble-paragraphs.d.ts +7 -0
- package/dist/preamble-paragraphs.d.ts.map +1 -0
- package/dist/preamble-paragraphs.js +7 -0
- package/dist/preamble-paragraphs.js.map +1 -0
- package/dist/quoted-span.d.ts +10 -0
- package/dist/quoted-span.d.ts.map +1 -0
- package/dist/quoted-span.js +20 -0
- package/dist/quoted-span.js.map +1 -0
- package/dist/render/eval.d.ts +2 -1
- package/dist/render/eval.d.ts.map +1 -1
- package/dist/render/eval.js +84 -43
- package/dist/render/eval.js.map +1 -1
- package/dist/resolve-genre.d.ts +11 -0
- package/dist/resolve-genre.d.ts.map +1 -0
- package/dist/resolve-genre.js +18 -0
- package/dist/resolve-genre.js.map +1 -0
- package/dist/soft-break.d.ts +19 -0
- package/dist/soft-break.d.ts.map +1 -0
- package/dist/soft-break.js +78 -0
- package/dist/soft-break.js.map +1 -0
- package/dist/structure/build.d.ts.map +1 -1
- package/dist/structure/build.js +23 -10
- package/dist/structure/build.js.map +1 -1
- package/dist/structure/date-order.d.ts +3 -0
- package/dist/structure/date-order.d.ts.map +1 -1
- package/dist/structure/date-order.js +9 -1
- package/dist/structure/date-order.js.map +1 -1
- package/dist/structure/heading-leaves.d.ts +7 -0
- package/dist/structure/heading-leaves.d.ts.map +1 -0
- package/dist/structure/heading-leaves.js +6 -0
- package/dist/structure/heading-leaves.js.map +1 -0
- package/dist/structure/issues.d.ts +1 -1
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +14 -3
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/listed-tags.d.ts +3 -0
- package/dist/structure/listed-tags.d.ts.map +1 -0
- package/dist/structure/listed-tags.js +6 -0
- package/dist/structure/listed-tags.js.map +1 -0
- package/dist/structure/number-in-sentence.d.ts +15 -0
- package/dist/structure/number-in-sentence.d.ts.map +1 -0
- package/dist/structure/number-in-sentence.js +13 -0
- package/dist/structure/number-in-sentence.js.map +1 -0
- package/dist/structure/unit-word.d.ts +8 -0
- package/dist/structure/unit-word.d.ts.map +1 -0
- package/dist/structure/unit-word.js +10 -0
- package/dist/structure/unit-word.js.map +1 -0
- package/dist/structure/wrapped-tail.d.ts +18 -0
- package/dist/structure/wrapped-tail.d.ts.map +1 -0
- package/dist/structure/wrapped-tail.js +11 -0
- package/dist/structure/wrapped-tail.js.map +1 -0
- package/package.json +3 -3
- package/rules/dangling-reference.yaml +2 -2
- package/rules/date-order.yaml +2 -2
- package/rules/duplicate-definition.yaml +2 -2
- package/rules/latin-spacing.yaml +4 -2
- package/rules/max-kanji-continuous.yaml +1 -1
- package/rules/no-doubled-joshi.yaml +2 -2
- package/rules/no-nakaguro-parallel.yaml +2 -2
- package/rules/title-case-consistency.yaml +2 -2
- package/rules/undefined-acronym.yaml +15 -1
- package/rules/unqualified-superlative.yaml +1 -1
- package/src/address-chain.ts +5 -2
- package/src/cli-text.ts +19 -3
- package/src/cli.ts +22 -19
- package/src/commands/eval.ts +26 -5
- package/src/commands/feedback.ts +2 -1
- package/src/commands/test.ts +3 -2
- package/src/commands/tree.ts +2 -1
- package/src/detectors/acronym-compound.ts +9 -0
- package/src/detectors/acronym-context.ts +32 -1
- package/src/detectors/acronym-expansion.ts +72 -5
- package/src/detectors/char-shape.ts +44 -17
- package/src/detectors/citation-key.ts +13 -0
- package/src/detectors/cited-name.ts +23 -0
- package/src/detectors/concrete-evidence.ts +31 -0
- package/src/detectors/conjugated-form.ts +40 -0
- package/src/detectors/counter-edge.ts +29 -0
- package/src/detectors/dotted-name.ts +14 -0
- package/src/detectors/doubled-word.ts +25 -2
- package/src/detectors/en-shape.ts +17 -30
- package/src/detectors/enumerated-runs.ts +68 -0
- package/src/detectors/gram-place.ts +8 -1
- package/src/detectors/gram-predicate.ts +55 -0
- package/src/detectors/heading-case.ts +41 -0
- package/src/detectors/heading-echo.ts +5 -1
- package/src/detectors/lexicon.ts +8 -5
- package/src/detectors/middle-dot.ts +10 -0
- package/src/detectors/name-numeral.ts +37 -0
- package/src/detectors/name-part.ts +24 -0
- package/src/detectors/name-run.ts +16 -0
- package/src/detectors/orthography.ts +20 -9
- package/src/detectors/placeholder.ts +38 -0
- package/src/detectors/polite-word.ts +14 -0
- package/src/detectors/quoted-variant.ts +20 -0
- package/src/detectors/register.ts +11 -7
- package/src/detectors/roman-numeral.ts +5 -0
- package/src/detectors/sentence-ending.ts +23 -6
- package/src/detectors/series-label.ts +33 -0
- package/src/detectors/signals.ts +44 -31
- package/src/detectors/structure-tree.ts +2 -2
- package/src/detectors/structure.ts +2 -1
- package/src/detectors/superlative-name.ts +30 -0
- package/src/detectors/token-shape.ts +12 -3
- package/src/document.ts +12 -5
- package/src/genre-check.ts +46 -0
- package/src/genre.ts +34 -5
- package/src/init.ts +0 -13
- package/src/joined-view.ts +96 -0
- package/src/line-continues.ts +43 -0
- package/src/measure.ts +9 -1
- package/src/number-name.ts +65 -15
- package/src/orthography.ts +15 -9
- package/src/plain-source.ts +5 -0
- package/src/plugin.ts +23 -2
- package/src/preamble-paragraphs.ts +9 -0
- package/src/quoted-span.ts +25 -0
- package/src/render/eval.ts +101 -38
- package/src/resolve-genre.ts +20 -0
- package/src/soft-break.ts +94 -0
- package/src/structure/build.ts +29 -17
- package/src/structure/date-order.ts +16 -1
- package/src/structure/heading-leaves.ts +7 -0
- package/src/structure/issues.ts +18 -3
- package/src/structure/listed-tags.ts +7 -0
- package/src/structure/number-in-sentence.ts +20 -0
- package/src/structure/unit-word.ts +11 -0
- package/src/structure/wrapped-tail.ts +22 -0
package/src/structure/build.ts
CHANGED
|
@@ -7,7 +7,10 @@ import { maskSpans } from "../mask.ts";
|
|
|
7
7
|
import type { DocumentProfile, Mention, NumberedLine, NumberingContext, Span, StructureKind, StructureNode, StructurePatterns } from "../plugin.ts";
|
|
8
8
|
import { lineNumberAt, linesOf, type Line } from "./lines.ts";
|
|
9
9
|
import { dottedNumber } from "./universal.ts";
|
|
10
|
+
import { numberInSentence } from "./number-in-sentence.ts";
|
|
10
11
|
import { unnumberedUnit, type OpenUnit } from "./unnumbered.ts";
|
|
12
|
+
import { readsOnHeading } from "./heading-leaves.ts";
|
|
13
|
+
import { onLine, wrappedLine, type WrappedLine } from "./wrapped-tail.ts";
|
|
11
14
|
|
|
12
15
|
/** 組み立て中の節点。できあがったら StructureNode に固める。 */
|
|
13
16
|
type Draft = {
|
|
@@ -128,11 +131,14 @@ const outsideAddresses = (mentions: readonly Mention[], text: string, profile: D
|
|
|
128
131
|
const withoutAbsolute = (relative: readonly Mention[], absolute: readonly Mention[]): readonly Mention[] =>
|
|
129
132
|
relative.filter((mention) => !absolute.some((other) => mention.start < other.end && other.start < mention.end));
|
|
130
133
|
|
|
131
|
-
type LeafFinder = (patterns: StructurePatterns, text: string, profile: DocumentProfile | undefined) => readonly Mention[];
|
|
134
|
+
type LeafFinder = (patterns: StructurePatterns, text: string, profile: DocumentProfile | undefined, wrapped: WrappedLine) => readonly Mention[];
|
|
132
135
|
|
|
133
136
|
const LEAVES: readonly { readonly kind: StructureKind; readonly find: LeafFinder }[] = [
|
|
134
137
|
{ kind: "definition", find: (patterns, text) => patterns.definitions(text) },
|
|
135
|
-
{
|
|
138
|
+
{
|
|
139
|
+
kind: "reference",
|
|
140
|
+
find: (patterns, _text, profile, wrapped) => onLine(substitutedDocuments(patterns.references(wrapped.text), wrapped.text, profile), wrapped),
|
|
141
|
+
},
|
|
136
142
|
{
|
|
137
143
|
kind: "reference",
|
|
138
144
|
find: (patterns, text, profile) => {
|
|
@@ -145,10 +151,12 @@ const LEAVES: readonly { readonly kind: StructureKind; readonly find: LeafFinder
|
|
|
145
151
|
{ kind: "date", find: (patterns, text) => patterns.dates?.(text) ?? [] },
|
|
146
152
|
];
|
|
147
153
|
|
|
148
|
-
/**
|
|
154
|
+
/** 言語を問わない通し番号。後ろが単位なら数量、本文の文の続きなら文の中の数なので、番号にしない。 */
|
|
149
155
|
const universalNumber = (patterns: StructurePatterns, text: string, context: NumberingContext, plainText: boolean): NumberedLine | undefined => {
|
|
150
156
|
const dotted = dottedNumber(text, context, plainText);
|
|
151
|
-
|
|
157
|
+
if (dotted === undefined || patterns.countedAfter?.(dotted.number, dotted.rest) === true) return undefined;
|
|
158
|
+
const numbered = { number: dotted.number, rest: dotted.rest, isHeading: context.isHeading };
|
|
159
|
+
return numberInSentence(numbered, patterns.continuesSentence) ? undefined : dotted;
|
|
152
160
|
};
|
|
153
161
|
|
|
154
162
|
/** 行の中の定義・参照・義務・数量を、いま開いている最も内側の節点の子にする。 */
|
|
@@ -179,17 +187,20 @@ const scopeOf = (state: State, patterns: StructurePatterns, text: string): Reado
|
|
|
179
187
|
return within === undefined ? { scope: "local" } : { scope: "local", within: within.address };
|
|
180
188
|
};
|
|
181
189
|
|
|
182
|
-
const addLeaves = (state: State, patterns: StructurePatterns, line: Line,
|
|
190
|
+
const addLeaves = (state: State, patterns: StructurePatterns, line: Line, wrapped: WrappedLine, offset: number, onHeading: boolean): void => {
|
|
183
191
|
const parent = top(state).draft;
|
|
192
|
+
const text = wrapped.line;
|
|
184
193
|
const scope = scopeOf(state, patterns, text);
|
|
185
|
-
const leaves = LEAVES.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
const leaves = LEAVES.filter(({ kind }) => !onHeading || readsOnHeading(kind))
|
|
195
|
+
.flatMap(({ kind, find }) =>
|
|
196
|
+
find(patterns, text, state.profile, wrapped).map((mention) => ({
|
|
197
|
+
kind,
|
|
198
|
+
start: line.start + offset + mention.start,
|
|
199
|
+
end: line.start + offset + mention.end,
|
|
200
|
+
attrs: mention.attrs,
|
|
201
|
+
})),
|
|
202
|
+
)
|
|
203
|
+
.sort((left, right) => left.start - right.start);
|
|
193
204
|
leaves.forEach((leaf) =>
|
|
194
205
|
parent.children.push({
|
|
195
206
|
kind: leaf.kind,
|
|
@@ -287,7 +298,7 @@ const withCaption = (state: State, line: Line, numbered: NumberedLine | undefine
|
|
|
287
298
|
return numbered === undefined || caption === undefined ? numbered : { ...numbered, heading: caption };
|
|
288
299
|
};
|
|
289
300
|
|
|
290
|
-
const readLine = (state: State, patterns: StructurePatterns, line: Line, heading: Heading | undefined): void => {
|
|
301
|
+
const readLine = (state: State, patterns: StructurePatterns, line: Line, heading: Heading | undefined, next: string | undefined): void => {
|
|
291
302
|
const text = heading === undefined ? line.text : headingLineText(line.text);
|
|
292
303
|
const openNumbers = state.stack.flatMap((frame) => (frame.numbered === undefined ? [] : [frame.numbered]));
|
|
293
304
|
const context = { open: openNumbers, isHeading: heading !== undefined };
|
|
@@ -303,7 +314,8 @@ const readLine = (state: State, patterns: StructurePatterns, line: Line, heading
|
|
|
303
314
|
// 番号付きの行は番号の後ろだけを読む。「第3条(支払)」の「第3条」を自分への参照として拾わない。
|
|
304
315
|
const scanned = numbered === undefined ? text : numbered.rest;
|
|
305
316
|
const offset = Math.max(0, line.text.lastIndexOf(scanned));
|
|
306
|
-
|
|
317
|
+
const onHeading = heading !== undefined;
|
|
318
|
+
if (scanned !== "") addLeaves(state, patterns, line, wrappedLine(scanned, onHeading, next), offset, onHeading);
|
|
307
319
|
};
|
|
308
320
|
|
|
309
321
|
/**
|
|
@@ -328,8 +340,8 @@ export const buildTree = (input: StructureInput, patterns: StructurePatterns): S
|
|
|
328
340
|
captions: new Map(),
|
|
329
341
|
plainText: !input.markdown,
|
|
330
342
|
};
|
|
331
|
-
lines.forEach((line) => {
|
|
332
|
-
if (line.text.trim() !== "") readLine(state, patterns, line, headings.get(line.number));
|
|
343
|
+
lines.forEach((line, index) => {
|
|
344
|
+
if (line.text.trim() !== "") readLine(state, patterns, line, headings.get(line.number), lines[index + 1]?.text);
|
|
333
345
|
// コードの行は覆って読まないが、開いている節の中身ではある。節の最後にコードブロックがあっても、範囲をそこまで伸ばす。
|
|
334
346
|
else if (input.source.slice(line.start, line.start + line.text.length).trim() !== "") extend(state, line.start + line.text.length);
|
|
335
347
|
});
|
|
@@ -5,6 +5,7 @@ import { runsOf, type Line } from "./runs.ts";
|
|
|
5
5
|
* 日程として並べた日付の順番。箇条書きの続いた項目か、表の続いた行で、日付をちょうど一つ持つものを並びとして読む。
|
|
6
6
|
* 並びの向き(古い順か新しい順か)は多いほうで決め、それに逆らう一歩だけを言う。新しい順に並べた履歴は正しい並び。
|
|
7
7
|
* 向きが決まらない並び(上がりと下がりが同じ数)は何も言わない。逆らう一歩を言えるのは、日付が 4 つ以上の並びだけになる。
|
|
8
|
+
* 向きに沿って並ぶ日付が半分以下の並びは、日付でなく別のもの(名前、版)で並べた一覧として何も言わない。
|
|
8
9
|
*/
|
|
9
10
|
export type DatedPoint = { readonly offset: number; readonly value: string };
|
|
10
11
|
|
|
@@ -23,6 +24,19 @@ const samePrecision = (dated: readonly DatedPoint[]): boolean => PRECISIONS.some
|
|
|
23
24
|
/** 上がりが多ければ 1、下がりが多ければ -1、同じ数なら 0(向きを決めない)。 */
|
|
24
25
|
const majorityOf = (up: number, down: number): number => Math.sign(up - down);
|
|
25
26
|
|
|
27
|
+
/** 向きに沿って並べられる日付の最大の数(間を飛ばしてよい。等しい日付は向きに逆らわない)。 */
|
|
28
|
+
export const longestInOrder = (values: readonly string[], direction: number): number =>
|
|
29
|
+
Math.max(
|
|
30
|
+
0,
|
|
31
|
+
...values.reduce<number[]>((lengths, value, index) => {
|
|
32
|
+
const along = values.slice(0, index).map((earlier, at) => (Math.sign(value.localeCompare(earlier)) === -direction ? 0 : (lengths[at] ?? 0)));
|
|
33
|
+
return [...lengths, 1 + Math.max(0, ...along)];
|
|
34
|
+
}, []),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
/** 日付のうち向きに沿うものが過半を占める。ひとつふたつの書き間違いなら残りが揃うが、名前順の一覧は揃わない。 */
|
|
38
|
+
const mostlyInOrder = (values: readonly string[], direction: number): boolean => longestInOrder(values, direction) * 2 > values.length;
|
|
39
|
+
|
|
26
40
|
/** 多いほうの向きに逆らう一歩。後ろの項目の日付を指す。 */
|
|
27
41
|
const againstMajority = (dated: readonly DatedPoint[]): StructureIssue[] => {
|
|
28
42
|
const steps = dated
|
|
@@ -31,7 +45,8 @@ const againstMajority = (dated: readonly DatedPoint[]): StructureIssue[] => {
|
|
|
31
45
|
const up = steps.filter((step) => step.sign > 0).length;
|
|
32
46
|
const down = steps.filter((step) => step.sign < 0).length;
|
|
33
47
|
const majority = majorityOf(up, down);
|
|
34
|
-
|
|
48
|
+
const values = dated.map((point) => point.value);
|
|
49
|
+
if (majority === 0 || !mostlyInOrder(values, majority)) return [];
|
|
35
50
|
return steps
|
|
36
51
|
.filter((step) => step.sign === -majority)
|
|
37
52
|
.map((step) => ({ offset: step.point.offset, values: { date: step.point.value, previous: step.previous?.value ?? "" } }));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { StructureKind } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 見出しの行から拾う葉か。見出しは節の題で、「『特別警報』とは」は下の本文が定義する語を掲げているだけで、定義ではない。
|
|
5
|
+
* 定義として数えると、本文の「『特別警報』とは、…」が二度目の定義に見える。参照や数量は見出しにあっても読む。
|
|
6
|
+
*/
|
|
7
|
+
export const readsOnHeading = (kind: StructureKind): boolean => kind !== "definition";
|
package/src/structure/issues.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
import { listedTags } from "./listed-tags.ts";
|
|
3
|
+
import { namesAbsentUnit } from "./unit-word.ts";
|
|
2
4
|
|
|
3
5
|
// 木だけで決まる誤り。参照先が無い、番号が飛ぶ・重なる、同じ語を二度定義する。
|
|
4
6
|
// 意味の食い違いは判定しない。書いてあることから機械で決まるものだけを出す。
|
|
@@ -46,24 +48,37 @@ const addressesOf = (node: StructureNode): string[] =>
|
|
|
46
48
|
|
|
47
49
|
const keysOf = (node: StructureNode): string[] => addressesOf(node).flatMap((address) => [address, labelled(address, textOf(node, "label"))]);
|
|
48
50
|
|
|
51
|
+
/**
|
|
52
|
+
* 他の文書を指す参照か。citedTag("[HTTP-CACHING]")は、書き方だけでは差し込み欄の "[BUYER-1]" と見分けられないので、
|
|
53
|
+
* 文書がその語を一覧に載せているときだけ他の文書の名とみなす。
|
|
54
|
+
*/
|
|
55
|
+
const citesOtherDocument =
|
|
56
|
+
(listed: ReadonlySet<string>) =>
|
|
57
|
+
(node: StructureNode): boolean =>
|
|
58
|
+
node.attrs["document"] !== undefined || (node.attrs["citedTag"] !== undefined && listed.has(textOf(node, "citedTag")));
|
|
59
|
+
|
|
49
60
|
/**
|
|
50
61
|
* 参照の番地が木に無い。他の文書の名前が付いた参照(民法第709条、Section 9 of the Master Agreement)は引かない。
|
|
51
62
|
* 条を 1 つも持たない文書も見ない。他の文書を指しているだけかもしれない。
|
|
52
63
|
*/
|
|
53
|
-
export const danglingReferences = (tree: StructureNode): StructureIssue[] => {
|
|
64
|
+
export const danglingReferences = (tree: StructureNode, source: string): StructureIssue[] => {
|
|
54
65
|
const nodes = inDocumentOrder(tree);
|
|
55
66
|
// 参照は条を指す。条を一つも持たない文書(契約書に付ける承諾書のひな形など)の「契約書第6条」は、別の文書の条。
|
|
56
67
|
if (!nodes.some((node) => node.kind === "article")) return [];
|
|
68
|
+
const tagged = nodes.some((node) => node.attrs["citedTag"] !== undefined);
|
|
69
|
+
const citesOther = citesOtherDocument(tagged ? listedTags(source) : new Set());
|
|
57
70
|
const addresses = new Set(nodes.filter((node) => NUMBERED.includes(node.kind)).flatMap(keysOf));
|
|
58
71
|
// Section で組んだ法令が "Articles 13 to 21 of the UK GDPR" と別の文書の Article を名指ししていれば、名の無い "Article 6(3)" もそちら。
|
|
59
72
|
// 名指しがあれば、名の無い "Article 9" が書き間違いか向こうの条かは区別できないので黙る。名指しが無い文書では報告する。
|
|
60
73
|
const numbering = (node: StructureNode): unknown => node.attrs["numbering"];
|
|
61
74
|
const numberings = new Set(nodes.flatMap((node) => (node.kind === "article" && node.numbering !== undefined ? [node.numbering] : [])));
|
|
62
|
-
const citedElsewhere = new Set(nodes.filter((node) => node.kind === "reference" && node
|
|
75
|
+
const citedElsewhere = new Set(nodes.filter((node) => node.kind === "reference" && citesOther(node)).map(numbering));
|
|
63
76
|
const otherNumbering = (node: StructureNode): boolean =>
|
|
64
77
|
numberings.size > 0 && typeof numbering(node) === "string" && !numberings.has(String(numbering(node))) && citedElsewhere.has(numbering(node));
|
|
78
|
+
const articleLabels = nodes.filter((node) => node.kind === "article").map((node) => textOf(node, "label"));
|
|
65
79
|
return nodes
|
|
66
|
-
.filter((node) => node.kind === "reference" && node
|
|
80
|
+
.filter((node) => node.kind === "reference" && !citesOther(node) && !otherNumbering(node))
|
|
81
|
+
.filter((node) => !namesAbsentUnit(node, articleLabels))
|
|
67
82
|
.filter((node) => !resolves(node, addresses))
|
|
68
83
|
.map((node) => ({ offset: node.span.start, values: { label: textOf(node, "label"), target: textOf(node, "target") } }));
|
|
69
84
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// 角括弧の見出し語を、文書が一覧に載せているか。一覧の項目は行頭の [語] で始まり、その後ろは行末か、
|
|
2
|
+
// 2 つ以上の空白かタブで本文と離れる(ぶら下げの組み方)。行頭の [語] に空白 1 つで文が続くのは本文。
|
|
3
|
+
|
|
4
|
+
const LISTED = /^[ \t]*\[(?<tag>[^[\]\s]{1,60})\](?:[ \t]*\r?$|[ \t]{2,}|\t)/u;
|
|
5
|
+
|
|
6
|
+
/** 文書が一覧の項目として載せている角括弧の見出し語(括弧を除く)。 */
|
|
7
|
+
export const listedTags = (source: string): ReadonlySet<string> => new Set(source.split("\n").flatMap((line) => LISTED.exec(line)?.groups?.["tag"] ?? []));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** 大文字と小文字のある文字で、小文字の語。節の題(「3.1 Scope」「4.2 The Supplier shall」)は小文字で始まらない。 */
|
|
2
|
+
const LOWERCASE_WORD = /^\p{Ll}/u;
|
|
3
|
+
|
|
4
|
+
/** 文の終わり。ピリオドは後ろが空白か行末のとき(「3.x」「e-Tax.nta」の点は文を終えない)。題は文として終わらない。 */
|
|
5
|
+
const SENTENCE_END = /[.!?](?=\s|$)|[。!?]/u;
|
|
6
|
+
|
|
7
|
+
/** 行頭の通し番号の行。rest は番号の後ろ。 */
|
|
8
|
+
export type NumberedText = { readonly number: string; readonly rest: string; readonly isHeading: boolean };
|
|
9
|
+
|
|
10
|
+
type ContinuesSentence = (number: string, rest: string) => boolean;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 本文の行の「3.11.0 was released on 2024-10-17.」「3.11.0 を公開しました。」の番号は、文の主語や目的語で、節の番号ではない。
|
|
14
|
+
* 続きが文として終わり、しかも小文字の語で始まるか、言語パッケージが文の続き(日本語なら助詞)と読んだとき。
|
|
15
|
+
* 小文字の題(「3.1 overview」「4.2.1. about:blank」)と見出しの行は章番号。
|
|
16
|
+
*/
|
|
17
|
+
export const numberInSentence = (numbered: NumberedText, continuesSentence?: ContinuesSentence): boolean =>
|
|
18
|
+
!numbered.isHeading &&
|
|
19
|
+
SENTENCE_END.test(numbered.rest) &&
|
|
20
|
+
(LOWERCASE_WORD.test(numbered.rest) || continuesSentence?.(numbered.number, numbered.rest) === true);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 参照が単位の語(attrs.unitWord、日本語の「条」)で番号を名指していて、文書のどの条の番号にもその語が無い。
|
|
5
|
+
* 見出しに「1 目的」と番号を振った指針の「法第2条」は、指針の 2 ではなく、その語で条を数える別の文書(法律)の条。
|
|
6
|
+
* 単位の語を付けない言語・参照(英語の Section)は、ここでは決めない。
|
|
7
|
+
*/
|
|
8
|
+
export const namesAbsentUnit = (reference: StructureNode, articleLabels: readonly string[]): boolean => {
|
|
9
|
+
const unitWord = reference.attrs["unitWord"];
|
|
10
|
+
return typeof unitWord === "string" && unitWord !== "" && !articleLabels.some((label) => label.includes(unitWord));
|
|
11
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Mention } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 参照を読む行と、その後ろにつないだ次の行。
|
|
5
|
+
*
|
|
6
|
+
* 72 桁で折り返す RFC は「Section 16.3.2\n of [HTTP]」のように、参照と「どの文書の」を別の行に書く。行だけを読むと
|
|
7
|
+
* 自分の文書の 16.3.2 に見える。改行と字下げは読み手には空白一つなので、そうつないだ文字列を言語の読み手に渡す。
|
|
8
|
+
* 拾った参照は行の中にあるものだけを残す。次の行の参照は、次の行を読むときに拾う。位置は行の上のまま。
|
|
9
|
+
*/
|
|
10
|
+
export type WrappedLine = { readonly line: string; readonly text: string; readonly lineLength: number };
|
|
11
|
+
|
|
12
|
+
/** 見出しは次の行へ続かない。見出しの行か、次の行が無い・空なら、行だけ。 */
|
|
13
|
+
export const wrappedLine = (text: string, onHeading: boolean, next: string | undefined): WrappedLine => {
|
|
14
|
+
const tail = onHeading ? "" : (next?.trim() ?? "");
|
|
15
|
+
if (tail === "") return { line: text, text, lineLength: text.length };
|
|
16
|
+
const kept = text.trimEnd();
|
|
17
|
+
return { line: text, text: `${kept} ${tail}`, lineLength: kept.length };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** 行の中で終わる参照だけ。つないだ次の行に入り込んだもの(「Sections 1,\n 2」の 2)は捨てる。 */
|
|
21
|
+
export const onLine = (mentions: readonly Mention[], wrapped: WrappedLine): readonly Mention[] =>
|
|
22
|
+
mentions.filter((mention) => mention.end <= wrapped.lineLength);
|