chaffjs 0.17.0 → 0.19.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/README.md +52 -56
- package/bin/chaff.js +17 -2
- package/dist/acronym-expansions.d.ts +26 -0
- package/dist/acronym-expansions.d.ts.map +1 -0
- package/dist/acronym-expansions.js +88 -0
- package/dist/acronym-expansions.js.map +1 -0
- package/dist/announced-count.d.ts +26 -0
- package/dist/announced-count.d.ts.map +1 -0
- package/dist/announced-count.js +138 -0
- package/dist/announced-count.js.map +1 -0
- package/dist/announced-list.d.ts +30 -0
- package/dist/announced-list.d.ts.map +1 -0
- package/dist/announced-list.js +95 -0
- package/dist/announced-list.js.map +1 -0
- package/dist/api.d.ts +168 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +10 -0
- package/dist/api.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 +0 -1
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +14 -18
- package/dist/cli-text.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +83 -84
- package/dist/cli.js.map +1 -1
- package/dist/closing-paragraph.d.ts +7 -0
- package/dist/closing-paragraph.d.ts.map +1 -0
- package/dist/closing-paragraph.js +22 -0
- package/dist/closing-paragraph.js.map +1 -0
- package/dist/commands/compare.d.ts +15 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +64 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/document-commands.d.ts +9 -0
- package/dist/commands/document-commands.d.ts.map +1 -0
- package/dist/commands/document-commands.js +17 -0
- package/dist/commands/document-commands.js.map +1 -0
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +19 -10
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/facts.d.ts +8 -0
- package/dist/commands/facts.d.ts.map +1 -0
- package/dist/commands/facts.js +30 -0
- package/dist/commands/facts.js.map +1 -0
- package/dist/commands/feedback.d.ts +15 -2
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +36 -6
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/fix-plan.d.ts +13 -0
- package/dist/commands/fix-plan.d.ts.map +1 -0
- package/dist/commands/fix-plan.js +44 -0
- package/dist/commands/fix-plan.js.map +1 -0
- package/dist/commands/outline.d.ts +8 -0
- package/dist/commands/outline.d.ts.map +1 -0
- package/dist/commands/outline.js +43 -0
- package/dist/commands/outline.js.map +1 -0
- package/dist/commands/read-document.d.ts +14 -0
- package/dist/commands/read-document.d.ts.map +1 -0
- package/dist/commands/read-document.js +21 -0
- package/dist/commands/read-document.js.map +1 -0
- package/dist/commands/suppressions.d.ts +7 -0
- package/dist/commands/suppressions.d.ts.map +1 -0
- package/dist/commands/suppressions.js +9 -0
- package/dist/commands/suppressions.js.map +1 -0
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +3 -5
- 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 +68 -0
- package/dist/compare/clock-time.js.map +1 -0
- package/dist/compare/distinct.d.ts +9 -0
- package/dist/compare/distinct.d.ts.map +1 -0
- package/dist/compare/distinct.js +12 -0
- package/dist/compare/distinct.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 +60 -0
- package/dist/compare/extract.js.map +1 -0
- package/dist/compare/fact-key.d.ts +17 -0
- package/dist/compare/fact-key.d.ts.map +1 -0
- package/dist/compare/fact-key.js +25 -0
- package/dist/compare/fact-key.js.map +1 -0
- package/dist/compare/fact-text.d.ts +28 -0
- package/dist/compare/fact-text.d.ts.map +1 -0
- package/dist/compare/fact-text.js +61 -0
- package/dist/compare/fact-text.js.map +1 -0
- package/dist/compare/facts-render.d.ts +17 -0
- package/dist/compare/facts-render.d.ts.map +1 -0
- package/dist/compare/facts-render.js +43 -0
- package/dist/compare/facts-render.js.map +1 -0
- package/dist/compare/facts-text.d.ts +15 -0
- package/dist/compare/facts-text.d.ts.map +1 -0
- package/dist/compare/facts-text.js +27 -0
- package/dist/compare/facts-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 +20 -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 +36 -0
- package/dist/compare/outcome.d.ts.map +1 -0
- package/dist/compare/outcome.js +46 -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 +43 -0
- package/dist/compare/proper-nouns.js.map +1 -0
- package/dist/compare/render.d.ts +13 -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 +27 -0
- package/dist/compare/text-atoms.d.ts.map +1 -0
- package/dist/compare/text-atoms.js +69 -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 +23 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +6 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/option-problems.d.ts +17 -0
- package/dist/config/option-problems.d.ts.map +1 -0
- package/dist/config/option-problems.js +59 -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 +21 -0
- package/dist/config/style.d.ts.map +1 -0
- package/dist/config/style.js +48 -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 +11 -0
- package/dist/custom/load.d.ts.map +1 -0
- package/dist/custom/load.js +19 -0
- package/dist/custom/load.js.map +1 -0
- package/dist/custom/module-path.d.ts +11 -0
- package/dist/custom/module-path.d.ts.map +1 -0
- package/dist/custom/module-path.js +15 -0
- package/dist/custom/module-path.js.map +1 -0
- package/dist/custom/parse.d.ts +84 -0
- package/dist/custom/parse.d.ts.map +1 -0
- package/dist/custom/parse.js +258 -0
- package/dist/custom/parse.js.map +1 -0
- package/dist/custom/problems.d.ts +8 -0
- package/dist/custom/problems.d.ts.map +1 -0
- package/dist/custom/problems.js +95 -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-language.js +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +30 -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 +23 -0
- package/dist/detectors/ai-phrasing.d.ts.map +1 -0
- package/dist/detectors/ai-phrasing.js +116 -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/bold-label.d.ts +10 -0
- package/dist/detectors/bold-label.d.ts.map +1 -0
- package/dist/detectors/bold-label.js +44 -0
- package/dist/detectors/bold-label.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 +7 -0
- package/dist/detectors/dangling-figure.d.ts.map +1 -0
- package/dist/detectors/dangling-figure.js +20 -0
- package/dist/detectors/dangling-figure.js.map +1 -0
- package/dist/detectors/definition-use.d.ts +8 -0
- package/dist/detectors/definition-use.d.ts.map +1 -0
- package/dist/detectors/definition-use.js +32 -0
- package/dist/detectors/definition-use.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 +35 -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/duplicate-heading.d.ts +14 -0
- package/dist/detectors/duplicate-heading.d.ts.map +1 -0
- package/dist/detectors/duplicate-heading.js +39 -0
- package/dist/detectors/duplicate-heading.js.map +1 -0
- package/dist/detectors/empty-section.d.ts +8 -0
- package/dist/detectors/empty-section.d.ts.map +1 -0
- package/dist/detectors/empty-section.js +16 -0
- package/dist/detectors/empty-section.js.map +1 -0
- 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/fullwidth-alnum.d.ts +24 -0
- package/dist/detectors/fullwidth-alnum.d.ts.map +1 -0
- package/dist/detectors/fullwidth-alnum.js +88 -0
- package/dist/detectors/fullwidth-alnum.js.map +1 -0
- 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/hankaku-kana.d.ts +9 -0
- package/dist/detectors/hankaku-kana.d.ts.map +1 -0
- package/dist/detectors/hankaku-kana.js +27 -0
- package/dist/detectors/hankaku-kana.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 +70 -1
- package/dist/detectors/index.js.map +1 -1
- package/dist/detectors/invisible-character.d.ts +20 -0
- package/dist/detectors/invisible-character.d.ts.map +1 -0
- package/dist/detectors/invisible-character.js +143 -0
- package/dist/detectors/invisible-character.js.map +1 -0
- 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 +14 -1
- package/dist/detectors/lexicon-match.d.ts.map +1 -1
- package/dist/detectors/lexicon-match.js +32 -2
- package/dist/detectors/lexicon-match.js.map +1 -1
- package/dist/detectors/lexicon.d.ts +6 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +31 -13
- package/dist/detectors/lexicon.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 +67 -0
- package/dist/detectors/list-sentence.d.ts.map +1 -0
- package/dist/detectors/list-sentence.js +130 -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 +71 -0
- package/dist/detectors/long-vowel.js.map +1 -0
- package/dist/detectors/markup-finding.d.ts +8 -0
- package/dist/detectors/markup-finding.d.ts.map +1 -0
- package/dist/detectors/markup-finding.js +29 -0
- package/dist/detectors/markup-finding.js.map +1 -0
- package/dist/detectors/modal-conflict.d.ts +4 -0
- package/dist/detectors/modal-conflict.d.ts.map +1 -0
- package/dist/detectors/modal-conflict.js +22 -0
- package/dist/detectors/modal-conflict.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/name-variant.d.ts +4 -0
- package/dist/detectors/name-variant.d.ts.map +1 -0
- package/dist/detectors/name-variant.js +13 -0
- package/dist/detectors/name-variant.js.map +1 -0
- package/dist/detectors/nominalization.d.ts +11 -0
- package/dist/detectors/nominalization.d.ts.map +1 -0
- package/dist/detectors/nominalization.js +56 -0
- package/dist/detectors/nominalization.js.map +1 -0
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +72 -37
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/outside-announced-list.d.ts +4 -0
- package/dist/detectors/outside-announced-list.d.ts.map +1 -0
- package/dist/detectors/outside-announced-list.js +24 -0
- package/dist/detectors/outside-announced-list.js.map +1 -0
- 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 +136 -229
- package/dist/detectors/oxford-comma.js.map +1 -1
- package/dist/detectors/phrase-match.d.ts +4 -1
- package/dist/detectors/phrase-match.d.ts.map +1 -1
- package/dist/detectors/phrase-match.js +26 -7
- package/dist/detectors/phrase-match.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/ra-nuki.d.ts +9 -0
- package/dist/detectors/ra-nuki.d.ts.map +1 -0
- package/dist/detectors/ra-nuki.js +30 -0
- package/dist/detectors/ra-nuki.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/requirement-modal.d.ts +5 -0
- package/dist/detectors/requirement-modal.d.ts.map +1 -0
- package/dist/detectors/requirement-modal.js +54 -0
- package/dist/detectors/requirement-modal.js.map +1 -0
- package/dist/detectors/requirement-smell.d.ts +4 -0
- package/dist/detectors/requirement-smell.d.ts.map +1 -0
- package/dist/detectors/requirement-smell.js +41 -0
- package/dist/detectors/requirement-smell.js.map +1 -0
- 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/space-before-punctuation.d.ts +8 -0
- package/dist/detectors/space-before-punctuation.d.ts.map +1 -0
- package/dist/detectors/space-before-punctuation.js +24 -0
- package/dist/detectors/space-before-punctuation.js.map +1 -0
- package/dist/detectors/spelling-variety.d.ts +23 -0
- package/dist/detectors/spelling-variety.d.ts.map +1 -0
- package/dist/detectors/spelling-variety.js +59 -0
- package/dist/detectors/spelling-variety.js.map +1 -0
- 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 +39 -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 +19 -6
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/superlative-comparison.d.ts +20 -0
- package/dist/detectors/superlative-comparison.d.ts.map +1 -0
- package/dist/detectors/superlative-comparison.js +32 -0
- package/dist/detectors/superlative-comparison.js.map +1 -0
- 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 +24 -0
- package/dist/detectors/url-run-on.js.map +1 -0
- package/dist/detectors/vague-figure-pointer.d.ts +10 -0
- package/dist/detectors/vague-figure-pointer.d.ts.map +1 -0
- package/dist/detectors/vague-figure-pointer.js +46 -0
- package/dist/detectors/vague-figure-pointer.js.map +1 -0
- package/dist/detectors/word-list.d.ts +2 -0
- package/dist/detectors/word-list.d.ts.map +1 -1
- package/dist/detectors/word-list.js +4 -1
- package/dist/detectors/word-list.js.map +1 -1
- 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 +20 -7
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +140 -125
- 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/extension/document-view.d.ts +7 -0
- package/dist/extension/document-view.d.ts.map +1 -0
- package/dist/extension/document-view.js +91 -0
- package/dist/extension/document-view.js.map +1 -0
- package/dist/extension/failure-text.d.ts +5 -0
- package/dist/extension/failure-text.d.ts.map +1 -0
- package/dist/extension/failure-text.js +33 -0
- package/dist/extension/failure-text.js.map +1 -0
- package/dist/extension/import-default.d.ts +7 -0
- package/dist/extension/import-default.d.ts.map +1 -0
- package/dist/extension/import-default.js +21 -0
- package/dist/extension/import-default.js.map +1 -0
- package/dist/extension/load.d.ts +28 -0
- package/dist/extension/load.d.ts.map +1 -0
- package/dist/extension/load.js +51 -0
- package/dist/extension/load.js.map +1 -0
- package/dist/extension/module-detector.d.ts +21 -0
- package/dist/extension/module-detector.d.ts.map +1 -0
- package/dist/extension/module-detector.js +49 -0
- package/dist/extension/module-detector.js.map +1 -0
- package/dist/extension/plugin-load.d.ts +9 -0
- package/dist/extension/plugin-load.d.ts.map +1 -0
- package/dist/extension/plugin-load.js +68 -0
- package/dist/extension/plugin-load.js.map +1 -0
- package/dist/extension/plugin-name.d.ts +8 -0
- package/dist/extension/plugin-name.d.ts.map +1 -0
- package/dist/extension/plugin-name.js +22 -0
- package/dist/extension/plugin-name.js.map +1 -0
- package/dist/extension/plugin-parse.d.ts +41 -0
- package/dist/extension/plugin-parse.d.ts.map +1 -0
- package/dist/extension/plugin-parse.js +156 -0
- package/dist/extension/plugin-parse.js.map +1 -0
- package/dist/extension/problem-text.d.ts +5 -0
- package/dist/extension/problem-text.d.ts.map +1 -0
- package/dist/extension/problem-text.js +74 -0
- package/dist/extension/problem-text.js.map +1 -0
- package/dist/extension/real-path.d.ts +3 -0
- package/dist/extension/real-path.d.ts.map +1 -0
- package/dist/extension/real-path.js +8 -0
- package/dist/extension/real-path.js.map +1 -0
- package/dist/extension/returned-findings.d.ts +17 -0
- package/dist/extension/returned-findings.d.ts.map +1 -0
- package/dist/extension/returned-findings.js +48 -0
- package/dist/extension/returned-findings.js.map +1 -0
- package/dist/extension/rule-export.d.ts +13 -0
- package/dist/extension/rule-export.d.ts.map +1 -0
- package/dist/extension/rule-export.js +16 -0
- package/dist/extension/rule-export.js.map +1 -0
- package/dist/feedback/draft.d.ts +2 -0
- package/dist/feedback/draft.d.ts.map +1 -1
- package/dist/feedback/draft.js +3 -0
- package/dist/feedback/draft.js.map +1 -1
- package/dist/figure-references.d.ts +39 -0
- package/dist/figure-references.d.ts.map +1 -0
- package/dist/figure-references.js +113 -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/finding-order.d.ts +9 -0
- package/dist/finding-order.d.ts.map +1 -0
- package/dist/finding-order.js +3 -0
- package/dist/finding-order.js.map +1 -0
- package/dist/fix-plan/mode.d.ts +21 -0
- package/dist/fix-plan/mode.d.ts.map +1 -0
- package/dist/fix-plan/mode.js +16 -0
- package/dist/fix-plan/mode.js.map +1 -0
- package/dist/fix-plan/plan.d.ts +77 -0
- package/dist/fix-plan/plan.d.ts.map +1 -0
- package/dist/fix-plan/plan.js +100 -0
- package/dist/fix-plan/plan.js.map +1 -0
- package/dist/fix-plan/render.d.ts +6 -0
- package/dist/fix-plan/render.d.ts.map +1 -0
- package/dist/fix-plan/render.js +101 -0
- package/dist/fix-plan/render.js.map +1 -0
- package/dist/fix-plan/text.d.ts +35 -0
- package/dist/fix-plan/text.d.ts.map +1 -0
- package/dist/fix-plan/text.js +95 -0
- package/dist/fix-plan/text.js.map +1 -0
- 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/language-sample.d.ts +2 -0
- package/dist/language-sample.d.ts.map +1 -0
- package/dist/language-sample.js +41 -0
- package/dist/language-sample.js.map +1 -0
- 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/link-line.d.ts +8 -0
- package/dist/link-line.d.ts.map +1 -0
- package/dist/link-line.js +12 -0
- package/dist/link-line.js.map +1 -0
- package/dist/long-vowel.d.ts +38 -0
- package/dist/long-vowel.d.ts.map +1 -0
- package/dist/long-vowel.js +78 -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 +182 -0
- package/dist/markup.js.map +1 -0
- package/dist/mask.js +8 -5
- package/dist/mask.js.map +1 -1
- package/dist/name-variants.d.ts +25 -0
- package/dist/name-variants.d.ts.map +1 -0
- package/dist/name-variants.js +181 -0
- package/dist/name-variants.js.map +1 -0
- package/dist/node-version.d.ts +7 -0
- package/dist/node-version.d.ts.map +1 -0
- package/dist/node-version.js +19 -0
- package/dist/node-version.js.map +1 -0
- package/dist/not-run.d.ts +14 -0
- package/dist/not-run.d.ts.map +1 -0
- package/dist/not-run.js +12 -0
- package/dist/not-run.js.map +1 -0
- 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 +10 -1
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +42 -16
- package/dist/orthography.js.map +1 -1
- package/dist/outline/render.d.ts +18 -0
- package/dist/outline/render.d.ts.map +1 -0
- package/dist/outline/render.js +60 -0
- package/dist/outline/render.js.map +1 -0
- package/dist/outline/shape.d.ts +26 -0
- package/dist/outline/shape.d.ts.map +1 -0
- package/dist/outline/shape.js +37 -0
- package/dist/outline/shape.js.map +1 -0
- package/dist/outline/text.d.ts +21 -0
- package/dist/outline/text.d.ts.map +1 -0
- package/dist/outline/text.js +30 -0
- package/dist/outline/text.js.map +1 -0
- 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 +138 -1
- 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 +4 -0
- package/dist/reasons.d.ts.map +1 -1
- package/dist/reasons.js +8 -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/compact.d.ts +3 -1
- package/dist/render/compact.d.ts.map +1 -1
- package/dist/render/compact.js +8 -2
- package/dist/render/compact.js.map +1 -1
- package/dist/render/explain.d.ts +9 -1
- package/dist/render/explain.d.ts.map +1 -1
- package/dist/render/explain.js +54 -13
- 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 +110 -16
- 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/suppressions.d.ts +3 -0
- package/dist/render/suppressions.d.ts.map +1 -1
- package/dist/render/suppressions.js +20 -1
- package/dist/render/suppressions.js.map +1 -1
- 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 +73 -0
- package/dist/rule-guide.d.ts.map +1 -0
- package/dist/rule-guide.js +95 -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-semantic.d.ts.map +1 -1
- package/dist/run-semantic.js +2 -1
- package/dist/run-semantic.js.map +1 -1
- package/dist/run.d.ts +18 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +80 -19
- 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 +8 -1
- package/dist/setting-problems.js.map +1 -1
- package/dist/spacing-minority.d.ts +16 -0
- package/dist/spacing-minority.d.ts.map +1 -0
- package/dist/spacing-minority.js +23 -0
- package/dist/spacing-minority.js.map +1 -0
- 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/stet-block.d.ts +5 -0
- package/dist/stet-block.d.ts.map +1 -0
- package/dist/stet-block.js +59 -0
- package/dist/stet-block.js.map +1 -0
- package/dist/stet.d.ts +4 -0
- package/dist/stet.d.ts.map +1 -1
- package/dist/stet.js +31 -11
- package/dist/stet.js.map +1 -1
- 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 +31 -0
- package/dist/structure/date-range.d.ts.map +1 -0
- package/dist/structure/date-range.js +77 -0
- package/dist/structure/date-range.js.map +1 -0
- package/dist/structure/definition-use.d.ts +32 -0
- package/dist/structure/definition-use.d.ts.map +1 -0
- package/dist/structure/definition-use.js +102 -0
- package/dist/structure/definition-use.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/lazy-tree.d.ts +8 -0
- package/dist/structure/lazy-tree.d.ts.map +1 -0
- package/dist/structure/lazy-tree.js +14 -0
- package/dist/structure/lazy-tree.js.map +1 -0
- package/dist/structure/modal-conflict.d.ts +28 -0
- package/dist/structure/modal-conflict.d.ts.map +1 -0
- package/dist/structure/modal-conflict.js +74 -0
- package/dist/structure/modal-conflict.js.map +1 -0
- package/dist/structure/numbered-clauses.d.ts +4 -0
- package/dist/structure/numbered-clauses.d.ts.map +1 -0
- package/dist/structure/numbered-clauses.js +9 -0
- package/dist/structure/numbered-clauses.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 +24 -3
- 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 +25 -0
- package/dist/style-parse.d.ts.map +1 -0
- package/dist/style-parse.js +88 -0
- package/dist/style-parse.js.map +1 -0
- package/dist/subheading-line.d.ts +23 -0
- package/dist/subheading-line.d.ts.map +1 -0
- package/dist/subheading-line.js +85 -0
- package/dist/subheading-line.js.map +1 -0
- package/dist/tag-coverage.d.ts +8 -0
- package/dist/tag-coverage.d.ts.map +1 -0
- package/dist/tag-coverage.js +7 -0
- package/dist/tag-coverage.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 +68 -0
- package/package.json +9 -3
- package/reference-headings.yaml +17 -0
- package/rules/acronym-expansion-conflict.yaml +82 -0
- package/rules/adverb-overuse.yaml +19 -0
- package/rules/agentless-passive.yaml +47 -0
- package/rules/agreement-slip.yaml +14 -1
- package/rules/ai-generated-composite.yaml +102 -0
- package/rules/ai-tell.yaml +57 -0
- package/rules/announced-count-mismatch.yaml +57 -0
- package/rules/announcing-opener.yaml +82 -0
- package/rules/assistant-residue.yaml +82 -0
- package/rules/bold-density.yaml +59 -0
- package/rules/bold-label-list.yaml +81 -0
- package/rules/broken-link.yaml +65 -0
- package/rules/closing-cliche.yaml +58 -0
- package/rules/colon-lead-in.yaml +83 -0
- package/rules/concrete-evidence-density.yaml +41 -0
- package/rules/contraction-consistency.yaml +18 -0
- package/rules/contrast-framing.yaml +88 -0
- package/rules/cushion-phrase-density.yaml +53 -1
- package/rules/dangling-figure-reference.yaml +61 -0
- package/rules/dangling-reference.yaml +54 -1
- package/rules/date-order.yaml +34 -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/double-negative.yaml +51 -0
- package/rules/doubled-punctuation.yaml +45 -0
- package/rules/doubled-word.yaml +18 -2
- package/rules/duplicate-definition.yaml +59 -1
- package/rules/duplicate-heading.yaml +78 -0
- package/rules/emoji-density.yaml +28 -2
- package/rules/empty-conclusion.yaml +28 -0
- package/rules/empty-intensifier.yaml +44 -0
- package/rules/empty-section.yaml +74 -0
- package/rules/excessive-hedging.yaml +49 -2
- package/rules/expletive-construction.yaml +19 -0
- package/rules/fullwidth-alnum-consistency.yaml +53 -0
- package/rules/hankaku-kana.yaml +41 -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/invisible-character.yaml +63 -0
- package/rules/katakana-long-vowel.yaml +99 -0
- package/rules/kutoten-consistency.yaml +53 -0
- package/rules/latin-spacing.yaml +30 -4
- package/rules/max-kanji-continuous.yaml +17 -0
- package/rules/max-paragraph-length.yaml +34 -0
- package/rules/max-sentence-length.yaml +58 -0
- package/rules/modal-conflict.yaml +106 -0
- package/rules/name-variant.yaml +88 -0
- package/rules/ngram-repetition.yaml +29 -2
- package/rules/no-doubled-joshi.yaml +17 -0
- package/rules/no-em-dash.yaml +49 -0
- package/rules/no-mixed-desumasu.yaml +28 -2
- package/rules/no-nakaguro-parallel.yaml +20 -0
- package/rules/nominalization.yaml +89 -0
- package/rules/numbering-gap.yaml +53 -1
- package/rules/outside-announced-list.yaml +80 -0
- package/rules/oxford-comma-consistency.yaml +18 -0
- package/rules/padded-intro.yaml +44 -0
- package/rules/paragraph-length-variance.yaml +73 -0
- package/rules/percent-sum-mismatch.yaml +58 -0
- package/rules/preamble-length.yaml +56 -0
- package/rules/preferred-term.yaml +28 -0
- package/rules/proper-noun-density.yaml +37 -2
- package/rules/ra-nuki.yaml +43 -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/requirement-modal.yaml +94 -0
- package/rules/requirement-smell.yaml +70 -0
- package/rules/risk-disclosure.yaml +22 -0
- package/rules/rule-of-three.yaml +143 -0
- package/rules/sasete-itadaku.yaml +18 -0
- package/rules/section-length-uniformity.yaml +113 -0
- package/rules/sentence-initial-conjunction-run.yaml +18 -0
- package/rules/sentence-rhythm.yaml +51 -0
- package/rules/space-before-punctuation.yaml +41 -0
- package/rules/spelling-consistency.yaml +47 -0
- package/rules/stock-transition.yaml +86 -0
- package/rules/stray-space.yaml +18 -0
- package/rules/taigen-dome-in-prose.yaml +33 -0
- package/rules/title-case-consistency.yaml +42 -0
- package/rules/total-mismatch.yaml +38 -1
- package/rules/unbalanced-bracket.yaml +56 -0
- package/rules/undefined-acronym.yaml +23 -0
- package/rules/unfilled-placeholder.yaml +50 -0
- package/rules/unqualified-superlative.yaml +20 -0
- package/rules/unsourced-number.yaml +16 -0
- package/rules/unused-definition.yaml +75 -0
- package/rules/url-run-on.yaml +45 -0
- package/rules/use-before-definition.yaml +77 -0
- package/rules/vague-figure-reference.yaml +66 -0
- package/skills/chaff/SKILL.md +171 -1
- package/src/acronym-expansions.ts +106 -0
- package/src/announced-count.ts +190 -0
- package/src/announced-list.ts +120 -0
- package/src/api.ts +154 -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 +14 -15
- package/src/cli.ts +93 -92
- package/src/closing-paragraph.ts +24 -0
- package/src/commands/compare.ts +73 -0
- package/src/commands/document-commands.ts +19 -0
- package/src/commands/eval.ts +22 -10
- package/src/commands/facts.ts +33 -0
- package/src/commands/feedback.ts +45 -7
- package/src/commands/fix-plan.ts +53 -0
- package/src/commands/outline.ts +49 -0
- package/src/commands/read-document.ts +24 -0
- package/src/commands/suppressions.ts +19 -0
- package/src/commands/test.ts +3 -5
- package/src/commands/tree.ts +41 -5
- package/src/compare/atom.ts +33 -0
- package/src/compare/clock-time.ts +89 -0
- package/src/compare/distinct.ts +13 -0
- package/src/compare/extract.ts +80 -0
- package/src/compare/fact-key.ts +31 -0
- package/src/compare/fact-text.ts +87 -0
- package/src/compare/facts-render.ts +63 -0
- package/src/compare/facts-text.ts +41 -0
- package/src/compare/markup-atoms.ts +29 -0
- package/src/compare/match.ts +105 -0
- package/src/compare/outcome.ts +80 -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 +96 -0
- package/src/compare/text.ts +121 -0
- package/src/compare/tree-atoms.ts +80 -0
- package/src/compare/written-names.ts +26 -0
- package/src/config/load.ts +30 -0
- package/src/config/option-problems.ts +72 -0
- package/src/config/read.ts +8 -0
- package/src/config/rule-problems.ts +12 -2
- package/src/config/style.ts +55 -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 +23 -0
- package/src/custom/module-path.ts +23 -0
- package/src/custom/parse.ts +323 -0
- package/src/custom/problems.ts +111 -0
- package/src/custom/regex-safety.ts +118 -0
- package/src/custom/token-pattern.ts +84 -0
- package/src/detect-language.ts +1 -1
- package/src/detect.ts +35 -2
- package/src/detectors/acronym-context.ts +16 -4
- package/src/detectors/ai-phrasing.ts +141 -0
- package/src/detectors/announced-count.ts +25 -0
- package/src/detectors/bold-label.ts +55 -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 +26 -0
- package/src/detectors/definition-use.ts +41 -0
- package/src/detectors/doubled-punctuation.ts +52 -0
- package/src/detectors/doubled-word.ts +19 -4
- package/src/detectors/duplicate-heading.ts +47 -0
- package/src/detectors/empty-section.ts +21 -0
- package/src/detectors/enumerated-runs.ts +13 -4
- package/src/detectors/fullwidth-alnum.ts +118 -0
- 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/hankaku-kana.ts +38 -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 +79 -1
- package/src/detectors/invisible-character.ts +190 -0
- package/src/detectors/kutoten-consistency.ts +96 -0
- package/src/detectors/lead-in.ts +3 -1
- package/src/detectors/lexicon-match.ts +41 -2
- package/src/detectors/lexicon.ts +40 -13
- 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 +198 -0
- package/src/detectors/list-view.ts +157 -0
- package/src/detectors/long-vowel.ts +82 -0
- package/src/detectors/markup-finding.ts +39 -0
- package/src/detectors/modal-conflict.ts +26 -0
- package/src/detectors/name-numeral.ts +4 -2
- package/src/detectors/name-variant.ts +15 -0
- package/src/detectors/nominalization.ts +73 -0
- package/src/detectors/orthography.ts +97 -41
- package/src/detectors/outside-announced-list.ts +25 -0
- package/src/detectors/oxford-comma.ts +179 -283
- package/src/detectors/phrase-match.ts +27 -7
- 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/ra-nuki.ts +38 -0
- package/src/detectors/register.ts +37 -10
- package/src/detectors/requirement-modal.ts +67 -0
- package/src/detectors/requirement-smell.ts +52 -0
- 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/space-before-punctuation.ts +32 -0
- package/src/detectors/spelling-variety.ts +81 -0
- package/src/detectors/structure-tree.ts +47 -1
- package/src/detectors/structure.ts +20 -7
- package/src/detectors/superlative-comparison.ts +47 -0
- 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 +33 -0
- package/src/detectors/vague-figure-pointer.ts +58 -0
- package/src/detectors/word-list.ts +6 -1
- package/src/document-sections.ts +46 -0
- package/src/document.ts +188 -173
- package/src/email-parts.ts +269 -0
- package/src/eval.ts +14 -4
- package/src/extension/document-view.ts +109 -0
- package/src/extension/failure-text.ts +46 -0
- package/src/extension/import-default.ts +13 -0
- package/src/extension/load.ts +97 -0
- package/src/extension/module-detector.ts +61 -0
- package/src/extension/plugin-load.ts +82 -0
- package/src/extension/plugin-name.ts +26 -0
- package/src/extension/plugin-parse.ts +229 -0
- package/src/extension/problem-text.ts +103 -0
- package/src/extension/real-path.ts +10 -0
- package/src/extension/returned-findings.ts +62 -0
- package/src/extension/rule-export.ts +23 -0
- package/src/feedback/draft.ts +6 -0
- package/src/figure-references.ts +173 -0
- package/src/files.ts +5 -0
- package/src/finding-order.ts +3 -0
- package/src/fix-plan/mode.ts +34 -0
- package/src/fix-plan/plan.ts +181 -0
- package/src/fix-plan/render.ts +128 -0
- package/src/fix-plan/text.ts +133 -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/language-sample.ts +48 -0
- package/src/levels.ts +14 -1
- package/src/line-paragraphs.ts +52 -9
- package/src/link-line.ts +13 -0
- package/src/long-vowel.ts +109 -0
- package/src/markdown-node.ts +19 -0
- package/src/markdown-read.ts +44 -0
- package/src/markup.ts +212 -0
- package/src/mask.ts +8 -8
- package/src/name-variants.ts +217 -0
- package/src/node-version.ts +22 -0
- package/src/not-run.ts +16 -0
- package/src/number-name.ts +151 -24
- package/src/orthography.ts +50 -14
- package/src/outline/render.ts +85 -0
- package/src/outline/shape.ts +72 -0
- package/src/outline/text.ts +50 -0
- package/src/page-furniture.ts +11 -2
- package/src/plain-source.ts +2 -1
- package/src/plugin.ts +120 -3
- package/src/profile/for-file.ts +3 -1
- package/src/quoted-span.ts +9 -3
- package/src/reasons.ts +12 -0
- package/src/reference-lists.ts +91 -0
- package/src/render/compact.ts +13 -3
- package/src/render/explain.ts +75 -14
- package/src/render/friendly.ts +20 -9
- package/src/render/options.ts +58 -0
- package/src/render/rules-json.ts +140 -18
- 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/suppressions.ts +30 -2
- 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 +173 -0
- package/src/rule-load.ts +91 -34
- package/src/rule-options.ts +131 -0
- package/src/run-semantic.ts +2 -1
- package/src/run.ts +105 -22
- package/src/sentence-shape.ts +4 -5
- package/src/setting-problems.ts +9 -1
- package/src/spacing-minority.ts +27 -0
- package/src/span-cut.ts +28 -0
- package/src/stet-block.ts +60 -0
- package/src/stet.ts +41 -15
- 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 +117 -0
- package/src/structure/definition-use.ts +130 -0
- package/src/structure/known-mentions.ts +96 -0
- package/src/structure/lazy-tree.ts +15 -0
- package/src/structure/modal-conflict.ts +86 -0
- package/src/structure/numbered-clauses.ts +11 -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 +33 -5
- package/src/structure/wrapped-tail.ts +38 -13
- package/src/style-load.ts +28 -0
- package/src/style-parse.ts +112 -0
- package/src/subheading-line.ts +106 -0
- package/src/tag-coverage.ts +13 -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 +30 -0
- package/styles/jis-z8301-2011.yaml +28 -0
- package/styles/jis-z8301-2019.yaml +31 -0
- package/styles/koyobun.yaml +35 -0
- package/dist/legal-address.d.ts +0 -2
- package/dist/legal-address.d.ts.map +0 -1
- package/dist/legal-address.js +0 -16
- package/dist/legal-address.js.map +0 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type { Lexicon, Span } from "./plugin.ts";
|
|
2
|
+
import { linesOf, type Line } from "./structure/lines.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The parts of a plain-text or Markdown email that are not the writer's prose: the header, the separator lines between
|
|
6
|
+
* messages, the signature, and a quoted reply. Found by shape, in any genre; the field names and the attribution words
|
|
7
|
+
* come from the language package's lexicons.
|
|
8
|
+
*/
|
|
9
|
+
export type EmailVocabulary = {
|
|
10
|
+
/** Header field names, lower-cased. */
|
|
11
|
+
readonly headerFields: ReadonlySet<string>;
|
|
12
|
+
/** The fields whose value the writer types (Subject, To), lower-cased. Their value stays prose, on a line of its own. */
|
|
13
|
+
readonly writtenFields: ReadonlySet<string>;
|
|
14
|
+
/** Words an attribution line ends with, before its colon ("wrote", 「書きました」). */
|
|
15
|
+
readonly attributions: readonly string[];
|
|
16
|
+
/** How an archive's note in place of a removed attachment ends ("was scrubbed...", 「を保管しました...」). */
|
|
17
|
+
readonly attachmentNotes: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type EmailParts = {
|
|
21
|
+
/**
|
|
22
|
+
* Header lines (all of them but a written field's value), separator lines, signatures and attribution lines: masked
|
|
23
|
+
* from prose, and paragraphs are cut around them.
|
|
24
|
+
*/
|
|
25
|
+
readonly furniture: readonly Span[];
|
|
26
|
+
/** An attribution line and the quoted lines after it: someone else's words, so not this document's headings or structure. */
|
|
27
|
+
readonly replyQuotes: readonly Span[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const lowerCased = (lexicon: Lexicon | undefined): ReadonlySet<string> => new Set((lexicon ?? []).map((entry) => entry.pattern.toLowerCase()));
|
|
31
|
+
|
|
32
|
+
export const emailVocabulary = (lexicons: Readonly<Record<string, Lexicon>>): EmailVocabulary => ({
|
|
33
|
+
headerFields: lowerCased(lexicons["email-header-field"]),
|
|
34
|
+
writtenFields: lowerCased(lexicons["email-written-field"]),
|
|
35
|
+
attributions: (lexicons["email-attribution"] ?? []).map((entry) => entry.pattern),
|
|
36
|
+
attachmentNotes: (lexicons["email-attachment-note"] ?? []).map((entry) => entry.pattern),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/** A signature has at most this many lines after its "-- " line (the convention is four). More is prose again. */
|
|
40
|
+
const SIGNATURE_MAX_LINES = 4;
|
|
41
|
+
/** An attribution paragraph longer than this is a paragraph of the writer's that happens to end with "wrote:". */
|
|
42
|
+
const ATTRIBUTION_MAX_LINES = 3;
|
|
43
|
+
/** Away from the top of a message, one known field ("Date: the first Monday") is a sentence; a header names several. */
|
|
44
|
+
const HEADER_MIN_FIELDS = 2;
|
|
45
|
+
/** An attachment stub is its note and a few fields: Mailman's longest is the note, Name, Type, Size, Desc and URL. */
|
|
46
|
+
const ATTACHMENT_STUB_MAX_LINES = 6;
|
|
47
|
+
|
|
48
|
+
/** "Field: value" or 「件名:値」. A colon followed by text, as in a URL, is not a field. */
|
|
49
|
+
const FIELD = /^([^\s::]{1,40})(?::(?:[ \t]+|$)|:[ \t]*)/u;
|
|
50
|
+
const FOLDED = /^[ \t]+\S/u;
|
|
51
|
+
/** An mbox archive's envelope line (RFC 4155): "From ", the sender, then the date. It has no colon after From. */
|
|
52
|
+
const ENVELOPE = /^From [^\s:]+ /u;
|
|
53
|
+
const SIGNATURE = /^-- ?$/u;
|
|
54
|
+
/** A line of dashes, underscores or equals signs, with a few words between them or none: "-----Original Message-----". */
|
|
55
|
+
const SEPARATOR = /^[-_=]{3,}(?:([^-_=]{1,40})[-_=]{2,})?$/u;
|
|
56
|
+
/** Two rules with only spaces or strokes between them are a drawing (an RFC's diagram), not a separator. */
|
|
57
|
+
const LETTER = /\p{L}/u;
|
|
58
|
+
const QUOTED = /^ {0,3}>/u;
|
|
59
|
+
const QUOTED_TEXT = /^ {0,3}>[\s>]*\S/u;
|
|
60
|
+
/** Gmail's attribution ends with the sender's address and a colon: 「… 山田太郎 <taro@example.com>:」. An archive writes "taro at example.com". */
|
|
61
|
+
const BRACKETED_THEN_COLON = /<([^<>]*)>[ \t]*[::]$/u;
|
|
62
|
+
const ADDRESS_MARK = /@| at /u;
|
|
63
|
+
const LATIN_LETTER = /[A-Za-z]/u;
|
|
64
|
+
/** The stub's last field: its value is a URL alone, bare or in angle brackets. */
|
|
65
|
+
const URL_VALUE = /^<?[a-z][a-z0-9+.-]*:\/\/\S+?>?$/iu;
|
|
66
|
+
|
|
67
|
+
const isBlank = (line: Line | undefined): boolean => line !== undefined && line.text.trim() === "";
|
|
68
|
+
const isSeparator = (line: Line | undefined): boolean => {
|
|
69
|
+
const match = line === undefined ? null : SEPARATOR.exec(line.text.trim());
|
|
70
|
+
return match !== null && (match[1] === undefined || LETTER.test(match[1]));
|
|
71
|
+
};
|
|
72
|
+
const isQuoted = (line: Line | undefined): boolean => line !== undefined && QUOTED.test(line.text);
|
|
73
|
+
const endOf = (line: Line): number => line.start + line.text.length;
|
|
74
|
+
const spanOfLines = (first: Line, last: Line): Span => ({ start: first.start, end: endOf(last) });
|
|
75
|
+
|
|
76
|
+
/** The first index at or after `from` whose line meets `test`, or -1. Scans forward only, so a long document stays linear. */
|
|
77
|
+
const indexFrom = (lines: readonly Line[], from: number, test: (line: Line, index: number) => boolean): number => {
|
|
78
|
+
for (let index = Math.max(0, from); index < lines.length; index += 1) {
|
|
79
|
+
const line = lines[index];
|
|
80
|
+
if (line !== undefined && test(line, index)) return index;
|
|
81
|
+
}
|
|
82
|
+
return -1;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** The last index at or before `from` whose line meets `test`, or -1. */
|
|
86
|
+
const indexBackFrom = (lines: readonly Line[], from: number, test: (line: Line) => boolean): number => {
|
|
87
|
+
for (let index = Math.min(from, lines.length - 1); index >= 0; index -= 1) {
|
|
88
|
+
const line = lines[index];
|
|
89
|
+
if (line !== undefined && test(line)) return index;
|
|
90
|
+
}
|
|
91
|
+
return -1;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** Runs of lines between blank lines and separator lines. */
|
|
95
|
+
const blocksOf = (lines: readonly Line[]): Line[][] =>
|
|
96
|
+
lines.reduce<Line[][]>((blocks, line, index) => {
|
|
97
|
+
if (isBlank(line) || isSeparator(line) || SIGNATURE.test(line.text)) return blocks;
|
|
98
|
+
const previous = lines[index - 1];
|
|
99
|
+
if (previous !== undefined && !isBlank(previous) && !isSeparator(previous) && !SIGNATURE.test(previous.text)) blocks.at(-1)?.push(line);
|
|
100
|
+
else blocks.push([line]);
|
|
101
|
+
return blocks;
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
/** The block opens a message: nothing but blank lines before it, or before it and the nearest separator line. */
|
|
105
|
+
const opensMessage = (lines: readonly Line[], first: Line): boolean => {
|
|
106
|
+
const last = indexBackFrom(lines, first.number - 2, (line) => !isBlank(line));
|
|
107
|
+
return last === -1 || isSeparator(lines[last]);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const knownField = (text: string, vocabulary: EmailVocabulary): boolean => {
|
|
111
|
+
const name = FIELD.exec(text)?.[1];
|
|
112
|
+
return name !== undefined && vocabulary.headerFields.has(name.toLowerCase());
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const isHeaderLine = (line: Line, index: number): boolean =>
|
|
116
|
+
FIELD.test(line.text) || (index > 0 && FOLDED.test(line.text)) || (index === 0 && ENVELOPE.test(line.text));
|
|
117
|
+
|
|
118
|
+
const isHeader = (block: readonly Line[], atTop: boolean, vocabulary: EmailVocabulary): boolean => {
|
|
119
|
+
if (!block.every(isHeaderLine)) return false;
|
|
120
|
+
const known = block.filter((line) => knownField(line.text, vocabulary)).length;
|
|
121
|
+
if (known >= HEADER_MIN_FIELDS) return true;
|
|
122
|
+
// Fewer known fields make a header only at the top of a message, and only if no other field sits beside them: "Summary:" is the writer's.
|
|
123
|
+
return atTop && known > 0 && block.every((line) => !FIELD.test(line.text) || knownField(line.text, vocabulary));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** A header's fields: each line with the folded lines under it. */
|
|
127
|
+
const fieldsOf = (block: readonly Line[]): Line[][] =>
|
|
128
|
+
block.reduce<Line[][]>((fields, line, index) => {
|
|
129
|
+
if (index > 0 && FOLDED.test(line.text)) fields.at(-1)?.push(line);
|
|
130
|
+
else fields.push([line]);
|
|
131
|
+
return fields;
|
|
132
|
+
}, []);
|
|
133
|
+
|
|
134
|
+
/** A written field loses only its label and keeps its value; any other field, and the envelope line, go whole. */
|
|
135
|
+
const fieldMask = (field: readonly Line[], vocabulary: EmailVocabulary): Span | undefined => {
|
|
136
|
+
const first = field[0];
|
|
137
|
+
const last = field.at(-1);
|
|
138
|
+
if (first === undefined || last === undefined) return undefined;
|
|
139
|
+
const label = FIELD.exec(first.text);
|
|
140
|
+
const name = label?.[1]?.toLowerCase();
|
|
141
|
+
if (label === null || name === undefined || !vocabulary.writtenFields.has(name)) return spanOfLines(first, last);
|
|
142
|
+
return { start: first.start, end: first.start + label[0].length };
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const headerSpans = (lines: readonly Line[], vocabulary: EmailVocabulary): Span[] =>
|
|
146
|
+
blocksOf(lines).flatMap((block) => {
|
|
147
|
+
const first = block[0];
|
|
148
|
+
if (first === undefined || !isHeader(block, opensMessage(lines, first), vocabulary)) return [];
|
|
149
|
+
return fieldsOf(block).flatMap((field) => fieldMask(field, vocabulary) ?? []);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const isUrlField = (line: Line | undefined): boolean => {
|
|
153
|
+
const label = line === undefined ? null : FIELD.exec(line.text);
|
|
154
|
+
return line !== undefined && label !== null && URL_VALUE.test(line.text.slice(label[0].length).trim());
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* An archive's note where it removed an attachment: right after a separator, a line ending as the lexicon says, then
|
|
159
|
+
* only field lines, the last one a URL. Mailman's "An HTML attachment was scrubbed..." and its "URL: <…>" line.
|
|
160
|
+
*/
|
|
161
|
+
const isAttachmentStub = (lines: readonly Line[], block: readonly Line[], vocabulary: EmailVocabulary): boolean => {
|
|
162
|
+
const [note, ...fields] = block;
|
|
163
|
+
if (note === undefined || block.length > ATTACHMENT_STUB_MAX_LINES) return false;
|
|
164
|
+
const noteText = note.text.trim();
|
|
165
|
+
if (!vocabulary.attachmentNotes.some((ending) => noteText.endsWith(ending))) return false;
|
|
166
|
+
return fields.every((line) => FIELD.test(line.text)) && isUrlField(fields.at(-1)) && isSeparator(lines[note.number - 2]);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const attachmentStubSpans = (lines: readonly Line[], vocabulary: EmailVocabulary): Span[] =>
|
|
170
|
+
blocksOf(lines).flatMap((block) => {
|
|
171
|
+
const first = block[0];
|
|
172
|
+
const last = block.at(-1);
|
|
173
|
+
return first !== undefined && last !== undefined && isAttachmentStub(lines, block, vocabulary) ? [spanOfLines(first, last)] : [];
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/** From the "-- " line: the blank lines right after it, then its lines up to a blank line, a separator or a quote. */
|
|
177
|
+
const signatureAt = (lines: readonly Line[], delimiter: Line): Span => {
|
|
178
|
+
const firstText = indexFrom(lines, delimiter.number, (line) => !isBlank(line));
|
|
179
|
+
if (firstText === -1) return spanOfLines(delimiter, delimiter);
|
|
180
|
+
const stop = indexFrom(
|
|
181
|
+
lines,
|
|
182
|
+
firstText,
|
|
183
|
+
(line, index) => index - firstText >= SIGNATURE_MAX_LINES || isBlank(line) || isSeparator(line) || isQuoted(line) || SIGNATURE.test(line.text),
|
|
184
|
+
);
|
|
185
|
+
return spanOfLines(delimiter, lines[(stop === -1 ? lines.length : stop) - 1] ?? delimiter);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const signatureSpans = (lines: readonly Line[]): Span[] => lines.filter((line) => SIGNATURE.test(line.text)).map((line) => signatureAt(lines, line));
|
|
189
|
+
|
|
190
|
+
const endsWithAttribution = (text: string, vocabulary: EmailVocabulary): boolean => {
|
|
191
|
+
const trimmed = text.trimEnd();
|
|
192
|
+
if (ADDRESS_MARK.test(BRACKETED_THEN_COLON.exec(trimmed)?.[1] ?? "")) return true;
|
|
193
|
+
if (!/[::]$/u.test(trimmed)) return false;
|
|
194
|
+
const words = trimmed.slice(0, -1).trimEnd();
|
|
195
|
+
return vocabulary.attributions.some((word) => {
|
|
196
|
+
if (!words.endsWith(word)) return false;
|
|
197
|
+
const before = words.at(-word.length - 1) ?? "";
|
|
198
|
+
return !(LATIN_LETTER.test(word.charAt(0)) && LATIN_LETTER.test(before));
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/** The paragraph that ends right before `index`, skipping blank lines: its lines, if it is short enough to be an attribution. */
|
|
203
|
+
const attributionBefore = (lines: readonly Line[], index: number, vocabulary: EmailVocabulary): Line[] | undefined => {
|
|
204
|
+
const lastText = indexBackFrom(lines, index - 1, (line) => !isBlank(line));
|
|
205
|
+
if (lastText === -1) return undefined;
|
|
206
|
+
const floor = lastText - ATTRIBUTION_MAX_LINES;
|
|
207
|
+
const window = lines.slice(Math.max(0, floor), lastText + 1);
|
|
208
|
+
const opening = window.findLastIndex((line) => isBlank(line) || isSeparator(line) || isQuoted(line));
|
|
209
|
+
if (opening === -1 && floor > 0) return undefined;
|
|
210
|
+
const paragraph = window.slice(opening + 1);
|
|
211
|
+
if (paragraph.length === 0 || paragraph.length > ATTRIBUTION_MAX_LINES) return undefined;
|
|
212
|
+
return endsWithAttribution(paragraph.map((line) => line.text.trim()).join(" "), vocabulary) ? paragraph : undefined;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/** A quoted line, or a line with text run on from a quoted line with text (a lazy continuation, as Markdown reads it). */
|
|
216
|
+
const continuesQuote = (lines: readonly Line[], index: number): boolean => {
|
|
217
|
+
const line = lines[index];
|
|
218
|
+
if (isQuoted(line)) return true;
|
|
219
|
+
const previous = lines[index - 1];
|
|
220
|
+
return line !== undefined && !isBlank(line) && !isSeparator(line) && previous !== undefined && QUOTED_TEXT.test(previous.text);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/** The last line of the quote that starts at `index`. Blank lines between quoted lines stay inside it. */
|
|
224
|
+
const quoteEnd = (lines: readonly Line[], index: number): number => {
|
|
225
|
+
const chunk = { start: index };
|
|
226
|
+
for (;;) {
|
|
227
|
+
const next = indexFrom(lines, chunk.start + 1, (_, at) => !continuesQuote(lines, at));
|
|
228
|
+
if (next === -1) return lines.length - 1;
|
|
229
|
+
const resumes = indexFrom(lines, next, (line) => !isBlank(line));
|
|
230
|
+
if (resumes === -1 || !isQuoted(lines[resumes])) return next - 1;
|
|
231
|
+
chunk.start = resumes;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const quoteStarts = (lines: readonly Line[]): number[] => lines.flatMap((line, index) => (isQuoted(line) && !continuesQuote(lines, index - 1) ? [index] : []));
|
|
236
|
+
|
|
237
|
+
type Reply = { readonly attribution: Span; readonly quote: Span };
|
|
238
|
+
|
|
239
|
+
const repliesOf = (lines: readonly Line[], vocabulary: EmailVocabulary): Reply[] =>
|
|
240
|
+
quoteStarts(lines).reduce<Reply[]>((replies, start) => {
|
|
241
|
+
const covered = replies.at(-1);
|
|
242
|
+
const line = lines[start];
|
|
243
|
+
if (line === undefined || (covered !== undefined && line.start < covered.quote.end)) return replies;
|
|
244
|
+
const attribution = attributionBefore(lines, start, vocabulary);
|
|
245
|
+
const first = attribution?.[0];
|
|
246
|
+
const last = attribution?.at(-1);
|
|
247
|
+
if (first === undefined || last === undefined) return replies;
|
|
248
|
+
const end = lines[quoteEnd(lines, start)];
|
|
249
|
+
if (end === undefined) return replies;
|
|
250
|
+
return [...replies, { attribution: spanOfLines(first, last), quote: spanOfLines(first, end) }];
|
|
251
|
+
}, []);
|
|
252
|
+
|
|
253
|
+
const bySpanStart = (left: Span, right: Span): number => left.start - right.start;
|
|
254
|
+
|
|
255
|
+
export const emailParts = (source: string, vocabulary: EmailVocabulary): EmailParts => {
|
|
256
|
+
const lines = linesOf(source);
|
|
257
|
+
const replies = repliesOf(lines, vocabulary);
|
|
258
|
+
const separators = lines.filter((line) => isSeparator(line)).map((line) => spanOfLines(line, line));
|
|
259
|
+
return {
|
|
260
|
+
furniture: [
|
|
261
|
+
...headerSpans(lines, vocabulary),
|
|
262
|
+
...attachmentStubSpans(lines, vocabulary),
|
|
263
|
+
...separators,
|
|
264
|
+
...signatureSpans(lines),
|
|
265
|
+
...replies.map((reply) => reply.attribution),
|
|
266
|
+
].toSorted(bySpanStart),
|
|
267
|
+
replyQuotes: replies.map((reply) => reply.quote),
|
|
268
|
+
};
|
|
269
|
+
};
|
package/src/eval.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { DETECTORS } from "./detectors/index.ts";
|
|
2
2
|
import { charLength } from "./measure.ts";
|
|
3
|
-
import type { ProseDocument, RuleDefinition } from "./plugin.ts";
|
|
3
|
+
import type { DetectorOptions, ProseDocument, RuleDefinition } from "./plugin.ts";
|
|
4
|
+
import { optionValues, settleOptions, type OptionLayer } from "./rule-options.ts";
|
|
4
5
|
import { missingList } from "./declared-lists.ts";
|
|
6
|
+
import { bodySectionOf } from "./body-section.ts";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* 閾値の較正。
|
|
@@ -44,12 +46,12 @@ const candidates = (rule: RuleDefinition, current: number): number[] => {
|
|
|
44
46
|
return [...new Set([...fromLevels, ...scaled, current])].toSorted((left, right) => left - right);
|
|
45
47
|
};
|
|
46
48
|
|
|
47
|
-
const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number): Point => {
|
|
49
|
+
const countAt = (docs: readonly ProseDocument[], rule: RuleDefinition, limit: number, settings: DetectorOptions["settings"]): Point => {
|
|
48
50
|
const detector = DETECTORS[rule.how_to_find];
|
|
49
51
|
if (detector === undefined) return { limit, findings: 0, documents: 0, per10k: 0 };
|
|
50
52
|
const perDoc = docs.map((doc) => {
|
|
51
53
|
const lexicon = rule.word_list === undefined ? undefined : doc.lexicons[rule.word_list];
|
|
52
|
-
return detector(doc, { limit, lexicon, where: rule.where }).length;
|
|
54
|
+
return detector(doc, { limit, lexicon, where: rule.where, settings }).length;
|
|
53
55
|
});
|
|
54
56
|
const findings = perDoc.reduce((sum, count) => sum + count, 0);
|
|
55
57
|
const chars = docs.reduce((sum, doc) => sum + doc.sentences.reduce((inner, sentence) => inner + charLength(sentence), 0), 0);
|
|
@@ -71,6 +73,10 @@ const meets = (need: string, docs: readonly ProseDocument[]): boolean => {
|
|
|
71
73
|
if (need === "lemma") return capabilities?.lemma === true;
|
|
72
74
|
// 木は adapter が structure を持つときだけ作れる。無いまま測ると、どの閾値でも 0 件になる。
|
|
73
75
|
if (need === "structure") return docs.length > 0 && docs.every((doc) => doc.structure !== undefined);
|
|
76
|
+
// 見出しの無い文書では lint が動かない。見出しのある文書が 1 つも無ければ、どの閾値でも 0 件になる。
|
|
77
|
+
if (need === "headings") return docs.some((doc) => bodySectionOf(doc.sections) !== undefined);
|
|
78
|
+
// 記法を読む rule は Markdown の文書でしか動かない。
|
|
79
|
+
if (need === "markdown") return docs.some((doc) => doc.markup?.markdown === true);
|
|
74
80
|
return false;
|
|
75
81
|
};
|
|
76
82
|
|
|
@@ -80,6 +86,8 @@ const meets = (need: string, docs: readonly ProseDocument[]): boolean => {
|
|
|
80
86
|
*/
|
|
81
87
|
const measurable = (rule: RuleDefinition, docs: readonly ProseDocument[], genre: string, language: string): boolean => {
|
|
82
88
|
if (rule.layer === "L4" || !rule.use_for.some((target) => genre.startsWith(target))) return false;
|
|
89
|
+
// A rule with nothing to count has no limit to sweep: its levels set severity.
|
|
90
|
+
if (rule.level_sets === "severity") return false;
|
|
83
91
|
if (rule.languages !== undefined && !rule.languages.includes(language)) return false;
|
|
84
92
|
if (rule.from.length > 0) return false;
|
|
85
93
|
if (docs.some((doc) => missingList(rule, doc.lexicons) !== undefined)) return false;
|
|
@@ -96,12 +104,14 @@ export const evaluate = (
|
|
|
96
104
|
genre: string,
|
|
97
105
|
language: string,
|
|
98
106
|
limits: Readonly<Record<string, number>> = {},
|
|
107
|
+
optionLayers: readonly OptionLayer[] = [],
|
|
99
108
|
): RuleReport[] =>
|
|
100
109
|
rules
|
|
101
110
|
.filter((rule) => measurable(rule, docs, genre, language))
|
|
102
111
|
.map((rule) => {
|
|
103
112
|
const current = limits[rule.id] ?? rule.levels.normal ?? 1;
|
|
104
|
-
const
|
|
113
|
+
const settings = rule.options === undefined ? undefined : optionValues(settleOptions(rule.id, rule.options, optionLayers));
|
|
114
|
+
const sweep = candidates(rule, current).map((limit) => countAt(docs, rule, limit, settings));
|
|
105
115
|
return {
|
|
106
116
|
rule: rule.id,
|
|
107
117
|
name: rule.name[language] ?? rule.id,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type * as Api from "../api.ts";
|
|
2
|
+
import type { BulletList, Lexicon, Markup, Paragraph, ProseDocument, Section, Sentence, Span, Token } from "../plugin.ts";
|
|
3
|
+
|
|
4
|
+
// The document as the plugin API shows it (api.ts RuleDocument): copies of only the public fields, frozen. A copy, so
|
|
5
|
+
// chaff's own shapes can change without breaking a plugin; frozen, so a plugin's rule cannot change what the next rule reads.
|
|
6
|
+
|
|
7
|
+
const freezeAll = (value: unknown): void => {
|
|
8
|
+
if (typeof value !== "object" || value === null || Object.isFrozen(value)) return;
|
|
9
|
+
Object.values(value).forEach(freezeAll);
|
|
10
|
+
Object.freeze(value);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const deepFreeze = <T>(value: T): T => {
|
|
14
|
+
freezeAll(value);
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const spanOf = (span: Span): Api.Span => ({ start: span.start, end: span.end });
|
|
19
|
+
|
|
20
|
+
const tokenOf = (token: Token): Api.Token => ({
|
|
21
|
+
span: spanOf(token.span),
|
|
22
|
+
surface: token.surface,
|
|
23
|
+
pos: token.pos,
|
|
24
|
+
...(token.lemma === undefined ? {} : { lemma: token.lemma }),
|
|
25
|
+
...(token.reading === undefined ? {} : { reading: token.reading }),
|
|
26
|
+
...(token.features === undefined ? {} : { features: { ...token.features } }),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/** Sentences are shared by the document, its paragraphs and its sections; each is copied once, so they stay one object. */
|
|
30
|
+
type SentenceCopies = (sentence: Sentence) => Api.Sentence;
|
|
31
|
+
|
|
32
|
+
const sentenceCopier = (): SentenceCopies => {
|
|
33
|
+
const copies = new Map<Sentence, Api.Sentence>();
|
|
34
|
+
return (sentence) => {
|
|
35
|
+
const known = copies.get(sentence);
|
|
36
|
+
if (known !== undefined) return known;
|
|
37
|
+
const copy = { span: spanOf(sentence.span), text: sentence.text, ...(sentence.tokens === undefined ? {} : { tokens: sentence.tokens.map(tokenOf) }) };
|
|
38
|
+
copies.set(sentence, copy);
|
|
39
|
+
return copy;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const paragraphOf = (paragraph: Paragraph, copy: SentenceCopies): Api.Paragraph => ({
|
|
44
|
+
span: spanOf(paragraph.span),
|
|
45
|
+
sentences: paragraph.sentences.map(copy),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const sectionOf = (section: Section, copy: SentenceCopies): Api.Section => ({
|
|
49
|
+
depth: section.depth,
|
|
50
|
+
heading: section.heading,
|
|
51
|
+
span: spanOf(section.span),
|
|
52
|
+
sentences: section.sentences.map(copy),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const listOf = (list: BulletList): Api.List => ({ span: spanOf(list.span), itemLengths: [...list.items] });
|
|
56
|
+
|
|
57
|
+
const lexiconOf = (lexicon: Lexicon): Api.Lexicon =>
|
|
58
|
+
lexicon.map((entry) => ({ pattern: entry.pattern, ...(entry.instead_of === undefined ? {} : { instead_of: entry.instead_of }) }));
|
|
59
|
+
|
|
60
|
+
const markupOf = (markup: Markup): Api.Markup => ({
|
|
61
|
+
markdown: markup.markdown,
|
|
62
|
+
headings: markup.headings.map((heading) => ({ depth: heading.depth, text: heading.text, span: { start: heading.start, end: heading.end } })),
|
|
63
|
+
images: markup.images.map((image) => ({ alt: image.alt, span: { start: image.start, end: image.end } })),
|
|
64
|
+
links: markup.links.map((link) => ({ destination: link.destination, span: { start: link.start, end: link.end } })),
|
|
65
|
+
ids: [...markup.ids].toSorted((left, right) => left.localeCompare(right, "en")),
|
|
66
|
+
texts: markup.texts.map(spanOf),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const EMPTY_MARKUP: Markup = { markdown: false, headings: [], images: [], links: [], ids: new Set(), texts: [] };
|
|
70
|
+
|
|
71
|
+
const viewOf = (doc: ProseDocument): Api.RuleDocument => {
|
|
72
|
+
const copy = sentenceCopier();
|
|
73
|
+
const fields = deepFreeze({
|
|
74
|
+
path: doc.path,
|
|
75
|
+
source: doc.source,
|
|
76
|
+
language: doc.language,
|
|
77
|
+
lengthUnit: doc.lengthUnit,
|
|
78
|
+
sentences: doc.sentences.map(copy),
|
|
79
|
+
paragraphs: doc.paragraphs.map((paragraph) => paragraphOf(paragraph, copy)),
|
|
80
|
+
sections: doc.sections.map((section) => sectionOf(section, copy)),
|
|
81
|
+
lists: doc.lists.map(listOf),
|
|
82
|
+
listItems: doc.listSpans.map(spanOf),
|
|
83
|
+
links: doc.links.map(spanOf),
|
|
84
|
+
lexicons: Object.fromEntries(Object.entries(doc.lexicons).map(([name, lexicon]) => [name, lexiconOf(lexicon)])),
|
|
85
|
+
});
|
|
86
|
+
// The markup is read from the Markdown tree only when a rule asks for it, as chaff's own rules do.
|
|
87
|
+
const markup: { value: Api.Markup | undefined } = { value: undefined };
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
...fields,
|
|
90
|
+
get markup(): Api.Markup {
|
|
91
|
+
markup.value ??= deepFreeze(markupOf(doc.markup ?? EMPTY_MARKUP));
|
|
92
|
+
return markup.value;
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** A word list as a detector is given it (DetectorOptions.lexicon): public fields only, frozen. */
|
|
98
|
+
export const frozenLexiconOf = (lexicon: Lexicon): Api.Lexicon => deepFreeze(lexiconOf(lexicon));
|
|
99
|
+
|
|
100
|
+
const views = new WeakMap<ProseDocument, Api.RuleDocument>();
|
|
101
|
+
|
|
102
|
+
/** The document as a plugin's detector sees it. Made once per document, however many plugin rules read it. */
|
|
103
|
+
export const ruleDocumentOf = (doc: ProseDocument): Api.RuleDocument => {
|
|
104
|
+
const known = views.get(doc);
|
|
105
|
+
if (known !== undefined) return known;
|
|
106
|
+
const view = viewOf(doc);
|
|
107
|
+
views.set(doc, view);
|
|
108
|
+
return view;
|
|
109
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Texts, UiLanguage } from "../ui.ts";
|
|
2
|
+
import type { RuleFailure } from "./module-detector.ts";
|
|
3
|
+
import type { ShapeProblem } from "./returned-findings.ts";
|
|
4
|
+
|
|
5
|
+
// Why a plugin's rule is listed as not run on a document, in the reader's language. It names where the detector came
|
|
6
|
+
// from, so the person who wrote it knows which file to open.
|
|
7
|
+
|
|
8
|
+
type Text = {
|
|
9
|
+
readonly reason: (origin: string, what: string) => string;
|
|
10
|
+
readonly threw: (message: string) => string;
|
|
11
|
+
/** Each wrong return, with the finding's number and what was there. */
|
|
12
|
+
readonly shape: Readonly<Record<ShapeProblem["kind"], (index: string, written: string) => string>>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const TEXT: Texts<Text> = {
|
|
16
|
+
ja: {
|
|
17
|
+
reason: (origin, what) => `${origin} の検出器が${what}ため`,
|
|
18
|
+
threw: (message) => `エラーを投げた(${message})`,
|
|
19
|
+
shape: {
|
|
20
|
+
"not-a-list": (_index, written) => `指摘の並びでなく ${written} を返した`,
|
|
21
|
+
"not-a-finding": (index, written) => `${index} 番目の指摘に { start } の形でないもの(${written})を返した`,
|
|
22
|
+
"bad-start": (index, written) => `${index} 番目の指摘の start に ${written} を返した(文書の中の位置を整数で返します)`,
|
|
23
|
+
"bad-end": (index, written) => `${index} 番目の指摘の end に ${written} を返した(start 以上、文書の長さ以下の整数で返します)`,
|
|
24
|
+
"bad-values": (index, written) => `${index} 番目の指摘の values に文字列と数でない値を入れた(${written})`,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
en: {
|
|
28
|
+
reason: (origin, what) => `the detector in ${origin} ${what}`,
|
|
29
|
+
threw: (message) => `threw an error (${message})`,
|
|
30
|
+
shape: {
|
|
31
|
+
"not-a-list": (_index, written) => `returned ${written}, not a list of findings`,
|
|
32
|
+
"not-a-finding": (index, written) => `returned ${written} as finding ${index}, not a { start } finding`,
|
|
33
|
+
"bad-start": (index, written) => `returned start ${written} in finding ${index} (an offset in the document, a whole number)`,
|
|
34
|
+
"bad-end": (index, written) => `returned end ${written} in finding ${index} (a whole number from start to the document's length)`,
|
|
35
|
+
"bad-values": (index, written) => `put a value that is not a string or a number in finding ${index}'s values (${written})`,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** The reason a rule whose detector failed is listed as not run. */
|
|
41
|
+
export const failureReason = (origin: string, failure: RuleFailure, ui: UiLanguage): string => {
|
|
42
|
+
const text = TEXT[ui];
|
|
43
|
+
if (failure.kind === "threw") return text.reason(origin, text.threw(failure.message));
|
|
44
|
+
const { kind, index, written } = failure.problem;
|
|
45
|
+
return text.reason(origin, text.shape[kind](String(index), written));
|
|
46
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
|
|
3
|
+
const firstLine = (error: unknown): string => (error instanceof Error ? error.message : String(error)).split("\n")[0] ?? "";
|
|
4
|
+
|
|
5
|
+
/** A module's default export, or the first line of why it could not be imported (a syntax error, a missing import). Running it runs its code. */
|
|
6
|
+
export const importDefault = async (file: string): Promise<{ readonly exported: unknown } | { readonly message: string }> => {
|
|
7
|
+
try {
|
|
8
|
+
const namespace: unknown = await import(pathToFileURL(file).href);
|
|
9
|
+
return { exported: typeof namespace === "object" && namespace !== null && "default" in namespace ? namespace.default : undefined };
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return { message: firstLine(error) };
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import type { Config } from "../config/load.ts";
|
|
3
|
+
import type { Detector, Lexicon, RuleDefinition } from "../plugin.ts";
|
|
4
|
+
import type { StyleDefinition } from "../style-parse.ts";
|
|
5
|
+
import { customRulesOf } from "../custom/load.ts";
|
|
6
|
+
import { withStyle } from "../config/style.ts";
|
|
7
|
+
import { moduleDetector } from "./module-detector.ts";
|
|
8
|
+
import { detectorExport, type ExportProblem } from "./rule-export.ts";
|
|
9
|
+
import { importDefault } from "./import-default.ts";
|
|
10
|
+
import { loadPlugins } from "./plugin-load.ts";
|
|
11
|
+
import type { ParsedPlugin, PluginProblem } from "./plugin-parse.ts";
|
|
12
|
+
import { staysInside } from "./real-path.ts";
|
|
13
|
+
|
|
14
|
+
// The code chaff.yaml names, loaded once before anything runs: each type: module rule's file, and each plugin under
|
|
15
|
+
// plugins:. Loading runs that code, which is why only chaff.yaml can name it. What cannot be loaded stops the run
|
|
16
|
+
// (settingProblems), like a rule in custom_rules that cannot be read: a rule that silently does not run looks like a clean document.
|
|
17
|
+
|
|
18
|
+
/** A rule whose file could not be loaded. file is the path as chaff.yaml writes it; detail: why, or what ExportProblem says. */
|
|
19
|
+
export type LoadProblem = {
|
|
20
|
+
readonly kind: "missing-file" | "outside" | "import-failed" | ExportProblem["kind"];
|
|
21
|
+
readonly rule: string;
|
|
22
|
+
readonly file: string;
|
|
23
|
+
readonly detail: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** What was loaded, and what could not be. */
|
|
27
|
+
export type Extensions = {
|
|
28
|
+
/** The detector of each type: module rule and each plugin rule written in code, by the rule's id. */
|
|
29
|
+
readonly detectors: Readonly<Record<string, Detector>>;
|
|
30
|
+
/** The plugins' rules, with their ids under each plugin's name. */
|
|
31
|
+
readonly rules: readonly RuleDefinition[];
|
|
32
|
+
/** The plugins' word lists by language, then by name. */
|
|
33
|
+
readonly lexicons: Readonly<Record<string, Readonly<Record<string, Lexicon>>>>;
|
|
34
|
+
/** The plugins' house styles. */
|
|
35
|
+
readonly styles: readonly StyleDefinition[];
|
|
36
|
+
readonly problems: readonly LoadProblem[];
|
|
37
|
+
readonly pluginProblems: readonly PluginProblem[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type Loaded = { readonly detector: Detector } | { readonly problem: LoadProblem };
|
|
41
|
+
|
|
42
|
+
/** A type: module rule: its id, its file, and the path as chaff.yaml writes it, which every message names. */
|
|
43
|
+
type ModuleRule = { readonly id: string; readonly file: string; readonly written: string };
|
|
44
|
+
|
|
45
|
+
const loadRule = async ({ id, file, written }: ModuleRule, baseDir: string): Promise<Loaded> => {
|
|
46
|
+
const at = { rule: id, file: written };
|
|
47
|
+
if (!existsSync(file)) return { problem: { ...at, kind: "missing-file", detail: "" } };
|
|
48
|
+
if (!staysInside(written, file, baseDir)) return { problem: { ...at, kind: "outside", detail: "" } };
|
|
49
|
+
const imported = await importDefault(file);
|
|
50
|
+
if ("message" in imported) return { problem: { ...at, kind: "import-failed", detail: imported.message } };
|
|
51
|
+
const read = detectorExport(imported.exported);
|
|
52
|
+
return "problem" in read ? { problem: { ...at, ...read.problem } } : { detector: moduleDetector(read.detect, written) };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const moduleRulesOf = (rules: readonly RuleDefinition[]): ModuleRule[] =>
|
|
56
|
+
rules.flatMap((rule) => (rule.custom?.type === "module" ? [{ id: rule.id, file: rule.custom.file, written: rule.custom.module }] : []));
|
|
57
|
+
|
|
58
|
+
/** Every type: module rule in chaff.yaml, loaded one by one in the order written, so the same chaff.yaml loads the same way. */
|
|
59
|
+
const loadModuleRules = async (config: Config): Promise<readonly { readonly id: string; readonly loaded: Loaded }[]> =>
|
|
60
|
+
moduleRulesOf(customRulesOf(config).rules).reduce<Promise<{ id: string; loaded: Loaded }[]>>(
|
|
61
|
+
async (done, rule) => [...(await done), { id: rule.id, loaded: await loadRule(rule, config.baseDir) }],
|
|
62
|
+
Promise.resolve([]),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
/** A plugin's code rules, each run as one of chaff's; a failure names the plugin as chaff.yaml writes it. */
|
|
66
|
+
const pluginDetectors = (plugin: ParsedPlugin): [string, Detector][] =>
|
|
67
|
+
Object.entries(plugin.detectors).map(([id, detect]) => [id, moduleDetector(detect, plugin.written)]);
|
|
68
|
+
|
|
69
|
+
const lexiconsByLanguage = (plugins: readonly ParsedPlugin[]): Record<string, Record<string, Lexicon>> => {
|
|
70
|
+
const languages = [...new Set(plugins.flatMap((plugin) => Object.keys(plugin.lexicons)))];
|
|
71
|
+
return Object.fromEntries(
|
|
72
|
+
languages.map((language) => [language, plugins.reduce<Record<string, Lexicon>>((merged, plugin) => ({ ...merged, ...plugin.lexicons[language] }), {})]),
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** Everything chaff.yaml names in code, loaded. */
|
|
77
|
+
const loadExtensions = async (config: Config): Promise<Extensions> => {
|
|
78
|
+
const modules = await loadModuleRules(config);
|
|
79
|
+
const { plugins, problems: pluginProblems } = await loadPlugins(config);
|
|
80
|
+
return {
|
|
81
|
+
detectors: Object.fromEntries([
|
|
82
|
+
...modules.flatMap((entry): [string, Detector][] => ("detector" in entry.loaded ? [[entry.id, entry.loaded.detector]] : [])),
|
|
83
|
+
...plugins.flatMap(pluginDetectors),
|
|
84
|
+
]),
|
|
85
|
+
rules: plugins.flatMap((plugin) => plugin.rules),
|
|
86
|
+
lexicons: lexiconsByLanguage(plugins),
|
|
87
|
+
styles: plugins.flatMap((plugin) => plugin.styles),
|
|
88
|
+
problems: modules.flatMap((entry) => ("problem" in entry.loaded ? [entry.loaded.problem] : [])),
|
|
89
|
+
pluginProblems,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** chaff.yaml with the code it names loaded, and the style it names applied when a plugin ships it. */
|
|
94
|
+
export const withExtensions = async (config: Config): Promise<Config> => {
|
|
95
|
+
const extensions = await loadExtensions(config);
|
|
96
|
+
return withStyle({ ...config, extensions }, extensions.styles);
|
|
97
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type * as Api from "../api.ts";
|
|
2
|
+
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
3
|
+
import { frozenLexiconOf, ruleDocumentOf } from "./document-view.ts";
|
|
4
|
+
import { returnedFindings, type ShapeProblem } from "./returned-findings.ts";
|
|
5
|
+
|
|
6
|
+
// A detector a team or a plugin wrote, run as one of chaff's. It reads the document through the plugin API, and what it
|
|
7
|
+
// returns is checked before chaff uses it. A throw or a wrong return is that rule's failure only: run.ts lists the rule
|
|
8
|
+
// as not run with the reason, and every other rule still runs.
|
|
9
|
+
|
|
10
|
+
/** A detector from a plugin. It is JavaScript nobody has type-checked against this chaff, so what it returns is unknown. */
|
|
11
|
+
export type UntrustedDetector = (doc: Api.RuleDocument, options: Api.DetectorOptions) => unknown;
|
|
12
|
+
|
|
13
|
+
export type RuleFailure = { readonly kind: "threw"; readonly message: string } | { readonly kind: "returned"; readonly problem: ShapeProblem };
|
|
14
|
+
|
|
15
|
+
/** A plugin's rule that failed on a document. origin is where the detector came from: its file, or its package. */
|
|
16
|
+
export class PluginRuleFailure extends Error {
|
|
17
|
+
readonly failure: RuleFailure;
|
|
18
|
+
readonly origin: string;
|
|
19
|
+
constructor(failure: RuleFailure, origin: string) {
|
|
20
|
+
super(`${origin}: ${failure.kind === "threw" ? failure.message : failure.problem.kind}`);
|
|
21
|
+
this.name = "PluginRuleFailure";
|
|
22
|
+
this.failure = failure;
|
|
23
|
+
this.origin = origin;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The first line of what was thrown. What a plugin throws is its own object, so printing it may throw too. */
|
|
28
|
+
const messageOf = (error: unknown): string => {
|
|
29
|
+
try {
|
|
30
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
31
|
+
return text.split("\n")[0] ?? text;
|
|
32
|
+
} catch {
|
|
33
|
+
return "an error that cannot be printed";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* What the detector returned, as findings, or how it failed. Reading the return can run the plugin's code too (a getter,
|
|
39
|
+
* a Proxy), so it is checked inside the try. A Promise is a wrong return; its rejection must not end the run later.
|
|
40
|
+
*/
|
|
41
|
+
const findingsOf = (detect: UntrustedDetector, doc: ProseDocument, options: Api.DetectorOptions): { findings: Finding[] } | { failure: RuleFailure } => {
|
|
42
|
+
const view = ruleDocumentOf(doc);
|
|
43
|
+
try {
|
|
44
|
+
const returned: unknown = detect(view, options);
|
|
45
|
+
if (returned instanceof Promise) returned.catch(() => undefined);
|
|
46
|
+
const result = returnedFindings(returned, doc.source, doc.sentences);
|
|
47
|
+
return "problem" in result ? { failure: { kind: "returned", problem: result.problem } } : { findings: [...result.findings] };
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return { failure: { kind: "threw", message: messageOf(error) } };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** detect as one of chaff's detectors. Throws PluginRuleFailure when it throws or returns anything but findings. */
|
|
54
|
+
export const moduleDetector =
|
|
55
|
+
(detect: UntrustedDetector, origin: string): Detector =>
|
|
56
|
+
(doc, options): Finding[] => {
|
|
57
|
+
const lexicon = options.lexicon === undefined ? undefined : frozenLexiconOf(options.lexicon);
|
|
58
|
+
const outcome = findingsOf(detect, doc, Object.freeze({ lexicon }));
|
|
59
|
+
if ("failure" in outcome) throw new PluginRuleFailure(outcome.failure, origin);
|
|
60
|
+
return outcome.findings;
|
|
61
|
+
};
|