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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-in-sentence.js","sourceRoot":"","sources":["../../src/structure/number-in-sentence.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC,qEAAqE;AACrE,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAO5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAsB,EAAE,iBAAqC,EAAW,EAAE,CACzG,CAAC,QAAQ,CAAC,SAAS;IACnB,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAChC,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,iBAAiB,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 参照が単位の語(attrs.unitWord、日本語の「条」)で番号を名指していて、文書のどの条の番号にもその語が無い。
|
|
4
|
+
* 見出しに「1 目的」と番号を振った指針の「法第2条」は、指針の 2 ではなく、その語で条を数える別の文書(法律)の条。
|
|
5
|
+
* 単位の語を付けない言語・参照(英語の Section)は、ここでは決めない。
|
|
6
|
+
*/
|
|
7
|
+
export declare const namesAbsentUnit: (reference: StructureNode, articleLabels: readonly string[]) => boolean;
|
|
8
|
+
//# sourceMappingURL=unit-word.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-word.d.ts","sourceRoot":"","sources":["../../src/structure/unit-word.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,WAAW,aAAa,EAAE,eAAe,SAAS,MAAM,EAAE,KAAG,OAG5F,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 参照が単位の語(attrs.unitWord、日本語の「条」)で番号を名指していて、文書のどの条の番号にもその語が無い。
|
|
3
|
+
* 見出しに「1 目的」と番号を振った指針の「法第2条」は、指針の 2 ではなく、その語で条を数える別の文書(法律)の条。
|
|
4
|
+
* 単位の語を付けない言語・参照(英語の Section)は、ここでは決めない。
|
|
5
|
+
*/
|
|
6
|
+
export const namesAbsentUnit = (reference, articleLabels) => {
|
|
7
|
+
const unitWord = reference.attrs["unitWord"];
|
|
8
|
+
return typeof unitWord === "string" && unitWord !== "" && !articleLabels.some((label) => label.includes(unitWord));
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=unit-word.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-word.js","sourceRoot":"","sources":["../../src/structure/unit-word.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,SAAwB,EAAE,aAAgC,EAAW,EAAE;IACrG,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7C,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrH,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Mention } from "../plugin.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 参照を読む行と、その後ろにつないだ次の行。
|
|
4
|
+
*
|
|
5
|
+
* 72 桁で折り返す RFC は「Section 16.3.2\n of [HTTP]」のように、参照と「どの文書の」を別の行に書く。行だけを読むと
|
|
6
|
+
* 自分の文書の 16.3.2 に見える。改行と字下げは読み手には空白一つなので、そうつないだ文字列を言語の読み手に渡す。
|
|
7
|
+
* 拾った参照は行の中にあるものだけを残す。次の行の参照は、次の行を読むときに拾う。位置は行の上のまま。
|
|
8
|
+
*/
|
|
9
|
+
export type WrappedLine = {
|
|
10
|
+
readonly line: string;
|
|
11
|
+
readonly text: string;
|
|
12
|
+
readonly lineLength: number;
|
|
13
|
+
};
|
|
14
|
+
/** 見出しは次の行へ続かない。見出しの行か、次の行が無い・空なら、行だけ。 */
|
|
15
|
+
export declare const wrappedLine: (text: string, onHeading: boolean, next: string | undefined) => WrappedLine;
|
|
16
|
+
/** 行の中で終わる参照だけ。つないだ次の行に入り込んだもの(「Sections 1,\n 2」の 2)は捨てる。 */
|
|
17
|
+
export declare const onLine: (mentions: readonly Mention[], wrapped: WrappedLine) => readonly Mention[];
|
|
18
|
+
//# sourceMappingURL=wrapped-tail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapped-tail.d.ts","sourceRoot":"","sources":["../../src/structure/wrapped-tail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAExG,0CAA0C;AAC1C,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,WAAW,OAAO,EAAE,MAAM,MAAM,GAAG,SAAS,KAAG,WAKxF,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,MAAM,GAAI,UAAU,SAAS,OAAO,EAAE,EAAE,SAAS,WAAW,KAAG,SAAS,OAAO,EAC3B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 見出しは次の行へ続かない。見出しの行か、次の行が無い・空なら、行だけ。 */
|
|
2
|
+
export const wrappedLine = (text, onHeading, next) => {
|
|
3
|
+
const tail = onHeading ? "" : (next?.trim() ?? "");
|
|
4
|
+
if (tail === "")
|
|
5
|
+
return { line: text, text, lineLength: text.length };
|
|
6
|
+
const kept = text.trimEnd();
|
|
7
|
+
return { line: text, text: `${kept} ${tail}`, lineLength: kept.length };
|
|
8
|
+
};
|
|
9
|
+
/** 行の中で終わる参照だけ。つないだ次の行に入り込んだもの(「Sections 1,\n 2」の 2)は捨てる。 */
|
|
10
|
+
export const onLine = (mentions, wrapped) => mentions.filter((mention) => mention.end <= wrapped.lineLength);
|
|
11
|
+
//# sourceMappingURL=wrapped-tail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapped-tail.js","sourceRoot":"","sources":["../../src/structure/wrapped-tail.ts"],"names":[],"mappings":"AAWA,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,SAAkB,EAAE,IAAwB,EAAe,EAAE;IACrG,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAC1E,CAAC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAA4B,EAAE,OAAoB,EAAsB,EAAE,CAC/F,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chaffjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Prose validation harness. Finds what is hard to read, and never rewrites it for you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chaff",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@anthropic-ai/sdk": "^0.125.0",
|
|
57
|
-
"@chaffjs/lang-en": "0.
|
|
58
|
-
"@chaffjs/lang-ja": "0.
|
|
57
|
+
"@chaffjs/lang-en": "0.13.0",
|
|
58
|
+
"@chaffjs/lang-ja": "0.14.0",
|
|
59
59
|
"mdast-util-from-markdown": "^2.0.3",
|
|
60
60
|
"mdast-util-frontmatter": "^2.0.1",
|
|
61
61
|
"mdast-util-gfm-table": "^2.0.0",
|
|
@@ -10,8 +10,8 @@ name:
|
|
|
10
10
|
en: Reference to a missing provision
|
|
11
11
|
|
|
12
12
|
why:
|
|
13
|
-
ja: 「第12条に定める」のような参照は、その条が文書に無ければ読み手を行き止まりにします。条を消したり番号を振り直したりしたときに、参照だけが古い番号のまま残ることがよくあります。chaff は文書を番地の付いた木にして(chaff tree
|
|
14
|
-
en: A reference such as "as set out in Section 12" leaves the reader at a dead end when that section is not in the document. It usually happens when a provision is deleted or renumbered and the reference keeps the old number. chaff builds the document's tree of addresses (chaff tree) and checks that each reference's address is in it.
|
|
13
|
+
ja: 「第12条に定める」のような参照は、その条が文書に無ければ読み手を行き止まりにします。条を消したり番号を振り直したりしたときに、参照だけが古い番号のまま残ることがよくあります。chaff は文書を番地の付いた木にして(chaff tree)、参照の番地が木にあるかを見ます。見出しに「1 目的」と番号を振っただけで「第N条」と書いた条の無い文書(ガイドラインや通達)の「法第2条」は、別の文書の条なので探しません。
|
|
14
|
+
en: A reference such as "as set out in Section 12" leaves the reader at a dead end when that section is not in the document. It usually happens when a provision is deleted or renumbered and the reference keeps the old number. chaff builds the document's tree of addresses (chaff tree) and checks that each reference's address is in it. A Japanese reference counted in 条 (法第2条) is not looked up in a document that numbers none of its provisions with 条, such as a guideline whose headings read "1 目的", because it points into another document.
|
|
15
15
|
|
|
16
16
|
message:
|
|
17
17
|
ja: 「{label}」(番地 {target})はこの文書にありません
|
package/rules/date-order.yaml
CHANGED
|
@@ -10,8 +10,8 @@ name:
|
|
|
10
10
|
en: A date out of order in a schedule
|
|
11
11
|
|
|
12
12
|
why:
|
|
13
|
-
ja:
|
|
14
|
-
en: In a list or a table of dates, such as an itinerary or milestones, one date earlier than the one before it makes the reader check whether it is a typo or a swapped row. The direction of the list (oldest or newest first) is taken from most of its steps, and only a date against it is pointed out.
|
|
13
|
+
ja: 旅程やマイルストーンのように日付を並べた箇条書きや表で、ひとつだけ前の日付より早い日付があると、書き間違いか順番の入れ替わりかを読み手が確かめることになります。並びが古い順か新しい順かは多いほうで決め、それに逆らう日付だけを指します。その向きに沿う日付が半分以下の並びは、名前や版の順に並べた一覧として扱い、何も言いません。
|
|
14
|
+
en: In a list or a table of dates, such as an itinerary or milestones, one date earlier than the one before it makes the reader check whether it is a typo or a swapped row. The direction of the list (oldest or newest first) is taken from most of its steps, and only a date against it is pointed out. A list where no more than half of the dates follow that direction is taken as sorted by something else, such as a name or a version, and nothing is said.
|
|
15
15
|
|
|
16
16
|
message:
|
|
17
17
|
ja: 「{date}」が、前後の日付の並びから外れています(前は「{previous}」)
|
|
@@ -10,8 +10,8 @@ name:
|
|
|
10
10
|
en: Term defined twice
|
|
11
11
|
|
|
12
12
|
why:
|
|
13
|
-
ja: 同じ語を二か所で定義すると、二つの定義が食い違っていないかを読み手が確かめなければなりません。長い契約書では、後から足した定義が先の定義と少しずれることがよくあります。中身が食い違っているかは機械では決まらないので、chaff
|
|
14
|
-
en: A term defined in two places makes the reader check whether the two definitions agree. In long contracts a definition added later often drifts from the first. Whether they conflict is not something a machine can decide, so chaff only points at the second one.
|
|
13
|
+
ja: 同じ語を二か所で定義すると、二つの定義が食い違っていないかを読み手が確かめなければなりません。長い契約書では、後から足した定義が先の定義と少しずれることがよくあります。中身が食い違っているかは機械では決まらないので、chaff は二度目の定義の場所だけを示します。見出し(「『X』とは」)は語を掲げるだけなので、定義として数えません。
|
|
14
|
+
en: A term defined in two places makes the reader check whether the two definitions agree. In long contracts a definition added later often drifts from the first. Whether they conflict is not something a machine can decide, so chaff only points at the second one. A heading that names the term is not counted as a definition.
|
|
15
15
|
|
|
16
16
|
message:
|
|
17
17
|
ja: 「{term}」は {first} 行目でも定義されています
|
package/rules/latin-spacing.yaml
CHANGED
|
@@ -6,14 +6,16 @@ languages: [ja]
|
|
|
6
6
|
severity: warning
|
|
7
7
|
# 番号・識別子として書かれた数を見分けるのに、数の後ろの語の品詞を使う。無ければ全部数える。
|
|
8
8
|
uses: [pos]
|
|
9
|
+
# 番地(千代田区紀尾井町1-3)を、都道府県までの地名の後ろの範囲(東京都2-3 営業日)と分ける。
|
|
10
|
+
extra_word_lists: [prefecture-unit]
|
|
9
11
|
|
|
10
12
|
name:
|
|
11
13
|
ja: 英数字の前後の空白がそろっていない
|
|
12
14
|
en: Spacing around Latin text is inconsistent
|
|
13
15
|
|
|
14
16
|
why:
|
|
15
|
-
ja: 日本語と英字・数字のあいだを空けるか詰めるかは、どちらでも読めます。困るのは一つの文書の中で混ざることで、読み手には違いに意味があるように見えます。chaff はどちらが正しいかを決めず、文書の中で少ないほうを指摘します。英字と、数字の前、数字の後ろは別々に数えます。「を 3回」のように、数字の前は空けて助数詞とは詰める書き方がふつうにあるからです。「3GBの」のように数字に続く単位は、英字ではなく数字の側として数えます。逆に「H30 等」「EC2 で」「Phase 1 は」のように英字で始まって数字で終わる名前は、英字の側として数えます。「073-489-5909」「2026-06-02」のような番号は数量ではないので数えません。題や注の番号として書かれた数(「3.1 リサーチの原則」の節番号、※1
|
|
16
|
-
en: Whether to put a space between Japanese and Latin letters or digits is a choice either way. What reads badly is mixing both in one document, which suggests the difference means something. chaff does not decide which is right; it points at whichever the document uses less. Letters, the space before a digit and the space after one are counted separately, since spacing before a number but not before its counter is common. A unit after a number (3GB) counts with the number; a name that starts with a letter and ends in a digit (H30, EC2, Phase 1) counts with the letters. A code such as a phone number or a date (073-489-5909, 2026-06-02) is not a quantity and is not counted. Neither is a number written as the label of a title or a note (a section number such as 3.1 before its title, a note number after
|
|
17
|
+
ja: 日本語と英字・数字のあいだを空けるか詰めるかは、どちらでも読めます。困るのは一つの文書の中で混ざることで、読み手には違いに意味があるように見えます。chaff はどちらが正しいかを決めず、文書の中で少ないほうを指摘します。英字と、数字の前、数字の後ろは別々に数えます。「を 3回」のように、数字の前は空けて助数詞とは詰める書き方がふつうにあるからです。「3GBの」のように数字に続く単位は、英字ではなく数字の側として数えます。逆に「H30 等」「EC2 で」「Phase 1 は」のように英字で始まって数字で終わる名前は、英字の側として数えます。「073-489-5909」「2026-06-02」のような番号は数量ではないので数えません。題や注の番号として書かれた数(「3.1 リサーチの原則」の節番号、※1 の注番号、行の頭に続き番号で並べた注の番号)、0 で始まる組を含む番号(102-0094)、〒の後ろの郵便番号(〒100-8916)、市・区・町まで下りた地名のすぐ後ろの番地(千代田区紀尾井町1-3)も、後ろの空白が番号と題・項目の区切りなので数えません。鉤括弧(「」『』)で引いた題名や発言の中も、空け方は引いた元のものなので数えません。
|
|
18
|
+
en: Whether to put a space between Japanese and Latin letters or digits is a choice either way. What reads badly is mixing both in one document, which suggests the difference means something. chaff does not decide which is right; it points at whichever the document uses less. Letters, the space before a digit and the space after one are counted separately, since spacing before a number but not before its counter is common. A unit after a number (3GB) counts with the number; a name that starts with a letter and ends in a digit (H30, EC2, Phase 1) counts with the letters. A code such as a phone number or a date (073-489-5909, 2026-06-02) is not a quantity and is not counted. Neither is a number written as the label of a title or a note (a section number such as 3.1 before its title, a note number after ※, the numbers of notes listed one per line in sequence), a code with a part starting with 0 (102-0094), a postal code after 〒 (〒100-8916), or a hyphenated address number right after a city, ward or town (千代田区紀尾井町1-3), since the space after it separates the label from its title or the next item. Nor is the spacing inside a title or a quotation in 「」 or 『』, which is the source's, not the writer's.
|
|
17
19
|
|
|
18
20
|
message:
|
|
19
21
|
ja: "日本語と{kind}のあいだを{style}(この文書はふつう{usual}。{of} 箇所のうち {count} 箇所が違う)"
|
|
@@ -2,7 +2,7 @@ id: max-kanji-continuous
|
|
|
2
2
|
layer: L3
|
|
3
3
|
status: experimental
|
|
4
4
|
how_to_find: kanji-run
|
|
5
|
-
#
|
|
5
|
+
# 品詞があれば、住所(地名と数だけでできた連なり)と 1 つの名前(辞書の固有名詞 1 語、人の姓と名)を数えない。無くても文字だけで動く。
|
|
6
6
|
uses: [pos]
|
|
7
7
|
# 住所の先頭にしか来ない単位(都道府県)。地名の後ろに付けば、割られた町名ではなく地名の並び。
|
|
8
8
|
extra_word_lists: [prefecture-unit]
|
|
@@ -12,8 +12,8 @@ name:
|
|
|
12
12
|
en: Nested repeated particle
|
|
13
13
|
|
|
14
14
|
why:
|
|
15
|
-
ja:
|
|
16
|
-
en: When the same particle repeats without a break, the reader cannot tell which phrase attaches to which. Items separated by punctuation are not counted.
|
|
15
|
+
ja: 「弊社の新製品の販売の計画」のように同じ助詞が読点を挟まずに続くと、どれがどれに係るのか読み手が追えなくなります。読点で区切られた並列は数えていません。鉤括弧で引いた題名や発言(「食品中のウイルスの制御のための…」)の中は書き手が言い換えられないので数えず、引いたもの全体を一つの名詞として読みます。
|
|
16
|
+
en: When the same particle repeats without a break, the reader cannot tell which phrase attaches to which. Items separated by punctuation are not counted. Nor are particles inside a title or a quotation in 「」 or 『』, which the writer cannot rephrase; the quotation as a whole is read as one noun.
|
|
17
17
|
|
|
18
18
|
message:
|
|
19
19
|
ja: 「{word}」が読点を挟まずに {count} 回続いています({limit} 回まで)
|
|
@@ -10,8 +10,8 @@ name:
|
|
|
10
10
|
en: Too many items joined by middle dots
|
|
11
11
|
|
|
12
12
|
why:
|
|
13
|
-
ja: 中黒の並列は 1 組なら読めますが、1 文に何組も入ると、どの項目がどの組に属するのか追えなくなります。実文書では 1 文 4
|
|
14
|
-
en: One run of middle dots reads fine. Several runs in one sentence make it impossible to tell which item belongs to which group.
|
|
13
|
+
ja: 中黒の並列は 1 組なら読めますが、1 文に何組も入ると、どの項目がどの組に属するのか追えなくなります。実文書では 1 文 4 個までは普通に読めていました。行頭の「・」は箇条書きの印なので数えません。
|
|
14
|
+
en: One run of middle dots reads fine. Several runs in one sentence make it impossible to tell which item belongs to which group. A 「・」 that opens a line is a bullet and is not counted.
|
|
15
15
|
|
|
16
16
|
message:
|
|
17
17
|
ja: この文に中黒が {count} 個あります({limit} 個まで)
|
|
@@ -10,8 +10,8 @@ name:
|
|
|
10
10
|
en: Heading capitalisation is inconsistent
|
|
11
11
|
|
|
12
12
|
why:
|
|
13
|
-
ja: Title Case と sentence case のどちらが正しいかは決めません。1
|
|
14
|
-
en: Neither Title Case nor sentence case is wrong. Mixed within one document, the headings look like they change level.
|
|
13
|
+
ja: Title Case と sentence case のどちらが正しいかは決めません。1 つの文書で混ざっていると、見出しの階層が変わったように見えます。文書の題名(先頭にある深さ 1 の見出しが 1 つだけのとき)は名前なので比べません。節の見出しが同数に割れたときだけ、題名の流儀に合わせます。
|
|
14
|
+
en: Neither Title Case nor sentence case is wrong. Mixed within one document, the headings look like they change level. The document's title (a single top-level heading that opens it) is a name and is not compared; when the section headings split evenly, the title's style decides.
|
|
15
15
|
|
|
16
16
|
message:
|
|
17
17
|
ja: この見出しだけ他と大文字化の流儀が違います(文書の中で {count} 個)
|
|
@@ -3,7 +3,21 @@ layer: L1
|
|
|
3
3
|
status: experimental
|
|
4
4
|
how_to_find: undefined-acronym
|
|
5
5
|
word_list: common-acronym
|
|
6
|
-
extra_word_lists:
|
|
6
|
+
extra_word_lists:
|
|
7
|
+
[
|
|
8
|
+
definition-marker,
|
|
9
|
+
definition-verb,
|
|
10
|
+
meridiem,
|
|
11
|
+
time-zone,
|
|
12
|
+
currency-code,
|
|
13
|
+
us-state-code,
|
|
14
|
+
emphasis-word,
|
|
15
|
+
numbered-division,
|
|
16
|
+
honorific,
|
|
17
|
+
date-time-unit,
|
|
18
|
+
http-method,
|
|
19
|
+
]
|
|
20
|
+
uses: [pos]
|
|
7
21
|
severity: info
|
|
8
22
|
|
|
9
23
|
name:
|
package/src/address-chain.ts
CHANGED
|
@@ -102,12 +102,15 @@ export const addressSpans = (text: string, profile: DocumentProfile | undefined)
|
|
|
102
102
|
return spans;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* 番地を同じ長さの空白にする。空白が連なりを切るので、番地は数えられず、前後は別の連なりになる。
|
|
107
|
+
* 長さを保つので、覆った後の位置は元の文字列の位置のまま。
|
|
108
|
+
*/
|
|
106
109
|
export const maskAddresses = (text: string, profile: DocumentProfile | undefined): string => {
|
|
107
110
|
const spans = addressSpans(text, profile);
|
|
108
111
|
if (spans.length === 0) return text;
|
|
109
112
|
const pieces: string[] = [];
|
|
110
|
-
spans.forEach((span, index) => pieces.push(text.slice(spans[index - 1]?.end ?? 0, span.start), " "));
|
|
113
|
+
spans.forEach((span, index) => pieces.push(text.slice(spans[index - 1]?.end ?? 0, span.start), " ".repeat(span.end - span.start)));
|
|
111
114
|
pieces.push(text.slice(spans.at(-1)?.end ?? 0));
|
|
112
115
|
return pieces.join("");
|
|
113
116
|
};
|
package/src/cli-text.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// What the command line says, in Japanese and English. Per-file text follows the file's language; the rest
|
|
2
2
|
// follows hostLanguage (chaff.yaml's language, else the terminal's locale).
|
|
3
3
|
import type { Texts } from "./ui.ts";
|
|
4
|
+
import type { GenreSetting } from "./genre-check.ts";
|
|
4
5
|
|
|
5
6
|
/** Where a file's genre came from, as the header names it. */
|
|
6
7
|
export type GenreSource = "--genre" | "by_path" | "config" | "default" | "front-matter" | "path" | "content";
|
|
@@ -81,7 +82,9 @@ export type CliText = {
|
|
|
81
82
|
readonly noMarkdown: (targets: string) => string;
|
|
82
83
|
readonly noMarkdownHere: string;
|
|
83
84
|
readonly noAdapter: (language: string) => string;
|
|
84
|
-
readonly unknownGenre: (genre: string) => string;
|
|
85
|
+
readonly unknownGenre: (genre: string, where: string, known: readonly string[]) => string;
|
|
86
|
+
readonly genreWhere: (where: GenreSetting, files: readonly string[]) => string;
|
|
87
|
+
readonly unreadFrontMatterGenre: (path: string, genre: string, known: readonly string[]) => string;
|
|
85
88
|
readonly unknownRule: (id: string) => string;
|
|
86
89
|
readonly unknownRuleWithList: (id: string, list: string) => string;
|
|
87
90
|
readonly unnamed: string;
|
|
@@ -115,7 +118,14 @@ export const CLI_TEXT: Texts<CliText> = {
|
|
|
115
118
|
noMarkdown: (targets) => `Markdown が 1 つも見つかりませんでした: ${targets}`,
|
|
116
119
|
noMarkdownHere: "Markdown が 1 つも見つかりませんでした。",
|
|
117
120
|
noAdapter: (language) => `言語 "${language}" のアダプタがありません。`,
|
|
118
|
-
unknownGenre: (genre) =>
|
|
121
|
+
unknownGenre: (genre, where, known) =>
|
|
122
|
+
`ジャンル "${genre}" はありません(${where})。使えるのは ${known.join("、")} です。npx chaff genres で一覧が出ます。`,
|
|
123
|
+
genreWhere: (where, files) => {
|
|
124
|
+
if (where === "config") return "chaff.yaml の genre";
|
|
125
|
+
return where === "by_path" ? `chaff.yaml の by_path、files: ${files.join(", ")}` : "--genre";
|
|
126
|
+
},
|
|
127
|
+
unreadFrontMatterGenre: (path, genre, known) =>
|
|
128
|
+
`${path}: front matter の genre "${genre}" はジャンルではないので読みませんでした。使えるのは ${known.join("、")} です。`,
|
|
119
129
|
unknownRule: (id) => `${id} というルールはありません。npx chaff rules --json で一覧が出ます。`,
|
|
120
130
|
unknownRuleWithList: (id, list) => `${id} というルールはありません。\n一覧:\n${list}`,
|
|
121
131
|
unnamed: "(名前なし)",
|
|
@@ -159,7 +169,13 @@ export const CLI_TEXT: Texts<CliText> = {
|
|
|
159
169
|
noMarkdown: (targets) => `No Markdown files found: ${targets}`,
|
|
160
170
|
noMarkdownHere: "No Markdown files found.",
|
|
161
171
|
noAdapter: (language) => `No language package for "${language}".`,
|
|
162
|
-
unknownGenre: (genre) => `There is no genre "${genre}". npx chaff genres lists them.`,
|
|
172
|
+
unknownGenre: (genre, where, known) => `There is no genre "${genre}" (${where}). The genres are ${known.join(", ")}. npx chaff genres lists them.`,
|
|
173
|
+
genreWhere: (where, files) => {
|
|
174
|
+
if (where === "config") return "genre in chaff.yaml";
|
|
175
|
+
return where === "by_path" ? `by_path in chaff.yaml, files: ${files.join(", ")}` : "--genre";
|
|
176
|
+
},
|
|
177
|
+
unreadFrontMatterGenre: (path, genre, known) =>
|
|
178
|
+
`${path}: the front matter's genre "${genre}" is not a genre, so it was not used. The genres are ${known.join(", ")}.`,
|
|
163
179
|
unknownRule: (id) => `There is no rule named ${id}. npx chaff rules --json lists them.`,
|
|
164
180
|
unknownRuleWithList: (id, list) => `There is no rule named ${id}.\nRules:\n${list}`,
|
|
165
181
|
unnamed: "(no name)",
|
package/src/cli.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { applyByPath } from "./config/by-path.ts";
|
|
|
7
7
|
import { applyLevel } from "./config/write.ts";
|
|
8
8
|
import { buildDocument, teamRules } from "./document.ts";
|
|
9
9
|
import { guessLanguage } from "./detect.ts";
|
|
10
|
+
import { plainSource } from "./plain-source.ts";
|
|
10
11
|
import { collectTargets } from "./files.ts";
|
|
11
12
|
import { BASELINE_FILE, fingerprint, readBaseline, splitByBaseline, writeBaseline } from "./baseline.ts";
|
|
12
13
|
import { applySuppressions } from "./stet.ts";
|
|
@@ -14,8 +15,10 @@ import { renderSuppressions, type PerFile } from "./render/suppressions.ts";
|
|
|
14
15
|
import { clock, describeChange, snapshotOf, watchPaths, type Snapshot } from "./watch.ts";
|
|
15
16
|
import { runEval } from "./commands/eval.ts";
|
|
16
17
|
import { runTest } from "./commands/test.ts";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
18
|
+
import { GENRES } from "./genre.ts";
|
|
19
|
+
import { unknownGenres, writtenGenres } from "./genre-check.ts";
|
|
20
|
+
import { resolveGenre } from "./resolve-genre.ts";
|
|
21
|
+
import { runInit } from "./init.ts";
|
|
19
22
|
import { targetsOf } from "./cli-args.ts";
|
|
20
23
|
import { loadRules } from "./rule-load.ts";
|
|
21
24
|
import { renderCompact } from "./render/compact.ts";
|
|
@@ -42,15 +45,12 @@ const hostText = (config: Config): CliText => CLI_TEXT[hostLanguage(config.langu
|
|
|
42
45
|
|
|
43
46
|
const readConfig = (): Config => (existsSync(join(process.cwd(), CONFIG_FILE)) ? loadConfig(join(process.cwd(), CONFIG_FILE)) : EMPTY);
|
|
44
47
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (config.genre !== undefined) return { genre: config.genre, from: "config" };
|
|
52
|
-
const guess = guessGenre(path, source, frontMatterGenre(source));
|
|
53
|
-
return guess === undefined ? { genre: "blog/tech", from: "default" } : { genre: guess.genre, from: guess.from };
|
|
48
|
+
const genreProblems = (command: string, argv: readonly string[]): string[] => {
|
|
49
|
+
const config = readConfig();
|
|
50
|
+
const text = hostText(config);
|
|
51
|
+
return unknownGenres(writtenGenres(command, flag(argv, "--genre"), config), GENRES).map((entry) =>
|
|
52
|
+
text.unknownGenre(entry.genre, text.genreWhere(entry.where, entry.files), GENRES),
|
|
53
|
+
);
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
/** resolveGenre with this run's --genre, for the commands that take it as a dependency. */
|
|
@@ -97,10 +97,11 @@ const headerFor = (path: string, genre: string, from: GenreSource, language: str
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
const inspect = async (path: string, config: Config, argv: readonly string[]): Promise<Inspected> => {
|
|
100
|
-
const source = await readFile(path, "utf8");
|
|
100
|
+
const source = plainSource(await readFile(path, "utf8"));
|
|
101
101
|
const language = applyByPath(config.byPath, config.baseDir, path).language ?? config.language ?? guessLanguage(source).language;
|
|
102
102
|
const adapter = await loadAdapter(language);
|
|
103
|
-
const { genre, from } = resolveGenre(path, source, config, flag(argv, "--genre"));
|
|
103
|
+
const { genre, from, unread } = resolveGenre(path, source, config, flag(argv, "--genre"));
|
|
104
|
+
if (unread !== undefined) console.error(`chaff: ${CLI_TEXT[uiLanguageOf(language)].unreadFrontMatterGenre(path, unread, GENRES)}`);
|
|
104
105
|
const rules = loadRules(language);
|
|
105
106
|
const experimental = config.experimental || argv.includes("--experimental");
|
|
106
107
|
await adapter.prepare?.(neededBy(rules, config.rules, experimental, genre, language));
|
|
@@ -292,7 +293,10 @@ const HANDLERS: Readonly<Record<string, Handler>> = {
|
|
|
292
293
|
genres: showGenres,
|
|
293
294
|
rules: showRules,
|
|
294
295
|
explain: (argv) => explain(argv[1]),
|
|
295
|
-
eval: (argv) =>
|
|
296
|
+
eval: (argv) => {
|
|
297
|
+
const config = readConfig();
|
|
298
|
+
return runEval(positional(argv), argv, { config, resolveGenre: genreFrom(argv), flag, ui: hostLanguage(config.language, process.env) });
|
|
299
|
+
},
|
|
296
300
|
tree: (argv) => runTree(treeTargets(argv), argv, treeContext()),
|
|
297
301
|
cite: (argv) => runCite(citeTargets(argv), argv, treeContext()),
|
|
298
302
|
test: (argv) => runTest(positional(argv), argv, { config: readConfig(), resolveGenre: genreFrom(argv), inspect }),
|
|
@@ -332,11 +336,10 @@ export const main = async (argv: readonly string[]): Promise<number> => {
|
|
|
332
336
|
console.log(VERSION_LINES.join("\n"));
|
|
333
337
|
return 0;
|
|
334
338
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
339
|
+
// 知らないジャンルでは、どの rule も当たらず、動かなかった rule も並ばない。「指摘なし」が素通りに見えるので、何かする前に止める。
|
|
340
|
+
const problems = genreProblems(first, argv);
|
|
341
|
+
problems.forEach((problem) => console.error(problem));
|
|
342
|
+
if (problems.length > 0) return 1;
|
|
340
343
|
const handler = HANDLERS[first];
|
|
341
344
|
if (handler !== undefined) return handler(argv);
|
|
342
345
|
const targets = targetsOf(first === "lint" ? argv.slice(1) : argv);
|
package/src/commands/eval.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainSource } from "../plain-source.ts";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { loadAdapter } from "../adapter-load.ts";
|
|
3
4
|
import { applyByPath } from "../config/by-path.ts";
|
|
@@ -10,28 +11,47 @@ import { renderEval } from "../render/eval.ts";
|
|
|
10
11
|
import { neededBy } from "../run.ts";
|
|
11
12
|
import type { Config } from "../config/load.ts";
|
|
12
13
|
import { profileFor } from "../profile/for-file.ts";
|
|
14
|
+
import { CLI_TEXT } from "../cli-text.ts";
|
|
15
|
+
import { uiLanguageOf, type Texts, type UiLanguage } from "../ui.ts";
|
|
16
|
+
|
|
17
|
+
const TEXT: Texts<{
|
|
18
|
+
readonly mixed: (mixes: string) => string;
|
|
19
|
+
readonly unknownRule: (id: string) => string;
|
|
20
|
+
}> = {
|
|
21
|
+
ja: {
|
|
22
|
+
mixed: (mixes) => `言語かジャンルが混ざっています: ${mixes}\n1 つに絞って測ってください(例: npx chaff eval examples/blog-ja/)。`,
|
|
23
|
+
unknownRule: (id) => `${id} という rule はありません。`,
|
|
24
|
+
},
|
|
25
|
+
en: {
|
|
26
|
+
mixed: (mixes) => `Languages or genres are mixed: ${mixes}\nMeasure one at a time (for example npx chaff eval examples/blog-en/).`,
|
|
27
|
+
unknownRule: (id) => `There is no rule named ${id}.`,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
13
30
|
|
|
14
31
|
export type Context = {
|
|
15
32
|
readonly config: Config;
|
|
16
33
|
readonly resolveGenre: (path: string, source: string, config: Config) => { genre: string; from: string };
|
|
17
34
|
readonly flag: (argv: readonly string[], name: string) => string | undefined;
|
|
35
|
+
/** The language of what is not about the documents measured: chaff.yaml's language, else the locale. */
|
|
36
|
+
readonly ui: UiLanguage;
|
|
18
37
|
};
|
|
19
38
|
|
|
20
39
|
/**
|
|
21
40
|
* 閾値の較正。手元の文書を「人間の良い文書」として扱い、どの閾値なら
|
|
22
41
|
* 誤検知が目標を下回るかを測る。書き換えはしない。
|
|
42
|
+
* 測った結果は文書の言語で出す(混ざっていれば測らないので、言語は 1 つ)。断りは ui の言語。
|
|
23
43
|
*/
|
|
24
44
|
export const runEval = async (targets: readonly string[], argv: readonly string[], context: Context): Promise<number> => {
|
|
25
45
|
const paths = collectTargets(targets.length > 0 ? targets : ["."]);
|
|
26
46
|
if (paths.length === 0) {
|
|
27
|
-
console.error(
|
|
47
|
+
console.error(CLI_TEXT[context.ui].noMarkdown(targets.join(", ")));
|
|
28
48
|
return 1;
|
|
29
49
|
}
|
|
30
|
-
const { config, resolveGenre, flag } = context;
|
|
50
|
+
const { config, resolveGenre, flag, ui } = context;
|
|
31
51
|
const only = flag(argv, "--rule");
|
|
32
52
|
const docs = await Promise.all(
|
|
33
53
|
paths.map(async (path) => {
|
|
34
|
-
const source = await readFile(path, "utf8");
|
|
54
|
+
const source = plainSource(await readFile(path, "utf8"));
|
|
35
55
|
const language = applyByPath(config.byPath, config.baseDir, path).language ?? config.language ?? guessLanguage(source).language;
|
|
36
56
|
const adapter = await loadAdapter(language);
|
|
37
57
|
const { genre } = resolveGenre(path, source, config);
|
|
@@ -44,12 +64,12 @@ export const runEval = async (targets: readonly string[], argv: readonly string[
|
|
|
44
64
|
// 言語とジャンルが混ざった corpus は測れない。閾値の単位が違うため。
|
|
45
65
|
const mixed = new Set(docs.map((entry) => `${entry.language}/${entry.genre}`));
|
|
46
66
|
if (mixed.size > 1) {
|
|
47
|
-
console.error(
|
|
67
|
+
console.error(TEXT[ui].mixed([...mixed].join(", ")));
|
|
48
68
|
return 1;
|
|
49
69
|
}
|
|
50
70
|
const rules = loadRules(language).filter((rule) => only === undefined || rule.id === only);
|
|
51
71
|
if (rules.length === 0) {
|
|
52
|
-
console.error(
|
|
72
|
+
console.error(TEXT[ui].unknownRule(only ?? CLI_TEXT[ui].unnamed));
|
|
53
73
|
return 1;
|
|
54
74
|
}
|
|
55
75
|
console.log(
|
|
@@ -63,6 +83,7 @@ export const runEval = async (targets: readonly string[], argv: readonly string[
|
|
|
63
83
|
),
|
|
64
84
|
docs.length,
|
|
65
85
|
paths.length,
|
|
86
|
+
uiLanguageOf(language),
|
|
66
87
|
),
|
|
67
88
|
);
|
|
68
89
|
return 0;
|
package/src/commands/feedback.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainSource } from "../plain-source.ts";
|
|
1
2
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { basename, join } from "node:path";
|
|
3
4
|
import type { Finding, RuleDefinition } from "../plugin.ts";
|
|
@@ -178,7 +179,7 @@ export const runFeedback = async (targets: readonly string[], argv: readonly str
|
|
|
178
179
|
console.error(text.notFound(request.path));
|
|
179
180
|
return 1;
|
|
180
181
|
}
|
|
181
|
-
const source = readFileSync(request.path, "utf8");
|
|
182
|
+
const source = plainSource(readFileSync(request.path, "utf8"));
|
|
182
183
|
const checked = await context.check(request.path);
|
|
183
184
|
const picked = pick(request, checked, source.split("\n").length, context.ui);
|
|
184
185
|
if ("error" in picked) {
|
package/src/commands/test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainSource } from "../plain-source.ts";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { loadAdapter } from "../adapter-load.ts";
|
|
@@ -33,7 +34,7 @@ const judgeAll = async (
|
|
|
33
34
|
): Promise<Judged[]> =>
|
|
34
35
|
Promise.all(
|
|
35
36
|
paths.map(async (path) => {
|
|
36
|
-
const source = await readFile(path, "utf8");
|
|
37
|
+
const source = plainSource(await readFile(path, "utf8"));
|
|
37
38
|
const language = applyByPath(config.byPath, config.baseDir, path).language ?? config.language ?? guessLanguage(source).language;
|
|
38
39
|
const adapter = await loadAdapter(language);
|
|
39
40
|
const doc = buildDocument(path, source, adapter, teamRules(config), profileFor(config, path, source, language));
|
|
@@ -53,7 +54,7 @@ const dryRun = async (
|
|
|
53
54
|
): Promise<void> => {
|
|
54
55
|
const plans = await Promise.all(
|
|
55
56
|
paths.map(async (path) => {
|
|
56
|
-
const source = await readFile(path, "utf8");
|
|
57
|
+
const source = plainSource(await readFile(path, "utf8"));
|
|
57
58
|
const language = applyByPath(config.byPath, config.baseDir, path).language ?? config.language ?? guessLanguage(source).language;
|
|
58
59
|
const adapter = await loadAdapter(language);
|
|
59
60
|
const doc = buildDocument(path, source, adapter, teamRules(config), profileFor(config, path, source, language));
|
package/src/commands/tree.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainSource } from "../plain-source.ts";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { loadAdapter } from "../adapter-load.ts";
|
|
3
4
|
import { applyByPath } from "../config/by-path.ts";
|
|
@@ -46,7 +47,7 @@ export const treeTargets = (argv: readonly string[]): string[] =>
|
|
|
46
47
|
|
|
47
48
|
export const readSource = async (path: string, context: TreeContext): Promise<string | undefined> => {
|
|
48
49
|
try {
|
|
49
|
-
return await readFile(path, "utf8");
|
|
50
|
+
return plainSource(await readFile(path, "utf8"));
|
|
50
51
|
} catch (err) {
|
|
51
52
|
console.error(treeText(context).unreadable(path, err instanceof Error ? err.message : String(err)));
|
|
52
53
|
return undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** - で繋いだ略語(RT-PCR)の部品。繋いでいなければ、その語だけ。 */
|
|
2
|
+
export const partsOf = (acronym: string): string[] => acronym.split("-");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 略語が説明済みか。- で繋いだ語は、繋いだ形のまま説明されているか、部品がどれも説明済みなら説明済み。
|
|
6
|
+
* US-EU は US も EU も通じるので指摘しない。RT-PCR は RT がどこにも説明されていないので、繋いだ形で指摘する。
|
|
7
|
+
*/
|
|
8
|
+
export const isExplained = (acronym: string, explainedAlone: (word: string) => boolean): boolean =>
|
|
9
|
+
explainedAlone(acronym) || partsOf(acronym).every(explainedAlone);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { escapeRegExp } from "../orthography.ts";
|
|
2
|
+
import { ROMAN_NUMERAL } from "./roman-numeral.ts";
|
|
3
|
+
import { citationKeySpans } from "./citation-key.ts";
|
|
4
|
+
import { dottedNameSpans } from "./dotted-name.ts";
|
|
5
|
+
import { loneNumeralSpans, nameNumeralSpans } from "./name-numeral.ts";
|
|
6
|
+
import { placeholderSpans } from "./placeholder.ts";
|
|
7
|
+
import { seriesLabelSpans } from "./series-label.ts";
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* 大文字の語が略語ではなく、決まった書き方の一部として読める所(3:30 PM、1pm ET、USD 1,000、Kansas City, MO 64108)。
|
|
@@ -15,6 +21,12 @@ export type NotationWords = {
|
|
|
15
21
|
readonly currencies: readonly string[];
|
|
16
22
|
readonly usStates: readonly string[];
|
|
17
23
|
readonly emphasis: readonly string[];
|
|
24
|
+
/** 番号を後ろに書く、文書の区切りの名前(Part、Section、Title)。 */
|
|
25
|
+
readonly divisions: readonly string[];
|
|
26
|
+
/** 速記録が大文字で書く発言者の姓の前に置く敬称(Mr.、Mrs.、Madam)。 */
|
|
27
|
+
readonly honorifics: readonly string[];
|
|
28
|
+
/** 日付・時刻の数字の後ろに書く単位(年、月、日、時、分)。その前の同じ大文字の繰り返し(YY年)は書式の置き場所。 */
|
|
29
|
+
readonly dateTimeUnits: readonly string[];
|
|
18
30
|
};
|
|
19
31
|
|
|
20
32
|
// 空の語彙表は「その書き方が無い」。空の選択肢 (?:) は至る所で空文字に当たるので、何にも当たらない形にする。
|
|
@@ -28,6 +40,15 @@ const ANY_MERIDIEM = String.raw`[AaPp]\.?[Mm]\.?`;
|
|
|
28
40
|
/** 桁区切りは 3 桁ずつ揃っているときだけ金額と読む。「item 1, USD」の 1, は金額ではない。 */
|
|
29
41
|
const AMOUNT = String.raw`(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?`;
|
|
30
42
|
|
|
43
|
+
/**
|
|
44
|
+
* 区切りの名前のすぐ後ろのローマ数字は番号(Part II、Section VIII、TITLE IV)。名前は語彙表の書き方か、全部大文字。
|
|
45
|
+
* CD や CI のようにローマ数字としても読める略語は、この位置でなければ略語のまま数える。
|
|
46
|
+
*/
|
|
47
|
+
const divisionOf = (words: readonly string[]): string => oneOf(words.flatMap((word) => [word, word.toUpperCase()]));
|
|
48
|
+
|
|
49
|
+
/** 敬称のすぐ後ろの大文字の姓(Mr. HAWLEY、Dr. O'NEIL)。速記録は発言者をこう書き、略語ではない。 */
|
|
50
|
+
const SURNAME_IN_CAPITALS = String.raw`[A-Z]+(?:['’-][A-Z]+)*(?![\p{L}\p{N}_])`;
|
|
51
|
+
|
|
31
52
|
// 強調の記号は空白に置き換えてある(**3:30** PM)ので、部品の間の空白は数を問わない。
|
|
32
53
|
const patternsOf = (words: NotationWords): readonly RegExp[] => [
|
|
33
54
|
new RegExp(String.raw`${CLOCK_12}\s*${oneOf(words.meridiem)}`, "gu"),
|
|
@@ -36,6 +57,8 @@ const patternsOf = (words: NotationWords): readonly RegExp[] => [
|
|
|
36
57
|
new RegExp(String.raw`(?<![\w.,])${AMOUNT}\s*${oneOf(words.currencies)}`, "gu"),
|
|
37
58
|
new RegExp(String.raw`,\s+${oneOf(words.usStates)}\s+\d{5}(?:-\d{4})?(?!\d)`, "gu"),
|
|
38
59
|
new RegExp(oneOf(words.emphasis), "gu"),
|
|
60
|
+
new RegExp(String.raw`(?<![\p{L}\p{N}_])${divisionOf(words.divisions)}\s+${ROMAN_NUMERAL}(?![\p{L}\p{N}_&])`, "gu"),
|
|
61
|
+
new RegExp(String.raw`(?<![\p{L}\p{N}_])${oneOf(words.honorifics)}\s+${SURNAME_IN_CAPITALS}`, "gu"),
|
|
39
62
|
];
|
|
40
63
|
|
|
41
64
|
export type NotAcronymSpans = (text: string) => Span[];
|
|
@@ -46,5 +69,13 @@ export type NotAcronymSpans = (text: string) => Span[];
|
|
|
46
69
|
*/
|
|
47
70
|
export const notAcronymSpansOf = (words: NotationWords): NotAcronymSpans => {
|
|
48
71
|
const patterns = patternsOf(words);
|
|
49
|
-
return (text) =>
|
|
72
|
+
return (text) => [
|
|
73
|
+
...patterns.flatMap((pattern) => [...text.matchAll(pattern)].map((match) => ({ start: match.index, end: match.index + match[0].length }))),
|
|
74
|
+
...citationKeySpans(text),
|
|
75
|
+
...dottedNameSpans(text),
|
|
76
|
+
...nameNumeralSpans(text),
|
|
77
|
+
...loneNumeralSpans(text),
|
|
78
|
+
...seriesLabelSpans(text),
|
|
79
|
+
...placeholderSpans(text, words.dateTimeUnits),
|
|
80
|
+
];
|
|
50
81
|
};
|