chaffjs 0.17.0 → 0.18.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/announced-count.d.ts +26 -0
- package/dist/announced-count.d.ts.map +1 -0
- package/dist/announced-count.js +104 -0
- package/dist/announced-count.js.map +1 -0
- package/dist/bare-url.d.ts +14 -0
- package/dist/bare-url.d.ts.map +1 -0
- package/dist/bare-url.js +28 -0
- package/dist/bare-url.js.map +1 -0
- package/dist/baseline.d.ts +5 -0
- package/dist/baseline.d.ts.map +1 -1
- package/dist/baseline.js +16 -1
- package/dist/baseline.js.map +1 -1
- package/dist/body-section.d.ts +7 -0
- package/dist/body-section.d.ts.map +1 -0
- package/dist/body-section.js +6 -0
- package/dist/body-section.js.map +1 -0
- package/dist/calendar-number.d.ts +2 -0
- package/dist/calendar-number.d.ts.map +1 -1
- package/dist/calendar-number.js +9 -2
- package/dist/calendar-number.js.map +1 -1
- package/dist/cli-args.d.ts +4 -0
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +5 -0
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +8 -4
- package/dist/cli-text.js.map +1 -1
- package/dist/cli.js +33 -30
- package/dist/cli.js.map +1 -1
- package/dist/commands/compare.d.ts +8 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +72 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +17 -9
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/feedback.d.ts +5 -2
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +11 -5
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +2 -4
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/tree.d.ts +13 -0
- package/dist/commands/tree.d.ts.map +1 -1
- package/dist/commands/tree.js +35 -5
- package/dist/commands/tree.js.map +1 -1
- package/dist/compare/atom.d.ts +31 -0
- package/dist/compare/atom.d.ts.map +1 -0
- package/dist/compare/atom.js +4 -0
- package/dist/compare/atom.js.map +1 -0
- package/dist/compare/clock-time.d.ts +8 -0
- package/dist/compare/clock-time.d.ts.map +1 -0
- package/dist/compare/clock-time.js +65 -0
- package/dist/compare/clock-time.js.map +1 -0
- package/dist/compare/extract.d.ts +15 -0
- package/dist/compare/extract.d.ts.map +1 -0
- package/dist/compare/extract.js +58 -0
- package/dist/compare/extract.js.map +1 -0
- package/dist/compare/fact-text.d.ts +23 -0
- package/dist/compare/fact-text.d.ts.map +1 -0
- package/dist/compare/fact-text.js +47 -0
- package/dist/compare/fact-text.js.map +1 -0
- package/dist/compare/markup-atoms.d.ts +11 -0
- package/dist/compare/markup-atoms.d.ts.map +1 -0
- package/dist/compare/markup-atoms.js +23 -0
- package/dist/compare/markup-atoms.js.map +1 -0
- package/dist/compare/match.d.ts +19 -0
- package/dist/compare/match.d.ts.map +1 -0
- package/dist/compare/match.js +84 -0
- package/dist/compare/match.js.map +1 -0
- package/dist/compare/outcome.d.ts +33 -0
- package/dist/compare/outcome.d.ts.map +1 -0
- package/dist/compare/outcome.js +40 -0
- package/dist/compare/outcome.js.map +1 -0
- package/dist/compare/proper-nouns.d.ts +19 -0
- package/dist/compare/proper-nouns.d.ts.map +1 -0
- package/dist/compare/proper-nouns.js +44 -0
- package/dist/compare/proper-nouns.js.map +1 -0
- package/dist/compare/render.d.ts +9 -0
- package/dist/compare/render.d.ts.map +1 -0
- package/dist/compare/render.js +64 -0
- package/dist/compare/render.js.map +1 -0
- package/dist/compare/spans.d.ts +9 -0
- package/dist/compare/spans.d.ts.map +1 -0
- package/dist/compare/spans.js +11 -0
- package/dist/compare/spans.js.map +1 -0
- package/dist/compare/text-atoms.d.ts +24 -0
- package/dist/compare/text-atoms.d.ts.map +1 -0
- package/dist/compare/text-atoms.js +67 -0
- package/dist/compare/text-atoms.js.map +1 -0
- package/dist/compare/text.d.ts +24 -0
- package/dist/compare/text.d.ts.map +1 -0
- package/dist/compare/text.js +90 -0
- package/dist/compare/text.js.map +1 -0
- package/dist/compare/tree-atoms.d.ts +20 -0
- package/dist/compare/tree-atoms.d.ts.map +1 -0
- package/dist/compare/tree-atoms.js +58 -0
- package/dist/compare/tree-atoms.js.map +1 -0
- package/dist/compare/written-names.d.ts +8 -0
- package/dist/compare/written-names.d.ts.map +1 -0
- package/dist/compare/written-names.js +24 -0
- package/dist/compare/written-names.js.map +1 -0
- package/dist/config/load.d.ts +15 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +5 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/option-problems.d.ts +16 -0
- package/dist/config/option-problems.d.ts.map +1 -0
- package/dist/config/option-problems.js +58 -0
- package/dist/config/option-problems.js.map +1 -0
- package/dist/config/read.d.ts +4 -0
- package/dist/config/read.d.ts.map +1 -0
- package/dist/config/read.js +8 -0
- package/dist/config/read.js.map +1 -0
- package/dist/config/rule-problems.d.ts +2 -4
- package/dist/config/rule-problems.d.ts.map +1 -1
- package/dist/config/rule-problems.js +7 -1
- package/dist/config/rule-problems.js.map +1 -1
- package/dist/config/style.d.ts +16 -0
- package/dist/config/style.d.ts.map +1 -0
- package/dist/config/style.js +36 -0
- package/dist/config/style.js.map +1 -0
- package/dist/config/warnings.d.ts +6 -0
- package/dist/config/warnings.d.ts.map +1 -0
- package/dist/config/warnings.js +10 -0
- package/dist/config/warnings.js.map +1 -0
- package/dist/config/write.d.ts.map +1 -1
- package/dist/config/write.js +17 -4
- package/dist/config/write.js.map +1 -1
- package/dist/custom/bounded-match.d.ts +15 -0
- package/dist/custom/bounded-match.d.ts.map +1 -0
- package/dist/custom/bounded-match.js +43 -0
- package/dist/custom/bounded-match.js.map +1 -0
- package/dist/custom/load.d.ts +8 -0
- package/dist/custom/load.d.ts.map +1 -0
- package/dist/custom/load.js +11 -0
- package/dist/custom/load.js.map +1 -0
- package/dist/custom/parse.d.ts +70 -0
- package/dist/custom/parse.d.ts.map +1 -0
- package/dist/custom/parse.js +215 -0
- package/dist/custom/parse.js.map +1 -0
- package/dist/custom/problems.d.ts +5 -0
- package/dist/custom/problems.d.ts.map +1 -0
- package/dist/custom/problems.js +78 -0
- package/dist/custom/problems.js.map +1 -0
- package/dist/custom/regex-safety.d.ts +11 -0
- package/dist/custom/regex-safety.d.ts.map +1 -0
- package/dist/custom/regex-safety.js +110 -0
- package/dist/custom/regex-safety.js.map +1 -0
- package/dist/custom/token-pattern.d.ts +8 -0
- package/dist/custom/token-pattern.d.ts.map +1 -0
- package/dist/custom/token-pattern.js +75 -0
- package/dist/custom/token-pattern.js.map +1 -0
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +24 -2
- package/dist/detect.js.map +1 -1
- package/dist/detectors/acronym-context.d.ts +2 -0
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +12 -4
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/ai-phrasing.d.ts +20 -0
- package/dist/detectors/ai-phrasing.d.ts.map +1 -0
- package/dist/detectors/ai-phrasing.js +112 -0
- package/dist/detectors/ai-phrasing.js.map +1 -0
- package/dist/detectors/announced-count.d.ts +4 -0
- package/dist/detectors/announced-count.d.ts.map +1 -0
- package/dist/detectors/announced-count.js +20 -0
- package/dist/detectors/announced-count.js.map +1 -0
- package/dist/detectors/broken-link.d.ts +17 -0
- package/dist/detectors/broken-link.d.ts.map +1 -0
- package/dist/detectors/broken-link.js +66 -0
- package/dist/detectors/broken-link.js.map +1 -0
- package/dist/detectors/cited-name.d.ts.map +1 -1
- package/dist/detectors/cited-name.js +4 -4
- package/dist/detectors/cited-name.js.map +1 -1
- package/dist/detectors/cited-title.d.ts +11 -0
- package/dist/detectors/cited-title.d.ts.map +1 -0
- package/dist/detectors/cited-title.js +75 -0
- package/dist/detectors/cited-title.js.map +1 -0
- package/dist/detectors/concrete-evidence.d.ts +1 -1
- package/dist/detectors/concrete-evidence.d.ts.map +1 -1
- package/dist/detectors/concrete-evidence.js +2 -1
- package/dist/detectors/concrete-evidence.js.map +1 -1
- package/dist/detectors/contrast-frame.d.ts +17 -0
- package/dist/detectors/contrast-frame.d.ts.map +1 -0
- package/dist/detectors/contrast-frame.js +32 -0
- package/dist/detectors/contrast-frame.js.map +1 -0
- package/dist/detectors/custom.d.ts +8 -0
- package/dist/detectors/custom.d.ts.map +1 -0
- package/dist/detectors/custom.js +71 -0
- package/dist/detectors/custom.js.map +1 -0
- package/dist/detectors/dangling-figure.d.ts +4 -0
- package/dist/detectors/dangling-figure.d.ts.map +1 -0
- package/dist/detectors/dangling-figure.js +18 -0
- package/dist/detectors/dangling-figure.js.map +1 -0
- package/dist/detectors/doubled-punctuation.d.ts +9 -0
- package/dist/detectors/doubled-punctuation.d.ts.map +1 -0
- package/dist/detectors/doubled-punctuation.js +33 -0
- package/dist/detectors/doubled-punctuation.js.map +1 -0
- package/dist/detectors/doubled-word.d.ts +5 -0
- package/dist/detectors/doubled-word.d.ts.map +1 -1
- package/dist/detectors/doubled-word.js +24 -11
- package/dist/detectors/doubled-word.js.map +1 -1
- package/dist/detectors/enumerated-runs.d.ts +1 -1
- package/dist/detectors/enumerated-runs.d.ts.map +1 -1
- package/dist/detectors/enumerated-runs.js +15 -4
- package/dist/detectors/enumerated-runs.js.map +1 -1
- package/dist/detectors/gram-furniture.d.ts +6 -0
- package/dist/detectors/gram-furniture.d.ts.map +1 -0
- package/dist/detectors/gram-furniture.js +21 -0
- package/dist/detectors/gram-furniture.js.map +1 -0
- package/dist/detectors/gram-place.d.ts +2 -0
- package/dist/detectors/gram-place.d.ts.map +1 -1
- package/dist/detectors/gram-place.js +9 -7
- package/dist/detectors/gram-place.js.map +1 -1
- package/dist/detectors/gram-windows.d.ts +9 -0
- package/dist/detectors/gram-windows.d.ts.map +1 -0
- package/dist/detectors/gram-windows.js +27 -0
- package/dist/detectors/gram-windows.js.map +1 -0
- package/dist/detectors/heading-case.d.ts +2 -0
- package/dist/detectors/heading-case.d.ts.map +1 -1
- package/dist/detectors/heading-case.js +29 -2
- package/dist/detectors/heading-case.js.map +1 -1
- package/dist/detectors/heading-code-words.d.ts +6 -0
- package/dist/detectors/heading-code-words.d.ts.map +1 -0
- package/dist/detectors/heading-code-words.js +29 -0
- package/dist/detectors/heading-code-words.js.map +1 -0
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +7 -4
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/heading-level-skip.d.ts +12 -0
- package/dist/detectors/heading-level-skip.d.ts.map +1 -0
- package/dist/detectors/heading-level-skip.js +11 -0
- package/dist/detectors/heading-level-skip.js.map +1 -0
- package/dist/detectors/image-alt-text.d.ts +3 -0
- package/dist/detectors/image-alt-text.d.ts.map +1 -0
- package/dist/detectors/image-alt-text.js +9 -0
- package/dist/detectors/image-alt-text.js.map +1 -0
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +34 -1
- package/dist/detectors/index.js.map +1 -1
- package/dist/detectors/kutoten-consistency.d.ts +24 -0
- package/dist/detectors/kutoten-consistency.d.ts.map +1 -0
- package/dist/detectors/kutoten-consistency.js +77 -0
- package/dist/detectors/kutoten-consistency.js.map +1 -0
- package/dist/detectors/lead-in.d.ts +1 -0
- package/dist/detectors/lead-in.d.ts.map +1 -1
- package/dist/detectors/lead-in.js +2 -1
- package/dist/detectors/lead-in.js.map +1 -1
- package/dist/detectors/lexicon-match.d.ts +4 -0
- package/dist/detectors/lexicon-match.d.ts.map +1 -1
- package/dist/detectors/lexicon-match.js +7 -2
- package/dist/detectors/lexicon-match.js.map +1 -1
- package/dist/detectors/list-item.d.ts +45 -0
- package/dist/detectors/list-item.d.ts.map +1 -0
- package/dist/detectors/list-item.js +88 -0
- package/dist/detectors/list-item.js.map +1 -0
- package/dist/detectors/list-items.d.ts +31 -0
- package/dist/detectors/list-items.d.ts.map +1 -0
- package/dist/detectors/list-items.js +113 -0
- package/dist/detectors/list-items.js.map +1 -0
- package/dist/detectors/list-lead-in.d.ts +7 -0
- package/dist/detectors/list-lead-in.d.ts.map +1 -0
- package/dist/detectors/list-lead-in.js +28 -0
- package/dist/detectors/list-lead-in.js.map +1 -0
- package/dist/detectors/list-sentence.d.ts +65 -0
- package/dist/detectors/list-sentence.d.ts.map +1 -0
- package/dist/detectors/list-sentence.js +105 -0
- package/dist/detectors/list-sentence.js.map +1 -0
- package/dist/detectors/list-view.d.ts +34 -0
- package/dist/detectors/list-view.d.ts.map +1 -0
- package/dist/detectors/list-view.js +137 -0
- package/dist/detectors/list-view.js.map +1 -0
- package/dist/detectors/long-vowel.d.ts +7 -0
- package/dist/detectors/long-vowel.d.ts.map +1 -0
- package/dist/detectors/long-vowel.js +57 -0
- package/dist/detectors/long-vowel.js.map +1 -0
- package/dist/detectors/markup-finding.d.ts +6 -0
- package/dist/detectors/markup-finding.d.ts.map +1 -0
- package/dist/detectors/markup-finding.js +19 -0
- package/dist/detectors/markup-finding.js.map +1 -0
- package/dist/detectors/name-numeral.d.ts +1 -1
- package/dist/detectors/name-numeral.d.ts.map +1 -1
- package/dist/detectors/name-numeral.js +2 -7
- package/dist/detectors/name-numeral.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +14 -10
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/oxford-comma.d.ts +7 -1
- package/dist/detectors/oxford-comma.d.ts.map +1 -1
- package/dist/detectors/oxford-comma.js +135 -229
- package/dist/detectors/oxford-comma.js.map +1 -1
- package/dist/detectors/place-run.d.ts.map +1 -1
- package/dist/detectors/place-run.js +10 -6
- package/dist/detectors/place-run.js.map +1 -1
- package/dist/detectors/placeholder-text.d.ts +9 -0
- package/dist/detectors/placeholder-text.d.ts.map +1 -0
- package/dist/detectors/placeholder-text.js +18 -0
- package/dist/detectors/placeholder-text.js.map +1 -0
- package/dist/detectors/quote-around.d.ts +3 -0
- package/dist/detectors/quote-around.d.ts.map +1 -0
- package/dist/detectors/quote-around.js +8 -0
- package/dist/detectors/quote-around.js.map +1 -0
- package/dist/detectors/register.d.ts +11 -3
- package/dist/detectors/register.d.ts.map +1 -1
- package/dist/detectors/register.js +28 -9
- package/dist/detectors/register.js.map +1 -1
- package/dist/detectors/roman-numeral.d.ts +2 -0
- package/dist/detectors/roman-numeral.d.ts.map +1 -1
- package/dist/detectors/roman-numeral.js +2 -0
- package/dist/detectors/roman-numeral.js.map +1 -1
- package/dist/detectors/sentence-ending.d.ts +17 -1
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +13 -7
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/sentence-length.d.ts.map +1 -1
- package/dist/detectors/sentence-length.js +13 -4
- package/dist/detectors/sentence-length.js.map +1 -1
- package/dist/detectors/signals.d.ts +8 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +67 -46
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts +6 -0
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +37 -1
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.d.ts +1 -3
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +3 -4
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/superlative-name.d.ts.map +1 -1
- package/dist/detectors/superlative-name.js +8 -5
- package/dist/detectors/superlative-name.js.map +1 -1
- package/dist/detectors/superlative-scope.d.ts.map +1 -1
- package/dist/detectors/superlative-scope.js +9 -4
- package/dist/detectors/superlative-scope.js.map +1 -1
- package/dist/detectors/token-column.d.ts +46 -0
- package/dist/detectors/token-column.d.ts.map +1 -0
- package/dist/detectors/token-column.js +95 -0
- package/dist/detectors/token-column.js.map +1 -0
- package/dist/detectors/unbalanced-bracket.d.ts +22 -0
- package/dist/detectors/unbalanced-bracket.d.ts.map +1 -0
- package/dist/detectors/unbalanced-bracket.js +119 -0
- package/dist/detectors/unbalanced-bracket.js.map +1 -0
- package/dist/detectors/url-run-on.d.ts +9 -0
- package/dist/detectors/url-run-on.d.ts.map +1 -0
- package/dist/detectors/url-run-on.js +19 -0
- package/dist/detectors/url-run-on.js.map +1 -0
- package/dist/document-sections.d.ts +13 -0
- package/dist/document-sections.d.ts.map +1 -0
- package/dist/document-sections.js +32 -0
- package/dist/document-sections.js.map +1 -0
- package/dist/document.d.ts +11 -4
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +90 -98
- package/dist/document.js.map +1 -1
- package/dist/email-parts.d.ts +28 -0
- package/dist/email-parts.d.ts.map +1 -0
- package/dist/email-parts.js +230 -0
- package/dist/email-parts.js.map +1 -0
- package/dist/eval.d.ts +2 -1
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +16 -4
- package/dist/eval.js.map +1 -1
- package/dist/figure-references.d.ts +30 -0
- package/dist/figure-references.d.ts.map +1 -0
- package/dist/figure-references.js +76 -0
- package/dist/figure-references.js.map +1 -0
- package/dist/files.d.ts +2 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +4 -0
- package/dist/files.js.map +1 -1
- package/dist/heading-label.d.ts +22 -0
- package/dist/heading-label.d.ts.map +1 -0
- package/dist/heading-label.js +50 -0
- package/dist/heading-label.js.map +1 -0
- package/dist/in-page-nav.d.ts +4 -1
- package/dist/in-page-nav.d.ts.map +1 -1
- package/dist/in-page-nav.js +53 -18
- package/dist/in-page-nav.js.map +1 -1
- package/dist/joined-view.d.ts.map +1 -1
- package/dist/joined-view.js +1 -0
- package/dist/joined-view.js.map +1 -1
- package/dist/levels.d.ts +5 -1
- package/dist/levels.d.ts.map +1 -1
- package/dist/levels.js +9 -0
- package/dist/levels.js.map +1 -1
- package/dist/line-paragraphs.d.ts +8 -0
- package/dist/line-paragraphs.d.ts.map +1 -1
- package/dist/line-paragraphs.js +33 -10
- package/dist/line-paragraphs.js.map +1 -1
- package/dist/long-vowel.d.ts +35 -0
- package/dist/long-vowel.d.ts.map +1 -0
- package/dist/long-vowel.js +71 -0
- package/dist/long-vowel.js.map +1 -0
- package/dist/markdown-node.d.ts +19 -0
- package/dist/markdown-node.d.ts.map +1 -0
- package/dist/markdown-node.js +6 -0
- package/dist/markdown-node.js.map +1 -0
- package/dist/markdown-read.d.ts +17 -0
- package/dist/markdown-read.d.ts.map +1 -0
- package/dist/markdown-read.js +37 -0
- package/dist/markdown-read.js.map +1 -0
- package/dist/markup.d.ts +22 -0
- package/dist/markup.d.ts.map +1 -0
- package/dist/markup.js +180 -0
- package/dist/markup.js.map +1 -0
- package/dist/mask.js +8 -5
- package/dist/mask.js.map +1 -1
- package/dist/number-name.d.ts +21 -5
- package/dist/number-name.d.ts.map +1 -1
- package/dist/number-name.js +119 -17
- package/dist/number-name.js.map +1 -1
- package/dist/orthography.d.ts +2 -0
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +9 -4
- package/dist/orthography.js.map +1 -1
- package/dist/page-furniture.d.ts +5 -2
- package/dist/page-furniture.d.ts.map +1 -1
- package/dist/page-furniture.js +8 -2
- package/dist/page-furniture.js.map +1 -1
- package/dist/plain-source.d.ts +1 -0
- package/dist/plain-source.d.ts.map +1 -1
- package/dist/plain-source.js +2 -1
- package/dist/plain-source.js.map +1 -1
- package/dist/plugin.d.ts +115 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/profile/for-file.d.ts.map +1 -1
- package/dist/profile/for-file.js +3 -1
- package/dist/profile/for-file.js.map +1 -1
- package/dist/quoted-span.d.ts.map +1 -1
- package/dist/quoted-span.js +8 -3
- package/dist/quoted-span.js.map +1 -1
- package/dist/reasons.d.ts +3 -0
- package/dist/reasons.d.ts.map +1 -1
- package/dist/reasons.js +6 -0
- package/dist/reasons.js.map +1 -1
- package/dist/reference-lists.d.ts +3 -0
- package/dist/reference-lists.d.ts.map +1 -0
- package/dist/reference-lists.js +75 -0
- package/dist/reference-lists.js.map +1 -0
- package/dist/render/explain.d.ts +7 -1
- package/dist/render/explain.d.ts.map +1 -1
- package/dist/render/explain.js +36 -12
- package/dist/render/explain.js.map +1 -1
- package/dist/render/friendly.d.ts.map +1 -1
- package/dist/render/friendly.js +19 -9
- package/dist/render/friendly.js.map +1 -1
- package/dist/render/options.d.ts +7 -0
- package/dist/render/options.d.ts.map +1 -0
- package/dist/render/options.js +50 -0
- package/dist/render/options.js.map +1 -0
- package/dist/render/rules-json.d.ts +4 -1
- package/dist/render/rules-json.d.ts.map +1 -1
- package/dist/render/rules-json.js +102 -12
- package/dist/render/rules-json.js.map +1 -1
- package/dist/render/rules-table.d.ts +4 -0
- package/dist/render/rules-table.d.ts.map +1 -0
- package/dist/render/rules-table.js +70 -0
- package/dist/render/rules-table.js.map +1 -0
- package/dist/render/sarif.js +4 -4
- package/dist/render/sarif.js.map +1 -1
- package/dist/render/semantic.js +3 -3
- package/dist/render/semantic.js.map +1 -1
- package/dist/render/severity-name.d.ts +6 -0
- package/dist/render/severity-name.d.ts.map +1 -0
- package/dist/render/severity-name.js +7 -0
- package/dist/render/severity-name.js.map +1 -0
- package/dist/render/text.d.ts +7 -2
- package/dist/render/text.d.ts.map +1 -1
- package/dist/render/text.js +15 -4
- package/dist/render/text.js.map +1 -1
- package/dist/resolve-genre.d.ts +1 -1
- package/dist/resolve-genre.d.ts.map +1 -1
- package/dist/resolve-genre.js +4 -1
- package/dist/resolve-genre.js.map +1 -1
- package/dist/rule-genres.d.ts +24 -0
- package/dist/rule-genres.d.ts.map +1 -0
- package/dist/rule-genres.js +11 -0
- package/dist/rule-genres.js.map +1 -0
- package/dist/rule-guide.d.ts +54 -0
- package/dist/rule-guide.d.ts.map +1 -0
- package/dist/rule-guide.js +81 -0
- package/dist/rule-guide.js.map +1 -0
- package/dist/rule-load.d.ts.map +1 -1
- package/dist/rule-load.js +87 -33
- package/dist/rule-load.js.map +1 -1
- package/dist/rule-options.d.ts +50 -0
- package/dist/rule-options.d.ts.map +1 -0
- package/dist/rule-options.js +106 -0
- package/dist/rule-options.js.map +1 -0
- package/dist/run.d.ts +13 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +54 -10
- package/dist/run.js.map +1 -1
- package/dist/sentence-shape.d.ts.map +1 -1
- package/dist/sentence-shape.js +4 -4
- package/dist/sentence-shape.js.map +1 -1
- package/dist/setting-problems.d.ts +2 -1
- package/dist/setting-problems.d.ts.map +1 -1
- package/dist/setting-problems.js +6 -1
- package/dist/setting-problems.js.map +1 -1
- package/dist/span-cut.d.ts +6 -0
- package/dist/span-cut.d.ts.map +1 -0
- package/dist/span-cut.js +22 -0
- package/dist/span-cut.js.map +1 -0
- package/dist/structure/aside-depth.d.ts +21 -0
- package/dist/structure/aside-depth.d.ts.map +1 -0
- package/dist/structure/aside-depth.js +65 -0
- package/dist/structure/aside-depth.js.map +1 -0
- package/dist/structure/build.d.ts +5 -1
- package/dist/structure/build.d.ts.map +1 -1
- package/dist/structure/build.js +29 -17
- package/dist/structure/build.js.map +1 -1
- package/dist/structure/closed-pairs.d.ts +8 -0
- package/dist/structure/closed-pairs.d.ts.map +1 -0
- package/dist/structure/closed-pairs.js +22 -0
- package/dist/structure/closed-pairs.js.map +1 -0
- package/dist/structure/date-range.d.ts +21 -0
- package/dist/structure/date-range.d.ts.map +1 -0
- package/dist/structure/date-range.js +45 -0
- package/dist/structure/date-range.js.map +1 -0
- package/dist/structure/known-mentions.d.ts +18 -0
- package/dist/structure/known-mentions.d.ts.map +1 -0
- package/dist/structure/known-mentions.js +78 -0
- package/dist/structure/known-mentions.js.map +1 -0
- package/dist/structure/numbering.d.ts +1 -0
- package/dist/structure/numbering.d.ts.map +1 -1
- package/dist/structure/numbering.js +11 -6
- package/dist/structure/numbering.js.map +1 -1
- package/dist/structure/of.d.ts +3 -1
- package/dist/structure/of.d.ts.map +1 -1
- package/dist/structure/of.js +5 -1
- package/dist/structure/of.js.map +1 -1
- package/dist/structure/percent-sum.d.ts +16 -0
- package/dist/structure/percent-sum.d.ts.map +1 -0
- package/dist/structure/percent-sum.js +104 -0
- package/dist/structure/percent-sum.js.map +1 -0
- package/dist/structure/quoted-number.d.ts +8 -0
- package/dist/structure/quoted-number.d.ts.map +1 -0
- package/dist/structure/quoted-number.js +34 -0
- package/dist/structure/quoted-number.js.map +1 -0
- package/dist/structure/relative-find.d.ts.map +1 -1
- package/dist/structure/relative-find.js +34 -46
- package/dist/structure/relative-find.js.map +1 -1
- package/dist/structure/relative-resolve.d.ts.map +1 -1
- package/dist/structure/relative-resolve.js +76 -30
- package/dist/structure/relative-resolve.js.map +1 -1
- package/dist/structure/runs.d.ts +2 -0
- package/dist/structure/runs.d.ts.map +1 -1
- package/dist/structure/runs.js +2 -2
- package/dist/structure/runs.js.map +1 -1
- package/dist/structure/sexp.d.ts +1 -1
- package/dist/structure/sexp.d.ts.map +1 -1
- package/dist/structure/sexp.js +18 -6
- package/dist/structure/sexp.js.map +1 -1
- package/dist/structure/total.d.ts +3 -0
- package/dist/structure/total.d.ts.map +1 -1
- package/dist/structure/total.js +2 -2
- package/dist/structure/total.js.map +1 -1
- package/dist/structure/universal.d.ts +14 -2
- package/dist/structure/universal.d.ts.map +1 -1
- package/dist/structure/universal.js +17 -2
- package/dist/structure/universal.js.map +1 -1
- package/dist/structure/wrapped-tail.d.ts +14 -7
- package/dist/structure/wrapped-tail.d.ts.map +1 -1
- package/dist/structure/wrapped-tail.js +33 -8
- package/dist/structure/wrapped-tail.js.map +1 -1
- package/dist/style-load.d.ts +4 -0
- package/dist/style-load.d.ts.map +1 -0
- package/dist/style-load.js +28 -0
- package/dist/style-load.js.map +1 -0
- package/dist/style-parse.d.ts +19 -0
- package/dist/style-parse.d.ts.map +1 -0
- package/dist/style-parse.js +60 -0
- package/dist/style-parse.js.map +1 -0
- package/dist/subheading-line.d.ts +6 -0
- package/dist/subheading-line.d.ts.map +1 -0
- package/dist/subheading-line.js +57 -0
- package/dist/subheading-line.js.map +1 -0
- package/dist/template-syntax.d.ts +17 -0
- package/dist/template-syntax.d.ts.map +1 -0
- package/dist/template-syntax.js +140 -0
- package/dist/template-syntax.js.map +1 -0
- package/dist/text-above.d.ts +19 -0
- package/dist/text-above.d.ts.map +1 -0
- package/dist/text-above.js +43 -0
- package/dist/text-above.js.map +1 -0
- package/dist/text-figures.d.ts +10 -0
- package/dist/text-figures.d.ts.map +1 -0
- package/dist/text-figures.js +131 -0
- package/dist/text-figures.js.map +1 -0
- package/dist/trailing-aside.d.ts +2 -0
- package/dist/trailing-aside.d.ts.map +1 -0
- package/dist/trailing-aside.js +53 -0
- package/dist/trailing-aside.js.map +1 -0
- package/dist/tree-walk.d.ts +18 -0
- package/dist/tree-walk.d.ts.map +1 -0
- package/dist/tree-walk.js +45 -0
- package/dist/tree-walk.js.map +1 -0
- package/genres.yaml +26 -0
- package/package.json +5 -3
- package/reference-headings.yaml +17 -0
- package/rules/adverb-overuse.yaml +19 -0
- package/rules/agentless-passive.yaml +19 -0
- package/rules/agreement-slip.yaml +14 -1
- package/rules/ai-generated-composite.yaml +102 -0
- package/rules/ai-tell.yaml +23 -0
- package/rules/announced-count-mismatch.yaml +57 -0
- package/rules/announcing-opener.yaml +51 -0
- package/rules/assistant-residue.yaml +52 -0
- package/rules/bold-density.yaml +31 -0
- package/rules/broken-link.yaml +65 -0
- package/rules/closing-cliche.yaml +33 -0
- package/rules/colon-lead-in.yaml +59 -0
- package/rules/concrete-evidence-density.yaml +41 -0
- package/rules/contraction-consistency.yaml +18 -0
- package/rules/contrast-framing.yaml +57 -0
- package/rules/cushion-phrase-density.yaml +25 -0
- package/rules/dangling-figure-reference.yaml +61 -0
- package/rules/dangling-reference.yaml +53 -1
- package/rules/date-order.yaml +33 -1
- package/rules/date-range-reversed.yaml +46 -0
- package/rules/date-weekday-mismatch.yaml +17 -1
- package/rules/double-keigo.yaml +16 -0
- package/rules/doubled-punctuation.yaml +45 -0
- package/rules/doubled-word.yaml +17 -1
- package/rules/duplicate-definition.yaml +59 -1
- package/rules/emoji-density.yaml +25 -0
- package/rules/empty-conclusion.yaml +28 -0
- package/rules/empty-intensifier.yaml +19 -0
- package/rules/excessive-hedging.yaml +19 -0
- package/rules/expletive-construction.yaml +19 -0
- package/rules/heading-echo.yaml +31 -0
- package/rules/heading-level-skip.yaml +78 -0
- package/rules/hiragana-fukushi.yaml +16 -0
- package/rules/image-alt-text.yaml +54 -0
- package/rules/internal-jargon.yaml +21 -0
- package/rules/katakana-long-vowel.yaml +98 -0
- package/rules/kutoten-consistency.yaml +53 -0
- package/rules/latin-spacing.yaml +23 -4
- package/rules/max-kanji-continuous.yaml +16 -0
- package/rules/max-paragraph-length.yaml +33 -0
- package/rules/max-sentence-length.yaml +32 -0
- package/rules/ngram-repetition.yaml +29 -2
- package/rules/no-doubled-joshi.yaml +16 -0
- package/rules/no-em-dash.yaml +25 -0
- package/rules/no-mixed-desumasu.yaml +27 -2
- package/rules/no-nakaguro-parallel.yaml +20 -0
- package/rules/numbering-gap.yaml +53 -1
- package/rules/oxford-comma-consistency.yaml +18 -0
- package/rules/padded-intro.yaml +19 -0
- package/rules/paragraph-length-variance.yaml +49 -0
- package/rules/percent-sum-mismatch.yaml +58 -0
- package/rules/preamble-length.yaml +56 -0
- package/rules/preferred-term.yaml +27 -0
- package/rules/proper-noun-density.yaml +26 -0
- package/rules/repeated-conjunction.yaml +47 -0
- package/rules/repeated-sentence-head.yaml +23 -0
- package/rules/required-sections.yaml +49 -0
- package/rules/risk-disclosure.yaml +22 -0
- package/rules/rule-of-three.yaml +97 -0
- package/rules/sasete-itadaku.yaml +18 -0
- package/rules/section-length-uniformity.yaml +89 -0
- package/rules/sentence-initial-conjunction-run.yaml +18 -0
- package/rules/sentence-rhythm.yaml +25 -0
- package/rules/stock-transition.yaml +55 -0
- package/rules/stray-space.yaml +18 -0
- package/rules/taigen-dome-in-prose.yaml +19 -0
- package/rules/title-case-consistency.yaml +42 -0
- package/rules/total-mismatch.yaml +37 -1
- package/rules/unbalanced-bracket.yaml +56 -0
- package/rules/undefined-acronym.yaml +22 -0
- package/rules/unfilled-placeholder.yaml +50 -0
- package/rules/unqualified-superlative.yaml +19 -0
- package/rules/unsourced-number.yaml +16 -0
- package/rules/url-run-on.yaml +45 -0
- package/skills/chaff/SKILL.md +70 -0
- package/src/announced-count.ts +148 -0
- package/src/bare-url.ts +35 -0
- package/src/baseline.ts +17 -1
- package/src/body-section.ts +7 -0
- package/src/calendar-number.ts +18 -4
- package/src/cli-args.ts +6 -0
- package/src/cli-text.ts +8 -4
- package/src/cli.ts +37 -37
- package/src/commands/compare.ts +80 -0
- package/src/commands/eval.ts +19 -8
- package/src/commands/feedback.ts +12 -6
- package/src/commands/test.ts +2 -4
- package/src/commands/tree.ts +41 -5
- package/src/compare/atom.ts +33 -0
- package/src/compare/clock-time.ts +86 -0
- package/src/compare/extract.ts +78 -0
- package/src/compare/fact-text.ts +68 -0
- package/src/compare/markup-atoms.ts +29 -0
- package/src/compare/match.ts +105 -0
- package/src/compare/outcome.ts +70 -0
- package/src/compare/proper-nouns.ts +65 -0
- package/src/compare/render.ts +102 -0
- package/src/compare/spans.ts +17 -0
- package/src/compare/text-atoms.ts +95 -0
- package/src/compare/text.ts +120 -0
- package/src/compare/tree-atoms.ts +80 -0
- package/src/compare/written-names.ts +26 -0
- package/src/config/load.ts +21 -0
- package/src/config/option-problems.ts +70 -0
- package/src/config/read.ts +8 -0
- package/src/config/rule-problems.ts +12 -2
- package/src/config/style.ts +42 -0
- package/src/config/warnings.ts +13 -0
- package/src/config/write.ts +18 -4
- package/src/custom/bounded-match.ts +58 -0
- package/src/custom/load.ts +15 -0
- package/src/custom/parse.ts +274 -0
- package/src/custom/problems.ts +89 -0
- package/src/custom/regex-safety.ts +118 -0
- package/src/custom/token-pattern.ts +84 -0
- package/src/detect.ts +28 -2
- package/src/detectors/acronym-context.ts +16 -4
- package/src/detectors/ai-phrasing.ts +137 -0
- package/src/detectors/announced-count.ts +25 -0
- package/src/detectors/broken-link.ts +90 -0
- package/src/detectors/cited-name.ts +6 -5
- package/src/detectors/cited-title.ts +96 -0
- package/src/detectors/concrete-evidence.ts +3 -2
- package/src/detectors/contrast-frame.ts +54 -0
- package/src/detectors/custom.ts +89 -0
- package/src/detectors/dangling-figure.ts +22 -0
- package/src/detectors/doubled-punctuation.ts +49 -0
- package/src/detectors/doubled-word.ts +19 -4
- package/src/detectors/enumerated-runs.ts +13 -4
- package/src/detectors/gram-furniture.ts +30 -0
- package/src/detectors/gram-place.ts +9 -5
- package/src/detectors/gram-windows.ts +31 -0
- package/src/detectors/heading-case.ts +30 -2
- package/src/detectors/heading-code-words.ts +35 -0
- package/src/detectors/heading-echo.ts +8 -4
- package/src/detectors/heading-level-skip.ts +19 -0
- package/src/detectors/image-alt-text.ts +11 -0
- package/src/detectors/index.ts +43 -1
- package/src/detectors/kutoten-consistency.ts +96 -0
- package/src/detectors/lead-in.ts +3 -1
- package/src/detectors/lexicon-match.ts +9 -2
- package/src/detectors/list-item.ts +122 -0
- package/src/detectors/list-items.ts +163 -0
- package/src/detectors/list-lead-in.ts +33 -0
- package/src/detectors/list-sentence.ts +157 -0
- package/src/detectors/list-view.ts +157 -0
- package/src/detectors/long-vowel.ts +66 -0
- package/src/detectors/markup-finding.ts +24 -0
- package/src/detectors/name-numeral.ts +4 -2
- package/src/detectors/orthography.ts +23 -17
- package/src/detectors/oxford-comma.ts +178 -283
- package/src/detectors/place-run.ts +7 -4
- package/src/detectors/placeholder-text.ts +27 -0
- package/src/detectors/quote-around.ts +9 -0
- package/src/detectors/register.ts +37 -10
- package/src/detectors/roman-numeral.ts +3 -0
- package/src/detectors/sentence-ending.ts +14 -7
- package/src/detectors/sentence-length.ts +16 -5
- package/src/detectors/signals.ts +80 -46
- package/src/detectors/structure-tree.ts +45 -1
- package/src/detectors/structure.ts +3 -4
- package/src/detectors/superlative-name.ts +7 -4
- package/src/detectors/superlative-scope.ts +8 -3
- package/src/detectors/token-column.ts +149 -0
- package/src/detectors/unbalanced-bracket.ts +153 -0
- package/src/detectors/url-run-on.ts +27 -0
- package/src/document-sections.ts +46 -0
- package/src/document.ts +106 -138
- package/src/email-parts.ts +269 -0
- package/src/eval.ts +14 -4
- package/src/figure-references.ts +112 -0
- package/src/files.ts +5 -0
- package/src/heading-label.ts +55 -0
- package/src/in-page-nav.ts +48 -19
- package/src/joined-view.ts +1 -0
- package/src/levels.ts +14 -1
- package/src/line-paragraphs.ts +52 -9
- package/src/long-vowel.ts +99 -0
- package/src/markdown-node.ts +19 -0
- package/src/markdown-read.ts +44 -0
- package/src/markup.ts +210 -0
- package/src/mask.ts +8 -8
- package/src/number-name.ts +151 -24
- package/src/orthography.ts +10 -3
- package/src/page-furniture.ts +11 -2
- package/src/plain-source.ts +2 -1
- package/src/plugin.ts +101 -1
- package/src/profile/for-file.ts +3 -1
- package/src/quoted-span.ts +9 -3
- package/src/reasons.ts +9 -0
- package/src/reference-lists.ts +91 -0
- package/src/render/explain.ts +47 -13
- package/src/render/friendly.ts +20 -9
- package/src/render/options.ts +58 -0
- package/src/render/rules-json.ts +130 -14
- package/src/render/rules-table.ts +91 -0
- package/src/render/sarif.ts +4 -4
- package/src/render/semantic.ts +3 -3
- package/src/render/severity-name.ts +10 -0
- package/src/render/text.ts +21 -7
- package/src/resolve-genre.ts +4 -1
- package/src/rule-genres.ts +25 -0
- package/src/rule-guide.ts +135 -0
- package/src/rule-load.ts +91 -34
- package/src/rule-options.ts +131 -0
- package/src/run.ts +74 -11
- package/src/sentence-shape.ts +4 -5
- package/src/setting-problems.ts +7 -1
- package/src/span-cut.ts +28 -0
- package/src/structure/aside-depth.ts +67 -0
- package/src/structure/build.ts +38 -19
- package/src/structure/closed-pairs.ts +20 -0
- package/src/structure/date-range.ts +69 -0
- package/src/structure/known-mentions.ts +96 -0
- package/src/structure/numbering.ts +9 -5
- package/src/structure/of.ts +11 -3
- package/src/structure/percent-sum.ts +135 -0
- package/src/structure/quoted-number.ts +36 -0
- package/src/structure/relative-find.ts +34 -47
- package/src/structure/relative-resolve.ts +77 -30
- package/src/structure/runs.ts +2 -2
- package/src/structure/sexp.ts +17 -5
- package/src/structure/total.ts +2 -2
- package/src/structure/universal.ts +24 -4
- package/src/structure/wrapped-tail.ts +38 -13
- package/src/style-load.ts +28 -0
- package/src/style-parse.ts +77 -0
- package/src/subheading-line.ts +68 -0
- package/src/template-syntax.ts +164 -0
- package/src/text-above.ts +49 -0
- package/src/text-figures.ts +147 -0
- package/src/trailing-aside.ts +50 -0
- package/src/tree-walk.ts +48 -0
- package/styles/bunkacho.yaml +25 -0
- package/styles/ieice.yaml +29 -0
- package/styles/jis-z8301-2011.yaml +25 -0
package/src/rule-load.ts
CHANGED
|
@@ -2,7 +2,10 @@ import { readFileSync, readdirSync } from "node:fs";
|
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { parse } from "yaml";
|
|
5
|
-
import type { LevelTable, RuleDefinition, Severity } from "./plugin.ts";
|
|
5
|
+
import type { LanguageLevels, LevelSets, LevelTable, RuleDefinition, Severity } from "./plugin.ts";
|
|
6
|
+
import { rankOfSeverity, severityAt } from "./levels.ts";
|
|
7
|
+
import { optionsOf } from "./rule-options.ts";
|
|
8
|
+
import { ruleGuideOf } from "./rule-guide.ts";
|
|
6
9
|
|
|
7
10
|
const RULES_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "rules");
|
|
8
11
|
|
|
@@ -10,13 +13,8 @@ const isRecord = (value: unknown): value is Record<string, unknown> => typeof va
|
|
|
10
13
|
|
|
11
14
|
const isLocalized = (value: unknown): value is Record<string, string> => isRecord(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/** L4 は件数ではなく深刻度を段で持つ。error/warning/info を数に写して同じ器に入れる。 */
|
|
16
|
-
const asNumber = (entry: unknown): number | undefined => {
|
|
17
|
-
if (typeof entry === "number") return entry;
|
|
18
|
-
return typeof entry === "string" ? SEVERITY_BY_NAME[entry] : undefined;
|
|
19
|
-
};
|
|
16
|
+
/** 数えるものの無い rule(L4、番号の抜け)は件数ではなく重さを段で持つ。error/warning/info を数に写して同じ器に入れる。 */
|
|
17
|
+
const asNumber = (entry: unknown): number | undefined => (typeof entry === "number" ? entry : rankOfSeverity(entry));
|
|
20
18
|
|
|
21
19
|
const isLevelTable = (value: unknown): value is LevelTable =>
|
|
22
20
|
isRecord(value) && Object.entries(value).every(([key, entry]) => ["strict", "normal", "relaxed"].includes(key) && asNumber(entry) !== undefined);
|
|
@@ -41,6 +39,20 @@ const genreTables = (raw: unknown, language: string): Readonly<Record<string, Le
|
|
|
41
39
|
return Object.fromEntries(entries);
|
|
42
40
|
};
|
|
43
41
|
|
|
42
|
+
/** levels を言語別に書いた rule の、loaded 以外の言語の段。言語で分けていない rule は空。 */
|
|
43
|
+
const otherLanguages = (raw: Record<string, unknown>, loaded: string): Record<string, LanguageLevels> => {
|
|
44
|
+
const levels = raw["levels"];
|
|
45
|
+
if (!isRecord(levels) || isLevelTable(levels)) return {};
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
Object.keys(levels)
|
|
48
|
+
.filter((language) => language !== loaded && language !== "default")
|
|
49
|
+
.flatMap((language) => {
|
|
50
|
+
const table = flattenLevels(levels, language);
|
|
51
|
+
return table === undefined ? [] : [[language, { levels: table, by_genre: genreTables(raw["by_genre"], language) }] as const];
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
44
56
|
const SEVERITIES: readonly Severity[] = ["error", "warning", "info"];
|
|
45
57
|
const isSeverity = (value: unknown): value is Severity => SEVERITIES.some((entry) => entry === value);
|
|
46
58
|
|
|
@@ -68,8 +80,8 @@ const missingFields = (raw: Record<string, unknown>, levels: LevelTable | undefi
|
|
|
68
80
|
|
|
69
81
|
const localizedOf = (value: unknown): Record<string, string> => (isLocalized(value) ? value : {});
|
|
70
82
|
|
|
71
|
-
/** 見つけ方ごとの message
|
|
72
|
-
const
|
|
83
|
+
/** 見つけ方ごとの message、置き場所ごとの読みかた。読めないものは捨てる。 */
|
|
84
|
+
const localizedByKey = (value: unknown): Record<string, Record<string, string>> =>
|
|
73
85
|
isRecord(value) ? Object.fromEntries(Object.entries(value).flatMap(([variant, text]) => (isLocalized(text) ? [[variant, text]] : []))) : {};
|
|
74
86
|
|
|
75
87
|
/**
|
|
@@ -92,38 +104,83 @@ const numberFor = (raw: unknown, language: string): number | undefined => {
|
|
|
92
104
|
|
|
93
105
|
const stringList = (value: unknown): string[] | undefined => (Array.isArray(value) ? value.map((entry) => String(entry)) : undefined);
|
|
94
106
|
|
|
107
|
+
/** What only some rules declare: options beyond the level, and token features the adapter computes on request. */
|
|
108
|
+
const extrasOf = (raw: Record<string, unknown>, file: string): Pick<RuleDefinition, "options" | "token_features"> => ({
|
|
109
|
+
...(raw["options"] === undefined ? {} : { options: optionsOf(raw["options"], file) }),
|
|
110
|
+
...(raw["token_features"] === undefined ? {} : { token_features: stringList(raw["token_features"]) ?? [] }),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/** The table flattenLevels reads, before its severities become numbers. */
|
|
114
|
+
const writtenTable = (raw: unknown, language: string): unknown => {
|
|
115
|
+
if (isLevelTable(raw) || !isRecord(raw)) return raw;
|
|
116
|
+
return raw[language] ?? raw["default"];
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/** Every level value written for a language: the rule's own table and each genre's. */
|
|
120
|
+
const writtenValues = (raw: Record<string, unknown>, language: string): unknown[] => {
|
|
121
|
+
const genres = isRecord(raw["by_genre"]) ? Object.values(raw["by_genre"]) : [];
|
|
122
|
+
return [raw["levels"], ...genres].flatMap((written) => {
|
|
123
|
+
const table = writtenTable(written, language);
|
|
124
|
+
return isRecord(table) ? Object.values(table) : [];
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/** Levels written as severities set the severity; a rule that mixes the two would say both. */
|
|
129
|
+
const levelSetsOf = (raw: Record<string, unknown>, language: string, file: string): LevelSets => {
|
|
130
|
+
const values = writtenValues(raw, language);
|
|
131
|
+
const severities = values.filter((value) => typeof value === "string").length;
|
|
132
|
+
if (severities === 0) return "limit";
|
|
133
|
+
if (severities < values.length) throw new Error(`${file}: levels と by_genre に重さ(error / warning / info)と数を混ぜて書けません`);
|
|
134
|
+
// A genre's table would give the rule a default severity other than its severity field.
|
|
135
|
+
if (isRecord(raw["by_genre"])) throw new Error(`${file}: 重さを段に持つ rule は by_genre を持てません`);
|
|
136
|
+
return "severity";
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/** severity は normal の段の重さそのもの。食い違うと、段を書かないときと normal と書いたときで重さが変わる。 */
|
|
140
|
+
const checkedSeverity = (rule: RuleDefinition, file: string): RuleDefinition => {
|
|
141
|
+
if (rule.level_sets === "limit" || severityAt(rule, "normal") === rule.severity) return rule;
|
|
142
|
+
throw new Error(`${file}: severity ${rule.severity} が levels の normal(${severityAt(rule, "normal")})と違います`);
|
|
143
|
+
};
|
|
144
|
+
|
|
95
145
|
const toRule = (raw: unknown, language: string, file: string): RuleDefinition => {
|
|
96
146
|
if (!isRecord(raw)) throw new Error(`${file}: rule は object であること`);
|
|
97
147
|
const levels = flattenLevels(raw["levels"], language);
|
|
98
148
|
const missing = missingFields(raw, levels);
|
|
99
149
|
if (missing.length > 0) throw new Error(`${file}: 必須フィールドがありません: ${missing.join(", ")}`);
|
|
100
150
|
if (levels === undefined) throw new Error(`${file}: levels を解決できません`);
|
|
101
|
-
return
|
|
102
|
-
id: String(raw["id"]),
|
|
103
|
-
layer: pick(raw["layer"], LAYERS) ?? "L1",
|
|
104
|
-
status: pick(raw["status"], STATUSES) ?? "experimental",
|
|
105
|
-
name: localizedOf(raw["name"]),
|
|
106
|
-
why: localizedOf(raw["why"]),
|
|
107
|
-
how_to_fix: localizedOf(raw["how_to_fix"]),
|
|
108
|
-
message: localizedOf(raw["message"]),
|
|
109
|
-
messages: messagesOf(raw["messages"]),
|
|
110
|
-
levels,
|
|
111
|
-
by_genre: genreTables(raw["by_genre"], language),
|
|
112
|
-
how_to_find: String(raw["how_to_find"]),
|
|
113
|
-
word_list: typeof raw["word_list"] === "string" ? raw["word_list"] : undefined,
|
|
114
|
-
extra_word_lists: stringList(raw["extra_word_lists"]) ?? [],
|
|
115
|
-
what_to_check: isLocalized(raw["what_to_check"]) ? raw["what_to_check"] : undefined,
|
|
116
|
-
where: typeof raw["where"] === "string" ? raw["where"] : undefined,
|
|
117
|
-
full_sentence: numberFor(raw["full_sentence"], language),
|
|
118
|
-
requires: stringList(raw["requires"]) ?? [],
|
|
119
|
-
uses: stringList(raw["uses"]) ?? [],
|
|
120
|
-
from: stringList(raw["from"]) ?? [],
|
|
121
|
-
languages: stringList(raw["languages"]),
|
|
122
|
-
use_for: Array.isArray(raw["use_for"]) ? raw["use_for"].map((entry) => String(entry)) : [],
|
|
123
|
-
severity: severityOf(raw["severity"], language),
|
|
124
|
-
};
|
|
151
|
+
return checkedSeverity(ruleOf(raw, levels, levelSetsOf(raw, language, file), language, file), file);
|
|
125
152
|
};
|
|
126
153
|
|
|
154
|
+
const ruleOf = (raw: Record<string, unknown>, levels: LevelTable, levelSets: LevelSets, language: string, file: string): RuleDefinition => ({
|
|
155
|
+
id: String(raw["id"]),
|
|
156
|
+
layer: pick(raw["layer"], LAYERS) ?? "L1",
|
|
157
|
+
status: pick(raw["status"], STATUSES) ?? "experimental",
|
|
158
|
+
name: localizedOf(raw["name"]),
|
|
159
|
+
why: localizedOf(raw["why"]),
|
|
160
|
+
how_to_fix: localizedOf(raw["how_to_fix"]),
|
|
161
|
+
message: localizedOf(raw["message"]),
|
|
162
|
+
messages: localizedByKey(raw["messages"]),
|
|
163
|
+
placeholders: localizedByKey(raw["placeholders"]),
|
|
164
|
+
levels,
|
|
165
|
+
level_sets: levelSets,
|
|
166
|
+
by_genre: genreTables(raw["by_genre"], language),
|
|
167
|
+
other_languages: otherLanguages(raw, language),
|
|
168
|
+
how_to_find: String(raw["how_to_find"]),
|
|
169
|
+
word_list: typeof raw["word_list"] === "string" ? raw["word_list"] : undefined,
|
|
170
|
+
extra_word_lists: stringList(raw["extra_word_lists"]) ?? [],
|
|
171
|
+
what_to_check: isLocalized(raw["what_to_check"]) ? raw["what_to_check"] : undefined,
|
|
172
|
+
where: typeof raw["where"] === "string" ? raw["where"] : undefined,
|
|
173
|
+
full_sentence: numberFor(raw["full_sentence"], language),
|
|
174
|
+
requires: stringList(raw["requires"]) ?? [],
|
|
175
|
+
uses: stringList(raw["uses"]) ?? [],
|
|
176
|
+
from: stringList(raw["from"]) ?? [],
|
|
177
|
+
languages: stringList(raw["languages"]),
|
|
178
|
+
use_for: Array.isArray(raw["use_for"]) ? raw["use_for"].map((entry) => String(entry)) : [],
|
|
179
|
+
severity: severityOf(raw["severity"], language),
|
|
180
|
+
...extrasOf(raw, file),
|
|
181
|
+
guide: ruleGuideOf(raw),
|
|
182
|
+
});
|
|
183
|
+
|
|
127
184
|
/**
|
|
128
185
|
* 読めない rule ファイルは、どれが何で読めないかを言う。
|
|
129
186
|
* yaml の例外をそのまま投げると、スタックトレースだけが出てファイル名が出ない。
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { Localized, OptionValue, RuleOption } from "./plugin.ts";
|
|
2
|
+
|
|
3
|
+
// A rule's options: what its YAML declares, whether a written value fits, and which setting decides each one.
|
|
4
|
+
// Pure: no file is read here. The settings come in as layers, strongest first (chaff.yaml, then a style, then the default).
|
|
5
|
+
|
|
6
|
+
const KINDS: readonly RuleOption["kind"][] = ["choice", "count", "words"];
|
|
7
|
+
|
|
8
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
|
|
10
|
+
const isLocalized = (value: unknown): value is Localized =>
|
|
11
|
+
isRecord(value) && Object.keys(value).length > 0 && Object.values(value).every((entry) => typeof entry === "string" && entry !== "");
|
|
12
|
+
|
|
13
|
+
const isCount = (value: unknown): value is number => typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
14
|
+
|
|
15
|
+
const isWords = (value: unknown): value is string[] => Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.trim() !== "");
|
|
16
|
+
|
|
17
|
+
/** Whether value fits the option: one of the choices, a whole number of 1 or more, or a list of words. */
|
|
18
|
+
export const fitsOption = (option: RuleOption, value: unknown): value is OptionValue => {
|
|
19
|
+
if (option.kind === "count") return isCount(value);
|
|
20
|
+
if (option.kind === "words") return isWords(value);
|
|
21
|
+
return typeof value === "string" && option.choices.includes(value);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** What a value must look like, for a problem message: the choices, or the kind. */
|
|
25
|
+
export const expectedOf = (option: RuleOption): string => (option.kind === "choice" ? option.choices.join(" / ") : option.kind);
|
|
26
|
+
|
|
27
|
+
const kindOf = (raw: Record<string, unknown>, where: string): RuleOption["kind"] => {
|
|
28
|
+
const kind = KINDS.find((entry) => entry === raw["kind"]);
|
|
29
|
+
if (kind === undefined) throw new Error(`${where}: kind must be one of ${KINDS.join(", ")}`);
|
|
30
|
+
return kind;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const choicesOf = (raw: Record<string, unknown>, kind: RuleOption["kind"], where: string): string[] => {
|
|
34
|
+
if (kind !== "choice") return [];
|
|
35
|
+
const choices = raw["choices"];
|
|
36
|
+
if (!isRecord(choices) || Object.keys(choices).length < 2) throw new Error(`${where}: a choice needs two or more choices, each with its meaning`);
|
|
37
|
+
return Object.keys(choices);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const choiceNamesOf = (raw: Record<string, unknown>, where: string): Record<string, Localized> => {
|
|
41
|
+
const choices = raw["choices"];
|
|
42
|
+
if (!isRecord(choices)) return {};
|
|
43
|
+
return Object.fromEntries(
|
|
44
|
+
Object.entries(choices).map(([choice, meaning]) => {
|
|
45
|
+
if (!isLocalized(meaning)) throw new Error(`${where}: choice ${choice} needs its meaning in ja and/or en`);
|
|
46
|
+
return [choice, meaning];
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const optionOf = (name: string, raw: unknown, file: string): RuleOption => {
|
|
52
|
+
const where = `${file}: options.${name}`;
|
|
53
|
+
if (!isRecord(raw)) throw new Error(`${where} must be a map`);
|
|
54
|
+
const kind = kindOf(raw, where);
|
|
55
|
+
const about = raw["about"];
|
|
56
|
+
if (!isLocalized(about)) throw new Error(`${where}: about needs what the option decides, in ja and/or en`);
|
|
57
|
+
const option: RuleOption = {
|
|
58
|
+
kind,
|
|
59
|
+
choices: choicesOf(raw, kind, where),
|
|
60
|
+
default: kind === "words" ? [] : 0,
|
|
61
|
+
about,
|
|
62
|
+
choiceNames: kind === "choice" ? choiceNamesOf(raw, where) : {},
|
|
63
|
+
};
|
|
64
|
+
const fallback: unknown = raw["default"] ?? (kind === "words" ? [] : undefined);
|
|
65
|
+
if (!fitsOption(option, fallback)) throw new Error(`${where}: default must be ${expectedOf(option)}`);
|
|
66
|
+
return { ...option, default: fallback };
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** The options a rule's YAML declares. A wrong declaration is chaff's own bug, so it throws with the file and the option. */
|
|
70
|
+
export const optionsOf = (raw: unknown, file: string): Record<string, RuleOption> => {
|
|
71
|
+
if (raw === undefined) return {};
|
|
72
|
+
if (!isRecord(raw)) throw new Error(`${file}: options must be a map of option names`);
|
|
73
|
+
return Object.fromEntries(Object.entries(raw).map(([name, option]) => [name, optionOf(name, option, file)]));
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** One place settings come from, and what it sets: { rule id: { option: value } }. */
|
|
77
|
+
export type OptionLayer = { readonly from: string; readonly values: Readonly<Record<string, unknown>> };
|
|
78
|
+
|
|
79
|
+
export type SettledOption = { readonly value: OptionValue; readonly from: string };
|
|
80
|
+
|
|
81
|
+
/** The source name of an option left at its default. */
|
|
82
|
+
export const DEFAULT_SOURCE = "default";
|
|
83
|
+
|
|
84
|
+
const optionMap = (layer: OptionLayer, ruleId: string): Readonly<Record<string, unknown>> => {
|
|
85
|
+
const values = layer.values[ruleId];
|
|
86
|
+
return isRecord(values) ? values : {};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Each option of a rule at the value of the strongest layer that sets it with a value that fits, and where that came from.
|
|
91
|
+
* A value that does not fit falls through to the next layer; optionProblems says so, so it is never silent.
|
|
92
|
+
*/
|
|
93
|
+
export const settleOptions = (ruleId: string, options: Readonly<Record<string, RuleOption>>, layers: readonly OptionLayer[]): Record<string, SettledOption> =>
|
|
94
|
+
Object.fromEntries(
|
|
95
|
+
Object.entries(options).map(([name, option]) => {
|
|
96
|
+
const fitting = layers.flatMap((layer): SettledOption[] => {
|
|
97
|
+
const value = optionMap(layer, ruleId)[name];
|
|
98
|
+
return fitsOption(option, value) ? [{ value, from: layer.from }] : [];
|
|
99
|
+
});
|
|
100
|
+
return [name, fitting[0] ?? { value: option.default, from: DEFAULT_SOURCE }];
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
/** The values alone, as the detector gets them. */
|
|
105
|
+
export const optionValues = (settled: Readonly<Record<string, SettledOption>>): Record<string, OptionValue> =>
|
|
106
|
+
Object.fromEntries(Object.entries(settled).map(([name, entry]) => [name, entry.value]));
|
|
107
|
+
|
|
108
|
+
/** What a layer sets that has no effect: an unknown rule, a rule with no options, an unknown option, or a value that does not fit. */
|
|
109
|
+
export type OptionProblem =
|
|
110
|
+
| { readonly kind: "unknown-rule"; readonly rule: string }
|
|
111
|
+
| { readonly kind: "no-options"; readonly rule: string }
|
|
112
|
+
| { readonly kind: "not-a-map"; readonly rule: string }
|
|
113
|
+
| { readonly kind: "unknown-option"; readonly rule: string; readonly option: string; readonly known: readonly string[] }
|
|
114
|
+
| { readonly kind: "bad-value"; readonly rule: string; readonly option: string; readonly value: string; readonly expected: string };
|
|
115
|
+
|
|
116
|
+
const printed = (value: unknown): string => JSON.stringify(value) ?? String(value);
|
|
117
|
+
|
|
118
|
+
const problemsOfRule = (ruleId: string, options: Readonly<Record<string, RuleOption>> | undefined, written: unknown): OptionProblem[] => {
|
|
119
|
+
if (options === undefined) return [{ kind: "unknown-rule", rule: ruleId }];
|
|
120
|
+
if (Object.keys(options).length === 0) return [{ kind: "no-options", rule: ruleId }];
|
|
121
|
+
if (!isRecord(written)) return [{ kind: "not-a-map", rule: ruleId }];
|
|
122
|
+
return Object.entries(written).flatMap(([name, value]): OptionProblem[] => {
|
|
123
|
+
const option = options[name];
|
|
124
|
+
if (option === undefined) return [{ kind: "unknown-option", rule: ruleId, option: name, known: Object.keys(options) }];
|
|
125
|
+
return fitsOption(option, value) ? [] : [{ kind: "bad-value", rule: ruleId, option: name, value: printed(value), expected: expectedOf(option) }];
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/** Every problem in what a layer sets, given each known rule's options (a rule with none maps to {}). */
|
|
130
|
+
export const optionProblems = (layer: OptionLayer, known: Readonly<Record<string, Readonly<Record<string, RuleOption>>>>): OptionProblem[] =>
|
|
131
|
+
Object.entries(layer.values).flatMap(([ruleId, written]) => problemsOfRule(ruleId, known[ruleId], written));
|
package/src/run.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DETECTORS } from "./detectors/index.ts";
|
|
2
|
-
import { resolve } from "./levels.ts";
|
|
3
|
-
import type { AdapterNeeds, Finding, Level, ProseDocument, RuleDefinition } from "./plugin.ts";
|
|
2
|
+
import { resolve, severityAt } from "./levels.ts";
|
|
3
|
+
import type { AdapterNeeds, Detector, DetectorOptions, Finding, Level, ProseDocument, RuleDefinition } from "./plugin.ts";
|
|
4
4
|
import { lineStarts, placeOf } from "./position.ts";
|
|
5
5
|
import { REASONS, type Reasons } from "./reasons.ts";
|
|
6
6
|
import { joinWords } from "./detectors/word-list.ts";
|
|
@@ -11,6 +11,9 @@ import { maskSpans } from "./mask.ts";
|
|
|
11
11
|
import { textOutline } from "./page-furniture.ts";
|
|
12
12
|
import { uiLanguageOf } from "./ui.ts";
|
|
13
13
|
import { presetLevels } from "./genre-load.ts";
|
|
14
|
+
import { bodySectionOf } from "./body-section.ts";
|
|
15
|
+
import { optionValues, settleOptions, type OptionLayer } from "./rule-options.ts";
|
|
16
|
+
import { PatternTimeout } from "./custom/bounded-match.ts";
|
|
14
17
|
|
|
15
18
|
export type Skipped = { readonly rule: string; readonly why: string };
|
|
16
19
|
|
|
@@ -68,7 +71,7 @@ const treeProblem = (doc: ProseDocument): string | undefined => {
|
|
|
68
71
|
|
|
69
72
|
/** 木が読んだのと同じ本文。Markdown はコードを覆ったもの、.txt はページの飾りだけを覆ったもの(.txt の字下げはコードではない)。 */
|
|
70
73
|
const textTheTreeRead = (doc: ProseDocument): string =>
|
|
71
|
-
isMarkdownPath(doc.path) ? (doc.prose ?? doc.source) : maskSpans(doc.source, textOutline(doc.source).opaque);
|
|
74
|
+
isMarkdownPath(doc.path) ? (doc.prose ?? doc.source) : maskSpans(doc.source, textOutline(doc.source, doc.replyQuotes).opaque);
|
|
72
75
|
|
|
73
76
|
const unreadByDocument = new WeakMap<ProseDocument, Unread | undefined>();
|
|
74
77
|
|
|
@@ -78,6 +81,15 @@ const unreadOf = (doc: ProseDocument): Unread | undefined => {
|
|
|
78
81
|
return unreadByDocument.get(doc);
|
|
79
82
|
};
|
|
80
83
|
|
|
84
|
+
/** 見出しを読む rule の要求。表題より下の見出しが無い文書では、本題の前を測れない。0 件を「前置きが短い」に見せない。 */
|
|
85
|
+
/** 記法を読む rule の要求(markdown)。.txt には見出しの記法も画像もリンクの記法も無いので、0 件を「問題なし」に見せない。 */
|
|
86
|
+
const DOCUMENT_NEEDS: ReadonlySet<string> = new Set(["headings", "markdown"]);
|
|
87
|
+
|
|
88
|
+
const documentNeed = (rule: RuleDefinition, doc: ProseDocument): string | undefined => {
|
|
89
|
+
if (rule.requires.includes("markdown") && !isMarkdownPath(doc.path)) return reasonsFor(doc).notMarkdown;
|
|
90
|
+
return rule.requires.includes("headings") && bodySectionOf(doc.sections) === undefined ? reasonsFor(doc).noHeadings : undefined;
|
|
91
|
+
};
|
|
92
|
+
|
|
81
93
|
/** 知らない要求は満たされていないものとして扱う。黙って無視すると、要求なしで動いてしまう。 */
|
|
82
94
|
const has = (capabilities: ProseDocument["capabilities"], need: string): boolean => {
|
|
83
95
|
if (need === "pos") return capabilities.pos;
|
|
@@ -97,7 +109,7 @@ const hasTokens = (doc: ProseDocument): boolean => doc.sentences.length === 0 ||
|
|
|
97
109
|
/** 要求を満たさない rule は動かせない。満たさないまま動かすと「指摘 0 件」が保証に見える。 */
|
|
98
110
|
const unmet = (rule: RuleDefinition, doc: ProseDocument): string | undefined => {
|
|
99
111
|
if (rule.languages !== undefined && !rule.languages.includes(doc.language)) return reasonsFor(doc).otherLanguage(doc.language);
|
|
100
|
-
const missing = rule.requires.filter((need) => !TREE_NEEDS.has(need)).find((need) => !has(doc.capabilities, need));
|
|
112
|
+
const missing = rule.requires.filter((need) => !TREE_NEEDS.has(need) && !DOCUMENT_NEEDS.has(need)).find((need) => !has(doc.capabilities, need));
|
|
101
113
|
if (missing !== undefined) return reasonsFor(doc).noCapability(missing);
|
|
102
114
|
return undefined;
|
|
103
115
|
};
|
|
@@ -119,12 +131,29 @@ export const wantsTags = (rule: RuleDefinition): boolean => [...rule.requires, .
|
|
|
119
131
|
* 解析器の初期化に払う代金を決める。動く rule が 1 本も要求しないなら読み込まない。
|
|
120
132
|
* capabilities は「払えばできる」の宣言なので、ここでは見ない。
|
|
121
133
|
*/
|
|
122
|
-
export const neededBy = (rules: readonly RuleDefinition[], settings: Settings, experimental: boolean, genre: string, language: string): AdapterNeeds =>
|
|
123
|
-
|
|
134
|
+
export const neededBy = (rules: readonly RuleDefinition[], settings: Settings, experimental: boolean, genre: string, language: string): AdapterNeeds => {
|
|
135
|
+
const running = forGenre(rules, genre)
|
|
124
136
|
.filter((rule) => rule.layer !== "L4" && levelFor(rule, settings, experimental, presetLevels(genre)) !== "off")
|
|
125
|
-
.filter((rule) => rule.languages === undefined || rule.languages.includes(language))
|
|
126
|
-
|
|
127
|
-
}
|
|
137
|
+
.filter((rule) => rule.languages === undefined || rule.languages.includes(language));
|
|
138
|
+
return { pos: running.some(wantsTags), features: tokenFeaturesOf(running) };
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** The token features the rules read (RuleDefinition.token_features), each once. */
|
|
142
|
+
export const tokenFeaturesOf = (rules: readonly RuleDefinition[]): string[] => [...new Set(rules.flatMap((rule) => rule.token_features ?? []))];
|
|
143
|
+
|
|
144
|
+
/** A detector's findings, or how long it ran before a team's pattern was stopped (bounded-match.ts). Other errors are chaff's bugs and propagate. */
|
|
145
|
+
const runDetector = (
|
|
146
|
+
detector: Detector,
|
|
147
|
+
doc: ProseDocument,
|
|
148
|
+
options: DetectorOptions,
|
|
149
|
+
): { readonly findings: readonly Finding[] } | { readonly timedOut: number } => {
|
|
150
|
+
try {
|
|
151
|
+
return { findings: detector(doc, options) };
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof PatternTimeout) return { timedOut: error.budget_ms };
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
128
157
|
|
|
129
158
|
const place = (starts: readonly number[], finding: Finding): Finding => {
|
|
130
159
|
const offset = finding.values["offset"];
|
|
@@ -160,6 +189,29 @@ export type Limits = Readonly<Record<string, number>>;
|
|
|
160
189
|
|
|
161
190
|
const limitFor = (rule: RuleDefinition, level: Level, genre: string, limits: Limits): number => limits[rule.id] ?? resolve(rule, level, genre).limit;
|
|
162
191
|
|
|
192
|
+
/** 文書と違う言語で書いた文の上限。chaff.yaml の数値は文書の言語の単位で書いたものなので、ここには効かせない。 */
|
|
193
|
+
const embeddedLimitsFor = (rule: RuleDefinition, level: Level, genre: string, embedded: readonly string[]): Record<string, number> =>
|
|
194
|
+
Object.fromEntries(
|
|
195
|
+
embedded.flatMap((language) => {
|
|
196
|
+
const tables = rule.other_languages?.[language];
|
|
197
|
+
return tables === undefined ? [] : [[language, resolve({ ...rule, ...tables }, level, genre).limit] as const];
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const embeddedLanguagesOf = (doc: ProseDocument): string[] => [
|
|
202
|
+
...new Set(doc.sentences.flatMap((sentence) => (sentence.embeddedLanguage === undefined ? [] : [sentence.embeddedLanguage.id]))),
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
/** What a run is set to: the levels chaff.yaml names, whether experimental rules run, the genre, and the numbers and options set. */
|
|
206
|
+
export type RunContext = {
|
|
207
|
+
readonly settings: Settings;
|
|
208
|
+
readonly experimental: boolean;
|
|
209
|
+
readonly genre: string;
|
|
210
|
+
readonly limits?: Limits;
|
|
211
|
+
/** Where rule options come from, strongest first (chaff.yaml). An option no layer sets is at its default. */
|
|
212
|
+
readonly optionLayers?: readonly OptionLayer[];
|
|
213
|
+
};
|
|
214
|
+
|
|
163
215
|
export const runRules = (
|
|
164
216
|
doc: ProseDocument,
|
|
165
217
|
rules: readonly RuleDefinition[],
|
|
@@ -167,10 +219,14 @@ export const runRules = (
|
|
|
167
219
|
experimental: boolean,
|
|
168
220
|
genre: string,
|
|
169
221
|
limits: Limits = {},
|
|
170
|
-
): RunResult => {
|
|
222
|
+
): RunResult => runRulesWith(doc, rules, { settings, experimental, genre, limits });
|
|
223
|
+
|
|
224
|
+
export const runRulesWith = (doc: ProseDocument, rules: readonly RuleDefinition[], context: RunContext): RunResult => {
|
|
225
|
+
const { settings, experimental, genre, limits = {}, optionLayers = [] } = context;
|
|
171
226
|
const preset = presetLevels(genre);
|
|
172
227
|
const starts = lineStarts(doc.source);
|
|
173
228
|
const applicable = forGenre(rules, genre);
|
|
229
|
+
const embedded = embeddedLanguagesOf(doc);
|
|
174
230
|
const experimentalOn = applicable.filter((rule) => rule.status === "experimental" && levelFor(rule, settings, experimental, preset) !== "off");
|
|
175
231
|
const forced = experimentalOn.filter((rule) => settings[rule.id] !== undefined).map((rule) => rule.id);
|
|
176
232
|
const presetOn = experimentalOn.filter((rule) => settings[rule.id] === undefined && preset[rule.id] !== undefined).map((rule) => rule.id);
|
|
@@ -191,6 +247,8 @@ export const runRules = (
|
|
|
191
247
|
// 段階を見た後で聞く。doc.structure は触れたときに木を作るので、止めている rule のために作らない。
|
|
192
248
|
const noTree = treeNeed(rule, doc);
|
|
193
249
|
if (noTree !== undefined) return { findings: acc.findings, skipped: [...acc.skipped, { rule: rule.id, why: noTree }] };
|
|
250
|
+
const noDocumentNeed = documentNeed(rule, doc);
|
|
251
|
+
if (noDocumentNeed !== undefined) return { findings: acc.findings, skipped: [...acc.skipped, { rule: rule.id, why: noDocumentNeed }] };
|
|
194
252
|
// 複合シグナルは二段目で扱う。一段目では「検出器が無い」と言わせない。
|
|
195
253
|
if (rule.from.length > 0) return acc;
|
|
196
254
|
const detector = DETECTORS[rule.how_to_find];
|
|
@@ -205,8 +263,13 @@ export const runRules = (
|
|
|
205
263
|
lexicon: rule.word_list === undefined ? undefined : doc.lexicons[rule.word_list],
|
|
206
264
|
where: rule.where,
|
|
207
265
|
fullSentence: rule.full_sentence,
|
|
266
|
+
embeddedLimits: embeddedLimitsFor(rule, level, genre, embedded),
|
|
267
|
+
...(rule.options === undefined ? {} : { settings: optionValues(settleOptions(rule.id, rule.options, optionLayers)) }),
|
|
268
|
+
...(rule.custom === undefined ? {} : { custom: rule.custom }),
|
|
208
269
|
};
|
|
209
|
-
const
|
|
270
|
+
const ran = runDetector(detector, doc, options);
|
|
271
|
+
if ("timedOut" in ran) return { findings: acc.findings, skipped: [...acc.skipped, { rule: rule.id, why: reasonsFor(doc).patternTimeout(ran.timedOut) }] };
|
|
272
|
+
const found = ran.findings.map((finding) => place(starts, { ...finding, rule: rule.id, severity: severityAt(rule, level, genre) }));
|
|
210
273
|
return { findings: [...acc.findings, ...found], skipped: acc.skipped };
|
|
211
274
|
},
|
|
212
275
|
{ findings: [], skipped: [] },
|
package/src/sentence-shape.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Sentence, Token } from "./plugin.ts";
|
|
2
|
+
import { ownEnd } from "./trailing-aside.ts";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 「これは文か」の判定を 1 箇所に置く。
|
|
@@ -21,13 +22,11 @@ const SKIP = new Set(["PUNCT", "PART", "SYM"]);
|
|
|
21
22
|
* 「これを最優先制約とする(§17)。」の述語は「とする」であって「17」ではない。
|
|
22
23
|
* 仕様書は相互参照を括弧で添えるので、これを数えると文末が全部そこになる。
|
|
23
24
|
*/
|
|
24
|
-
const TRAILING = /[((][^((]*[))][\s。.!?!?]*$/u;
|
|
25
|
-
|
|
26
25
|
const beforeTrailing = (sentence: Sentence): readonly Token[] => {
|
|
27
26
|
const tokens = sentence.tokens ?? [];
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
const cut = sentence.span.start +
|
|
27
|
+
const end = ownEnd(sentence.text);
|
|
28
|
+
if (end === sentence.text.length) return tokens;
|
|
29
|
+
const cut = sentence.span.start + end;
|
|
31
30
|
const kept = tokens.filter((token) => token.span.end <= cut);
|
|
32
31
|
// 括弧を外したら何も残らない文は、括弧そのものが中身。そのまま見る。
|
|
33
32
|
return kept.length === 0 ? tokens : kept;
|
package/src/setting-problems.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Config } from "./config/load.ts";
|
|
2
2
|
import type { CliText } from "./cli-text.ts";
|
|
3
|
+
import type { UiLanguage } from "./ui.ts";
|
|
4
|
+
import { styleProblems } from "./config/style.ts";
|
|
5
|
+
import { loadStyles } from "./style-load.ts";
|
|
6
|
+
import { customRuleProblems } from "./custom/problems.ts";
|
|
3
7
|
import { GENRES } from "./genre.ts";
|
|
4
8
|
import { unknownGenres, writtenGenres } from "./genre-check.ts";
|
|
5
9
|
import { loadProfiles } from "./profile/load.ts";
|
|
@@ -18,7 +22,9 @@ const profileProblems = (command: string, config: Config, text: CliText): string
|
|
|
18
22
|
};
|
|
19
23
|
|
|
20
24
|
/** Settings that name something chaff does not have. Each would silently check less than was asked, so the run stops on them. */
|
|
21
|
-
export const settingProblems = (command: string, genreFlag: string | undefined, config: Config, text: CliText): string[] => [
|
|
25
|
+
export const settingProblems = (command: string, genreFlag: string | undefined, config: Config, text: CliText, ui: UiLanguage = "en"): string[] => [
|
|
22
26
|
...genreProblems(command, genreFlag, config, text),
|
|
23
27
|
...profileProblems(command, config, text),
|
|
28
|
+
...styleProblems(config, loadStyles(), ui),
|
|
29
|
+
...customRuleProblems(config, ui),
|
|
24
30
|
];
|
package/src/span-cut.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Span } from "./plugin.ts";
|
|
2
|
+
import { mergeSpans } from "./span-merge.ts";
|
|
3
|
+
import { firstEndingAfter } from "./soft-break.ts";
|
|
4
|
+
|
|
5
|
+
const piecesOutside = (span: Span, sortedCuts: readonly Span[]): Span[] => {
|
|
6
|
+
const overlapping = sortedCuts
|
|
7
|
+
.slice(firstEndingAfter(sortedCuts, span.start), firstEndingAfter(sortedCuts, span.end) + 1)
|
|
8
|
+
.filter((cut) => cut.start < span.end);
|
|
9
|
+
const { pieces, cursor } = overlapping.reduce<{ pieces: Span[]; cursor: number }>(
|
|
10
|
+
(acc, cut) => ({
|
|
11
|
+
pieces: cut.start > acc.cursor ? [...acc.pieces, { start: acc.cursor, end: cut.start }] : acc.pieces,
|
|
12
|
+
cursor: Math.max(acc.cursor, cut.end),
|
|
13
|
+
}),
|
|
14
|
+
{ pieces: [], cursor: span.start },
|
|
15
|
+
);
|
|
16
|
+
return cursor < span.end ? [...pieces, { start: cursor, end: span.end }] : pieces;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** The parts of each span that no cut covers, in order. Cuts may overlap one another and come in any order. */
|
|
20
|
+
export const cutSpans = (spans: readonly Span[], cuts: readonly Span[]): Span[] => {
|
|
21
|
+
if (cuts.length === 0) return [...spans];
|
|
22
|
+
const sortedCuts = mergeSpans(cuts, true);
|
|
23
|
+
return spans.flatMap((span) => piecesOutside(span, sortedCuts));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** cutSpans, less the pieces of `source` that hold only white space. */
|
|
27
|
+
export const cutTextSpans = (spans: readonly Span[], cuts: readonly Span[], source: string): Span[] =>
|
|
28
|
+
cuts.length === 0 ? [...spans] : cutSpans(spans, cuts).filter((piece) => source.slice(piece.start, piece.end).trim() !== "");
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { RelativeVocabulary } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
type Aside = RelativeVocabulary["aside"];
|
|
4
|
+
|
|
5
|
+
/** 文字と、その位置(UTF-16 の単位で)。絵文字のような 2 単位の文字も 1 文字として読む。 */
|
|
6
|
+
export const characters = (text: string): { readonly char: string; readonly at: number }[] => {
|
|
7
|
+
const found: { char: string; at: number }[] = [];
|
|
8
|
+
let at = 0;
|
|
9
|
+
for (const char of text) {
|
|
10
|
+
found.push({ char, at });
|
|
11
|
+
at += char.length;
|
|
12
|
+
}
|
|
13
|
+
return found;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** at の位置で開いたままの括弧書きの開きの位置。text の頭から at まで読む。 */
|
|
17
|
+
export const openAsidesAt = (text: string, at: number, aside: Aside): number[] => {
|
|
18
|
+
const opens: number[] = [];
|
|
19
|
+
if (aside === undefined) return opens;
|
|
20
|
+
characters(text.slice(0, at)).forEach(({ char, at: position }) => {
|
|
21
|
+
if (char === aside.open) opens.push(position);
|
|
22
|
+
if (char === aside.close) opens.pop();
|
|
23
|
+
});
|
|
24
|
+
return opens;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** at で開いたままの括弧書きの数(depth)と、一番内側の開きの位置(innermost)。 */
|
|
28
|
+
export type AsideDepth = { readonly depth: (at: number) => number; readonly innermost: (at: number) => number | undefined };
|
|
29
|
+
|
|
30
|
+
/** 文字の切れ目でない位置(2 単位の文字の途中)の印。 */
|
|
31
|
+
const UNREAD = -2;
|
|
32
|
+
const NO_OPEN = -1;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 本文を一度だけ読み、文字の切れ目ごとに openAsidesAt の答えを覚える。参照ごとに頭から読み直すと、参照の数と行の長さの積になる。
|
|
36
|
+
* 覚えていない位置(2 単位の文字の途中)は openAsidesAt で読む。
|
|
37
|
+
*/
|
|
38
|
+
export const asideDepth = (text: string, aside: Aside): AsideDepth => {
|
|
39
|
+
if (aside === undefined) return { depth: () => 0, innermost: () => undefined };
|
|
40
|
+
const depths = new Int32Array(text.length + 1).fill(UNREAD);
|
|
41
|
+
const innermosts = new Int32Array(text.length + 1).fill(UNREAD);
|
|
42
|
+
const opens: number[] = [];
|
|
43
|
+
depths[0] = 0;
|
|
44
|
+
innermosts[0] = NO_OPEN;
|
|
45
|
+
characters(text).forEach(({ char, at }) => {
|
|
46
|
+
if (char === aside.open) opens.push(at);
|
|
47
|
+
if (char === aside.close) opens.pop();
|
|
48
|
+
depths[at + char.length] = opens.length;
|
|
49
|
+
innermosts[at + char.length] = opens.at(-1) ?? NO_OPEN;
|
|
50
|
+
});
|
|
51
|
+
// text.slice(0, at) が切る位置。負の数は後ろから数え、本文の外は端に寄せる。文字の途中なら覚えていない。
|
|
52
|
+
const cut = (at: number): number => {
|
|
53
|
+
const whole = Math.trunc(Number.isNaN(at) ? 0 : at);
|
|
54
|
+
return whole < 0 ? Math.max(text.length + whole, 0) : Math.min(whole, text.length);
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
depth: (at) => {
|
|
58
|
+
const depth = depths[cut(at)] ?? UNREAD;
|
|
59
|
+
return depth === UNREAD ? openAsidesAt(text, at, aside).length : depth;
|
|
60
|
+
},
|
|
61
|
+
innermost: (at) => {
|
|
62
|
+
const open = innermosts[cut(at)] ?? UNREAD;
|
|
63
|
+
if (open === UNREAD) return openAsidesAt(text, at, aside).at(-1);
|
|
64
|
+
return open === NO_OPEN ? undefined : open;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
};
|