chaffjs 0.18.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.map +1 -1
- package/dist/announced-count.js +44 -10
- package/dist/announced-count.js.map +1 -1
- 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/cli-text.d.ts +0 -1
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +6 -14
- package/dist/cli-text.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +58 -62
- 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 +8 -1
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +9 -17
- package/dist/commands/compare.js.map +1 -1
- 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 +3 -2
- 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 +10 -0
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +25 -1
- 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.js +1 -1
- package/dist/commands/test.js.map +1 -1
- package/dist/compare/clock-time.d.ts.map +1 -1
- package/dist/compare/clock-time.js +5 -2
- package/dist/compare/clock-time.js.map +1 -1
- 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.map +1 -1
- package/dist/compare/extract.js +7 -5
- package/dist/compare/extract.js.map +1 -1
- 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 +5 -0
- package/dist/compare/fact-text.d.ts.map +1 -1
- package/dist/compare/fact-text.js +16 -2
- package/dist/compare/fact-text.js.map +1 -1
- 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/match.d.ts +1 -0
- package/dist/compare/match.d.ts.map +1 -1
- package/dist/compare/match.js +1 -1
- package/dist/compare/match.js.map +1 -1
- package/dist/compare/outcome.d.ts +4 -1
- package/dist/compare/outcome.d.ts.map +1 -1
- package/dist/compare/outcome.js +10 -4
- package/dist/compare/outcome.js.map +1 -1
- package/dist/compare/proper-nouns.d.ts +3 -3
- package/dist/compare/proper-nouns.d.ts.map +1 -1
- package/dist/compare/proper-nouns.js +2 -3
- package/dist/compare/proper-nouns.js.map +1 -1
- package/dist/compare/render.d.ts +4 -0
- package/dist/compare/render.d.ts.map +1 -1
- package/dist/compare/render.js +2 -2
- package/dist/compare/render.js.map +1 -1
- package/dist/compare/text-atoms.d.ts +5 -2
- package/dist/compare/text-atoms.d.ts.map +1 -1
- package/dist/compare/text-atoms.js +7 -5
- package/dist/compare/text-atoms.js.map +1 -1
- package/dist/compare/text.d.ts.map +1 -1
- package/dist/compare/text.js +2 -2
- package/dist/compare/text.js.map +1 -1
- package/dist/config/load.d.ts +8 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +1 -0
- package/dist/config/load.js.map +1 -1
- package/dist/config/option-problems.d.ts +3 -2
- package/dist/config/option-problems.d.ts.map +1 -1
- package/dist/config/option-problems.js +4 -3
- package/dist/config/option-problems.js.map +1 -1
- package/dist/config/style.d.ts +5 -0
- package/dist/config/style.d.ts.map +1 -1
- package/dist/config/style.js +13 -1
- package/dist/config/style.js.map +1 -1
- package/dist/custom/load.d.ts +6 -3
- package/dist/custom/load.d.ts.map +1 -1
- package/dist/custom/load.js +10 -2
- package/dist/custom/load.js.map +1 -1
- 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 +17 -3
- package/dist/custom/parse.d.ts.map +1 -1
- package/dist/custom/parse.js +57 -14
- package/dist/custom/parse.js.map +1 -1
- package/dist/custom/problems.d.ts +4 -1
- package/dist/custom/problems.d.ts.map +1 -1
- package/dist/custom/problems.js +56 -39
- package/dist/custom/problems.js.map +1 -1
- package/dist/detect-language.js +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +9 -3
- package/dist/detect.js.map +1 -1
- package/dist/detectors/ai-phrasing.d.ts +4 -1
- package/dist/detectors/ai-phrasing.d.ts.map +1 -1
- package/dist/detectors/ai-phrasing.js +6 -2
- package/dist/detectors/ai-phrasing.js.map +1 -1
- 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/dangling-figure.d.ts +5 -2
- package/dist/detectors/dangling-figure.d.ts.map +1 -1
- package/dist/detectors/dangling-figure.js +5 -3
- package/dist/detectors/dangling-figure.js.map +1 -1
- 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.map +1 -1
- package/dist/detectors/doubled-punctuation.js +4 -2
- package/dist/detectors/doubled-punctuation.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/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/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-code-words.js +2 -2
- package/dist/detectors/heading-code-words.js.map +1 -1
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +36 -0
- 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.js +2 -2
- package/dist/detectors/kutoten-consistency.js.map +1 -1
- package/dist/detectors/lexicon-match.d.ts +10 -1
- package/dist/detectors/lexicon-match.d.ts.map +1 -1
- package/dist/detectors/lexicon-match.js +26 -1
- 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-sentence.d.ts +3 -1
- package/dist/detectors/list-sentence.d.ts.map +1 -1
- package/dist/detectors/list-sentence.js +26 -1
- package/dist/detectors/list-sentence.js.map +1 -1
- package/dist/detectors/long-vowel.d.ts.map +1 -1
- package/dist/detectors/long-vowel.js +18 -4
- package/dist/detectors/long-vowel.js.map +1 -1
- package/dist/detectors/markup-finding.d.ts +3 -1
- package/dist/detectors/markup-finding.d.ts.map +1 -1
- package/dist/detectors/markup-finding.js +10 -0
- package/dist/detectors/markup-finding.js.map +1 -1
- 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-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 +59 -28
- 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.map +1 -1
- package/dist/detectors/oxford-comma.js +1 -0
- 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/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/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/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.map +1 -1
- package/dist/detectors/structure-tree.js +3 -1
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +16 -2
- 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/url-run-on.d.ts.map +1 -1
- package/dist/detectors/url-run-on.js +6 -1
- package/dist/detectors/url-run-on.js.map +1 -1
- 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.d.ts +9 -3
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +55 -32
- package/dist/document.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 +11 -2
- package/dist/figure-references.d.ts.map +1 -1
- package/dist/figure-references.js +50 -13
- package/dist/figure-references.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/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/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 +9 -6
- package/dist/long-vowel.d.ts.map +1 -1
- package/dist/long-vowel.js +15 -8
- package/dist/long-vowel.js.map +1 -1
- package/dist/markup.d.ts.map +1 -1
- package/dist/markup.js +4 -2
- package/dist/markup.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/orthography.d.ts +8 -1
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +33 -12
- 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/plugin.d.ts +24 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/reasons.d.ts +1 -0
- package/dist/reasons.d.ts.map +1 -1
- package/dist/reasons.js +2 -0
- package/dist/reasons.js.map +1 -1
- 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 +3 -1
- package/dist/render/explain.d.ts.map +1 -1
- package/dist/render/explain.js +32 -15
- package/dist/render/explain.js.map +1 -1
- package/dist/render/rules-json.d.ts.map +1 -1
- package/dist/render/rules-json.js +16 -12
- package/dist/render/rules-json.js.map +1 -1
- 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/rule-guide.d.ts +19 -0
- package/dist/rule-guide.d.ts.map +1 -1
- package/dist/rule-guide.js +14 -0
- package/dist/rule-guide.js.map +1 -1
- 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 +5 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +31 -14
- package/dist/run.js.map +1 -1
- package/dist/setting-problems.d.ts.map +1 -1
- package/dist/setting-problems.js +3 -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/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/date-range.d.ts +10 -0
- package/dist/structure/date-range.d.ts.map +1 -1
- package/dist/structure/date-range.js +33 -1
- package/dist/structure/date-range.js.map +1 -1
- 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/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/universal.d.ts.map +1 -1
- package/dist/structure/universal.js +8 -2
- package/dist/structure/universal.js.map +1 -1
- package/dist/style-parse.d.ts +6 -0
- package/dist/style-parse.d.ts.map +1 -1
- package/dist/style-parse.js +32 -4
- package/dist/style-parse.js.map +1 -1
- package/dist/subheading-line.d.ts +19 -2
- package/dist/subheading-line.d.ts.map +1 -1
- package/dist/subheading-line.js +39 -11
- package/dist/subheading-line.js.map +1 -1
- 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/genres.yaml +42 -0
- package/package.json +7 -3
- package/rules/acronym-expansion-conflict.yaml +82 -0
- package/rules/adverb-overuse.yaml +2 -2
- package/rules/agentless-passive.yaml +28 -0
- package/rules/ai-tell.yaml +34 -0
- package/rules/announced-count-mismatch.yaml +2 -2
- package/rules/announcing-opener.yaml +31 -0
- package/rules/assistant-residue.yaml +30 -0
- package/rules/bold-density.yaml +28 -0
- package/rules/bold-label-list.yaml +81 -0
- package/rules/closing-cliche.yaml +27 -2
- package/rules/colon-lead-in.yaml +28 -4
- package/rules/contrast-framing.yaml +33 -2
- package/rules/cushion-phrase-density.yaml +32 -5
- package/rules/dangling-reference.yaml +1 -0
- package/rules/date-order.yaml +1 -0
- package/rules/date-range-reversed.yaml +2 -2
- package/rules/double-negative.yaml +51 -0
- package/rules/doubled-punctuation.yaml +2 -2
- package/rules/doubled-word.yaml +2 -2
- package/rules/duplicate-heading.yaml +78 -0
- package/rules/emoji-density.yaml +5 -4
- package/rules/empty-intensifier.yaml +25 -0
- package/rules/empty-section.yaml +74 -0
- package/rules/excessive-hedging.yaml +32 -4
- package/rules/fullwidth-alnum-consistency.yaml +53 -0
- package/rules/hankaku-kana.yaml +41 -0
- package/rules/image-alt-text.yaml +1 -1
- package/rules/invisible-character.yaml +63 -0
- package/rules/katakana-long-vowel.yaml +10 -9
- package/rules/latin-spacing.yaml +12 -5
- package/rules/max-kanji-continuous.yaml +1 -0
- package/rules/max-paragraph-length.yaml +1 -0
- package/rules/max-sentence-length.yaml +26 -0
- package/rules/modal-conflict.yaml +106 -0
- package/rules/name-variant.yaml +88 -0
- package/rules/no-doubled-joshi.yaml +1 -0
- package/rules/no-em-dash.yaml +26 -2
- package/rules/no-mixed-desumasu.yaml +1 -0
- package/rules/nominalization.yaml +89 -0
- package/rules/outside-announced-list.yaml +80 -0
- package/rules/padded-intro.yaml +25 -0
- package/rules/paragraph-length-variance.yaml +26 -2
- package/rules/preferred-term.yaml +1 -0
- package/rules/proper-noun-density.yaml +14 -5
- package/rules/ra-nuki.yaml +43 -0
- package/rules/requirement-modal.yaml +94 -0
- package/rules/requirement-smell.yaml +70 -0
- package/rules/rule-of-three.yaml +46 -0
- package/rules/section-length-uniformity.yaml +26 -2
- package/rules/sentence-rhythm.yaml +26 -0
- package/rules/space-before-punctuation.yaml +41 -0
- package/rules/spelling-consistency.yaml +47 -0
- package/rules/stock-transition.yaml +33 -2
- package/rules/taigen-dome-in-prose.yaml +14 -0
- package/rules/total-mismatch.yaml +1 -0
- package/rules/undefined-acronym.yaml +1 -0
- package/rules/unqualified-superlative.yaml +5 -4
- package/rules/unused-definition.yaml +75 -0
- package/rules/use-before-definition.yaml +77 -0
- package/rules/vague-figure-reference.yaml +66 -0
- package/skills/chaff/SKILL.md +108 -8
- package/src/acronym-expansions.ts +106 -0
- package/src/announced-count.ts +53 -11
- package/src/announced-list.ts +120 -0
- package/src/api.ts +154 -0
- package/src/cli-text.ts +6 -11
- package/src/cli.ts +64 -63
- package/src/closing-paragraph.ts +24 -0
- package/src/commands/compare.ts +11 -18
- package/src/commands/document-commands.ts +19 -0
- package/src/commands/eval.ts +3 -2
- package/src/commands/facts.ts +33 -0
- package/src/commands/feedback.ts +33 -1
- 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 +1 -1
- package/src/compare/clock-time.ts +5 -2
- package/src/compare/distinct.ts +13 -0
- package/src/compare/extract.ts +7 -5
- package/src/compare/fact-key.ts +31 -0
- package/src/compare/fact-text.ts +21 -2
- package/src/compare/facts-render.ts +63 -0
- package/src/compare/facts-text.ts +41 -0
- package/src/compare/match.ts +1 -1
- package/src/compare/outcome.ts +14 -4
- package/src/compare/proper-nouns.ts +4 -4
- package/src/compare/render.ts +2 -2
- package/src/compare/text-atoms.ts +7 -6
- package/src/compare/text.ts +3 -2
- package/src/config/load.ts +9 -0
- package/src/config/option-problems.ts +6 -4
- package/src/config/style.ts +14 -1
- package/src/custom/load.ts +11 -3
- package/src/custom/module-path.ts +23 -0
- package/src/custom/parse.ts +67 -18
- package/src/custom/problems.ts +63 -41
- package/src/detect-language.ts +1 -1
- package/src/detect.ts +10 -3
- package/src/detectors/ai-phrasing.ts +6 -2
- package/src/detectors/bold-label.ts +55 -0
- package/src/detectors/dangling-figure.ts +8 -4
- package/src/detectors/definition-use.ts +41 -0
- package/src/detectors/doubled-punctuation.ts +5 -2
- package/src/detectors/duplicate-heading.ts +47 -0
- package/src/detectors/empty-section.ts +21 -0
- package/src/detectors/fullwidth-alnum.ts +118 -0
- package/src/detectors/hankaku-kana.ts +38 -0
- package/src/detectors/heading-code-words.ts +2 -2
- package/src/detectors/index.ts +36 -0
- package/src/detectors/invisible-character.ts +190 -0
- package/src/detectors/kutoten-consistency.ts +2 -2
- package/src/detectors/lexicon-match.ts +33 -1
- package/src/detectors/lexicon.ts +40 -13
- package/src/detectors/list-sentence.ts +45 -4
- package/src/detectors/long-vowel.ts +20 -4
- package/src/detectors/markup-finding.ts +16 -1
- package/src/detectors/modal-conflict.ts +26 -0
- package/src/detectors/name-variant.ts +15 -0
- package/src/detectors/nominalization.ts +73 -0
- package/src/detectors/orthography.ts +77 -27
- package/src/detectors/outside-announced-list.ts +25 -0
- package/src/detectors/oxford-comma.ts +1 -0
- package/src/detectors/phrase-match.ts +27 -7
- package/src/detectors/ra-nuki.ts +38 -0
- package/src/detectors/requirement-modal.ts +67 -0
- package/src/detectors/requirement-smell.ts +52 -0
- package/src/detectors/space-before-punctuation.ts +32 -0
- package/src/detectors/spelling-variety.ts +81 -0
- package/src/detectors/structure-tree.ts +3 -1
- package/src/detectors/structure.ts +17 -3
- package/src/detectors/superlative-comparison.ts +47 -0
- package/src/detectors/url-run-on.ts +7 -1
- package/src/detectors/vague-figure-pointer.ts +58 -0
- package/src/detectors/word-list.ts +6 -1
- package/src/document.ts +88 -41
- 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 +73 -12
- 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/language-sample.ts +48 -0
- package/src/link-line.ts +13 -0
- package/src/long-vowel.ts +18 -8
- package/src/markup.ts +4 -2
- package/src/name-variants.ts +217 -0
- package/src/node-version.ts +22 -0
- package/src/not-run.ts +16 -0
- package/src/orthography.ts +40 -11
- package/src/outline/render.ts +85 -0
- package/src/outline/shape.ts +72 -0
- package/src/outline/text.ts +50 -0
- package/src/plugin.ts +21 -4
- package/src/reasons.ts +3 -0
- package/src/render/compact.ts +13 -3
- package/src/render/explain.ts +47 -20
- package/src/render/rules-json.ts +18 -12
- package/src/render/suppressions.ts +30 -2
- package/src/rule-guide.ts +38 -0
- package/src/run-semantic.ts +2 -1
- package/src/run.ts +37 -17
- package/src/setting-problems.ts +3 -1
- package/src/spacing-minority.ts +27 -0
- package/src/stet-block.ts +60 -0
- package/src/stet.ts +41 -15
- package/src/structure/date-range.ts +49 -1
- package/src/structure/definition-use.ts +130 -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/universal.ts +10 -2
- package/src/style-parse.ts +38 -3
- package/src/subheading-line.ts +51 -13
- package/src/tag-coverage.ts +13 -0
- package/styles/ieice.yaml +5 -4
- package/styles/jis-z8301-2011.yaml +5 -2
- 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
package/src/detectors/lexicon.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { namesQuantity } from "./superlative-name.ts";
|
|
|
8
8
|
import { namesAmount } from "./superlative-amount.ts";
|
|
9
9
|
import { restricted, type Restrictors } from "./superlative-clause.ts";
|
|
10
10
|
import { stackedHedges, type StackedHedge } from "./stacked-hedge.ts";
|
|
11
|
+
import { comparisonMarkersOf, counterpartBefore, onlyQuoted, quotedRange, type ComparisonMarkers } from "./superlative-comparison.ts";
|
|
11
12
|
|
|
12
13
|
const PER = 1000;
|
|
13
14
|
|
|
@@ -19,30 +20,52 @@ type Hit = { readonly sentence: Sentence; readonly matched: string };
|
|
|
19
20
|
const hitsFor = (doc: ProseDocument, lexicon: Lexicon): Hit[] =>
|
|
20
21
|
doc.sentences.flatMap((sentence) => lexicon.filter((entry) => entryIn(sentence, entry)).map((entry) => ({ sentence, matched: entry.pattern })));
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* 床より短い文書の扱い。skip は測らない。at-floor は SHORT_LENGTH の長さの文書として測り、一つだけなら言わない(一つは礼儀)。
|
|
25
|
+
* クッション言葉はメールや手紙のような短い文書に重なるので at-floor。逃げの表現は短い文書でも一文に重ねた形で見つかるので skip。
|
|
26
|
+
*/
|
|
27
|
+
type ShortDocuments = "skip" | "at-floor";
|
|
28
|
+
|
|
29
|
+
/** 短い文書を測るときの長さ。どちらの言語でも、既定の水準で三つ目から言う長さ(二つは「お忙しいところ恐れ入りますが」のように普通に重なる)。 */
|
|
30
|
+
const SHORT_LENGTH = { word: 400, char: 500 };
|
|
31
|
+
|
|
32
|
+
/** 短い文書でも、これより少なければ言わない。 */
|
|
33
|
+
const SHORT_MINIMUM_HITS = 2;
|
|
34
|
+
|
|
35
|
+
const perThousand = (count: number, length: number): number => (length === 0 ? 0 : Math.round((count / length) * PER));
|
|
36
|
+
|
|
22
37
|
/**
|
|
23
38
|
* 単位長あたりの出現率。件数で数えると長い文書ほど当たる(bold-density と同じ)。
|
|
24
|
-
*
|
|
39
|
+
* 短すぎて測らない文書、1 つも無いとき、閾値に収まるときは undefined。
|
|
25
40
|
*/
|
|
41
|
+
export const rateOver = (doc: ProseDocument, count: number, limit: number): number | undefined => {
|
|
42
|
+
const length = wordsOf(doc);
|
|
43
|
+
const rate = perThousand(count, length);
|
|
44
|
+
return length < FLOOR[doc.lengthUnit] || count === 0 || rate <= limit ? undefined : rate;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** rule の id は呼び出し側が持つ。detector は「密度が閾値を超えたか」しか知らない。指摘が言う密度は、短い文書でも文書の実際の長さでの値。 */
|
|
26
48
|
const densityRule =
|
|
27
|
-
(rule: string): Detector =>
|
|
49
|
+
(rule: string, short: ShortDocuments = "skip"): Detector =>
|
|
28
50
|
(doc, options): Finding[] => {
|
|
29
51
|
const hits = hitsFor(doc, options.lexicon ?? []);
|
|
30
52
|
const length = wordsOf(doc);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (length
|
|
53
|
+
const isShort = length < FLOOR[doc.lengthUnit];
|
|
54
|
+
if (hits.length === 0 || (isShort && (short === "skip" || hits.length < SHORT_MINIMUM_HITS))) return [];
|
|
55
|
+
if (perThousand(hits.length, isShort ? SHORT_LENGTH[doc.lengthUnit] : length) <= options.limit) return [];
|
|
56
|
+
const density = perThousand(hits.length, length);
|
|
34
57
|
return hits.map((hit) => ({
|
|
35
58
|
rule,
|
|
36
59
|
severity: "warning",
|
|
37
60
|
line: 0,
|
|
38
61
|
column: 0,
|
|
39
62
|
quote: hit.sentence.text.trim(),
|
|
40
|
-
values: { matched: hit.matched, count: hits.length, density
|
|
63
|
+
values: { matched: hit.matched, count: hits.length, density, limit: options.limit, offset: hit.sentence.span.start },
|
|
41
64
|
}));
|
|
42
65
|
};
|
|
43
66
|
|
|
44
67
|
const hedgingDensity = densityRule("excessive-hedging");
|
|
45
|
-
export const cushionDensity = densityRule("cushion-phrase-density");
|
|
68
|
+
export const cushionDensity = densityRule("cushion-phrase-density", "at-floor");
|
|
46
69
|
|
|
47
70
|
/** 書いたとおりの字。行の折り返しをまたいでいたら空白 1 つに。 */
|
|
48
71
|
const writtenAt = (source: string, span: Span): string => source.slice(span.start, span.end).replace(/\s+/gu, " ").trim();
|
|
@@ -83,7 +106,7 @@ export const hedging: Detector = (doc, options): Finding[] => {
|
|
|
83
106
|
const DIGIT = /\d/u;
|
|
84
107
|
|
|
85
108
|
type Qualifiers = {
|
|
86
|
-
readonly comparison:
|
|
109
|
+
readonly comparison: ComparisonMarkers;
|
|
87
110
|
readonly scope: ScopeMarkers;
|
|
88
111
|
readonly quantityNouns: Lexicon;
|
|
89
112
|
readonly amounts: Lexicon;
|
|
@@ -91,7 +114,7 @@ type Qualifiers = {
|
|
|
91
114
|
};
|
|
92
115
|
|
|
93
116
|
const qualifiersOf = (doc: ProseDocument): Qualifiers => ({
|
|
94
|
-
comparison: doc.lexicons["comparison-marker"] ?? [],
|
|
117
|
+
comparison: comparisonMarkersOf(doc.lexicons["comparison-marker"] ?? []),
|
|
95
118
|
scope: scopeMarkersOf(doc.lexicons["superlative-scope"] ?? []),
|
|
96
119
|
quantityNouns: doc.lexicons["quantity-noun"] ?? [],
|
|
97
120
|
amounts: doc.lexicons["superlative-amount"] ?? [],
|
|
@@ -102,22 +125,26 @@ const qualifiersOf = (doc: ProseDocument): Qualifiers => ({
|
|
|
102
125
|
},
|
|
103
126
|
});
|
|
104
127
|
|
|
105
|
-
/**
|
|
128
|
+
/** 範囲・節・分詞・形容詞・すぐ前の相手のどれかが最上級を限っているか、最上級が量か名前を言っているか。 */
|
|
106
129
|
const qualifiedAt = (tokens: readonly Token[], range: TokenRange, qualifiers: Qualifiers): boolean =>
|
|
130
|
+
counterpartBefore(tokens, range, qualifiers.comparison.before) ||
|
|
107
131
|
scoped(tokens, range, qualifiers.scope) ||
|
|
108
132
|
restricted(tokens, range, qualifiers.restrictors) ||
|
|
109
133
|
namesQuantity(tokens, range, qualifiers.quantityNouns) ||
|
|
110
134
|
namesAmount(tokens, range, qualifiers.amounts);
|
|
111
135
|
|
|
112
|
-
/**
|
|
136
|
+
/** どの出現も引いた言葉か、限られているか、量を言うときだけ。1 つでもそうでない出現があれば、その文には限定の無い最上級がある。 */
|
|
113
137
|
const everyQualified = (sentence: Sentence, entry: LexiconEntry, qualifiers: Qualifiers): boolean => {
|
|
114
138
|
const tokens = sentence.tokens ?? [];
|
|
115
139
|
const ranges = entryRanges(sentence, entry);
|
|
116
|
-
return ranges.length > 0 && ranges.every((range) => qualifiedAt(tokens, range, qualifiers));
|
|
140
|
+
return ranges.length > 0 && ranges.every((range) => quotedRange(sentence, range) || qualifiedAt(tokens, range, qualifiers));
|
|
117
141
|
};
|
|
118
142
|
|
|
119
143
|
const qualified = (sentence: Sentence, entry: LexiconEntry, qualifiers: Qualifiers): boolean =>
|
|
120
|
-
DIGIT.test(sentence.text) ||
|
|
144
|
+
DIGIT.test(sentence.text) ||
|
|
145
|
+
onlyQuoted(sentence, entry) ||
|
|
146
|
+
qualifiers.comparison.anywhere.some((marker) => entryIn(sentence, marker)) ||
|
|
147
|
+
everyQualified(sentence, entry, qualifiers);
|
|
121
148
|
|
|
122
149
|
const bareHits = (doc: ProseDocument, lexicon: Lexicon): Hit[] => {
|
|
123
150
|
const qualifiers = qualifiersOf(doc);
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import type { Lexicon, Token } from "../plugin.ts";
|
|
1
|
+
import type { Lexicon, LexiconEntry, Token } from "../plugin.ts";
|
|
2
2
|
import { citedTitles } from "./cited-title.ts";
|
|
3
3
|
import { columnOf, type Column } from "./token-column.ts";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 並びを読むための語彙表。participle は解析器が分詞と読まないが読点のあとで分詞の句を始める語(meaning)、
|
|
7
|
-
* example は例を挙げる句(such as, e.g.)、pair は 2 つだけを結ぶ語とその接続詞(between and / either or
|
|
7
|
+
* example は例を挙げる句(such as, e.g.)、pair は 2 つだけを結ぶ語とその接続詞(between and / either or)、
|
|
8
|
+
* region は地名のあとに読点を挟んで添える州や国の名(New London, Wisconsin)。
|
|
8
9
|
*/
|
|
9
|
-
export type ListWords = {
|
|
10
|
+
export type ListWords = {
|
|
11
|
+
readonly participle: ReadonlySet<string>;
|
|
12
|
+
readonly example: Lexicon;
|
|
13
|
+
readonly pair: ReadonlySet<string>;
|
|
14
|
+
readonly region: Lexicon;
|
|
15
|
+
};
|
|
10
16
|
|
|
11
17
|
const LIST_CONJUNCTION: ReadonlySet<string> = new Set(["and", "or"]);
|
|
12
18
|
|
|
@@ -60,6 +66,40 @@ const byDepth = (depths: readonly number[], test: (index: number) => boolean): R
|
|
|
60
66
|
|
|
61
67
|
const isComma = (token: Token): boolean => token.surface === ",";
|
|
62
68
|
|
|
69
|
+
const surfacesOf = ({ pattern, tokens: words = [] }: LexiconEntry): string[] => (words.length > 0 ? words.map((word) => word.surface) : pattern.split(" "));
|
|
70
|
+
|
|
71
|
+
const writtenAt = (tokens: readonly Token[], start: number, entry: LexiconEntry): boolean =>
|
|
72
|
+
surfacesOf(entry).every((surface, offset) => tokens[start + offset]?.surface === surface);
|
|
73
|
+
|
|
74
|
+
/** start から書いてある州や国の名。語ごとに書いたとおりに照らす。 */
|
|
75
|
+
const regionAt = (tokens: readonly Token[], start: number, regions: Lexicon): LexiconEntry | undefined =>
|
|
76
|
+
regions.find((entry) => writtenAt(tokens, start, entry));
|
|
77
|
+
|
|
78
|
+
/** 名の後ろが文や句の切れ目(, . ; : ) か文の終わり)。New London, Wisconsin, and … の Wisconsin。 */
|
|
79
|
+
const closesName = (token: Token | undefined): boolean => token === undefined || [",", ".", ";", ":", ")"].includes(token.surface);
|
|
80
|
+
|
|
81
|
+
/** at の直前が州や国の名で終わる(Texas, Florida, … の Texas)。名の長さの分だけ前から照らす。 */
|
|
82
|
+
const endsWithRegion = (tokens: readonly Token[], at: number, regions: Lexicon): boolean =>
|
|
83
|
+
regions.some((entry) => {
|
|
84
|
+
const start = at - surfacesOf(entry).length;
|
|
85
|
+
return start >= 0 && writtenAt(tokens, start, entry);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 地名と、それに添えた州や国の名のあいだの読点(New London, Wisconsin, and a photo / Lyon, France, then)。並びの区切りではない。
|
|
90
|
+
* 前が固有名詞で、それ自身が州や国の名でなく(Texas, Florida, and Ohio は州の並び)、後ろの名が切れ目で閉じるときだけ。
|
|
91
|
+
* 地名の後ろにしか書かない名(position: after。Washington, D.C.)は、前が州の名でも地名に添えたもの。
|
|
92
|
+
*/
|
|
93
|
+
const regionCommasOf = (tokens: readonly Token[], regions: Lexicon): ReadonlySet<number> =>
|
|
94
|
+
new Set(
|
|
95
|
+
tokens.flatMap((token, at) => {
|
|
96
|
+
if (!isComma(token) || tokens[at - 1]?.pos !== "PROPN") return [];
|
|
97
|
+
const region = regionAt(tokens, at + 1, regions);
|
|
98
|
+
if (region === undefined || !closesName(tokens[at + 1 + surfacesOf(region).length])) return [];
|
|
99
|
+
return region.position === "after" || !endsWithRegion(tokens, at, regions) ? [at] : [];
|
|
100
|
+
}),
|
|
101
|
+
);
|
|
102
|
+
|
|
63
103
|
/** 項目への問いの列。読点は項目に入ったり入らなかったりするので、脇に置いて問いごとに数える(token-column.ts)。 */
|
|
64
104
|
const columnsOf = (tokens: readonly Token[], depths: readonly number[]) => {
|
|
65
105
|
const commaDepth = (token: Token, index: number): number | undefined => (isComma(token) ? depths[index] : undefined);
|
|
@@ -143,6 +183,7 @@ export const listSentenceOf = (tokens: readonly Token[], words: ListWords, sourc
|
|
|
143
183
|
const depths = depthsOf(tokens);
|
|
144
184
|
const column = columnsOf(tokens, depths);
|
|
145
185
|
const exampleEnds = exampleEndsOf(tokens, depths, column, words.example);
|
|
186
|
+
const regionCommas = regionCommasOf(tokens, words.region);
|
|
146
187
|
return {
|
|
147
188
|
tokens,
|
|
148
189
|
depths,
|
|
@@ -151,7 +192,7 @@ export const listSentenceOf = (tokens: readonly Token[], words: ListWords, sourc
|
|
|
151
192
|
exampleEnds,
|
|
152
193
|
exampleStarts: byDepth(depths, (index) => (exampleEnds[index]?.length ?? 0) > 0),
|
|
153
194
|
pairOpeners: pairOpenersOf(tokens, depths, words.pair),
|
|
154
|
-
commas: byDepth(depths, (index) => tokens[index]?.surface === ","),
|
|
195
|
+
commas: byDepth(depths, (index) => tokens[index]?.surface === "," && !regionCommas.has(index)),
|
|
155
196
|
inCitedTitle: citedTitles(tokens, source),
|
|
156
197
|
};
|
|
157
198
|
};
|
|
@@ -9,12 +9,28 @@ const endingOf = (value: OptionValue | undefined): Ending => ENDINGS.find((endin
|
|
|
9
9
|
const wordsOf = (value: OptionValue | undefined): readonly string[] =>
|
|
10
10
|
Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === "string") : [];
|
|
11
11
|
|
|
12
|
-
/** The minimum when no setting gives one:
|
|
13
|
-
const DEFAULT_MIN_MORAE =
|
|
12
|
+
/** The minimum when no setting gives one: two morae before the final ー, which leaves カー alone. */
|
|
13
|
+
const DEFAULT_MIN_MORAE = 2;
|
|
14
14
|
|
|
15
15
|
/** A listed word is exempt written either way: listing コンピューター exempts コンピュータ too. */
|
|
16
16
|
const exemptStems = (except: readonly string[]): ReadonlySet<string> => new Set(except.map((word) => stemOf(word.trim())));
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Words that become another word with a final ー (フリ, as in 振り, and フリー, free): the language's long-vowel-distinct word list.
|
|
20
|
+
* Both are nouns to the tagger, so only the list tells them apart; they are left out as if listed under except.
|
|
21
|
+
* The list is optional: without it the rule still runs and compares every word.
|
|
22
|
+
*/
|
|
23
|
+
const distinctWordsOf = (doc: ProseDocument): string[] => (doc.lexicons["long-vowel-distinct"] ?? []).map((entry) => entry.pattern);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The kana a final ー follows where drop drops it: the language's long-vowel-drop-after list (ア段, the -er, -or, -ar of
|
|
27
|
+
* JIS Z 8301:2011 G.6.2.2). Without the list, drop reaches every final ー.
|
|
28
|
+
*/
|
|
29
|
+
const dropAfterOf = (doc: ProseDocument): ReadonlySet<string> | undefined => {
|
|
30
|
+
const kana = doc.lexicons["long-vowel-drop-after"];
|
|
31
|
+
return kana === undefined ? undefined : new Set(kana.map((entry) => entry.pattern));
|
|
32
|
+
};
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* The katakana nouns of a sentence, as the language adapter split them: ユーザー inside ユーザーインターフェース is its own word.
|
|
20
36
|
* Proper nouns (PROPN) and the team's names keep their own spelling (ディズニー).
|
|
@@ -42,9 +58,9 @@ const quoteAt = (doc: ProseDocument, offset: number): string =>
|
|
|
42
58
|
export const katakanaLongVowel: Detector = (doc, options): Finding[] => {
|
|
43
59
|
const settings = options.settings ?? {};
|
|
44
60
|
const minMorae = typeof settings["min_morae"] === "number" ? settings["min_morae"] : DEFAULT_MIN_MORAE;
|
|
45
|
-
const exempt = exemptStems(wordsOf(settings["except"]));
|
|
61
|
+
const exempt = exemptStems([...wordsOf(settings["except"]), ...distinctWordsOf(doc)]);
|
|
46
62
|
const words = doc.sentences.flatMap((sentence) => kanaWordsOf(sentence, doc.names ?? [], exempt));
|
|
47
|
-
const odd = oddLongVowels(words, endingOf(settings["ending"]), minMorae);
|
|
63
|
+
const odd = oddLongVowels(words, endingOf(settings["ending"]), minMorae, dropAfterOf(doc));
|
|
48
64
|
if (odd.length === 0 || odd.length < options.limit) return [];
|
|
49
65
|
return odd.map((entry) => ({
|
|
50
66
|
rule: "",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Finding, Markup, ProseDocument, Span } from "../plugin.ts";
|
|
1
|
+
import type { Finding, Markup, MarkupHeading, ProseDocument, Span } from "../plugin.ts";
|
|
2
|
+
import { hasTitle } from "../heading-title.ts";
|
|
2
3
|
|
|
3
4
|
// 記法の rule(見出し・画像・リンク・URL)が指摘を作る形。
|
|
4
5
|
|
|
@@ -22,3 +23,17 @@ export const findingAt = (doc: ProseDocument, span: Span, values: Readonly<Recor
|
|
|
22
23
|
|
|
23
24
|
/** Markdown の文書の記法。Markdown でなければ undefined。 */
|
|
24
25
|
export const markupOf = (doc: ProseDocument): Markup | undefined => (doc.markup?.markdown === true ? doc.markup : undefined);
|
|
26
|
+
|
|
27
|
+
/** 文の終わりの句点。下線で書く見出し(setext)の言葉がこれで終わるなら、区切り線の上の文。 */
|
|
28
|
+
const SENTENCE_END = /[.。!?!?]$/u;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 下線で書く見出し(setext)のうち、区切り線(メールの「-----」)の上の段落を Markdown が見出しと読んだもの。
|
|
32
|
+
* 二行以上にわたるか、句点で終わる。書き手は見出しを立てていない。
|
|
33
|
+
*/
|
|
34
|
+
const isUnderlinedParagraph = (source: string, heading: MarkupHeading): boolean =>
|
|
35
|
+
!source.startsWith("#", heading.start) && (heading.text.includes("\n") || SENTENCE_END.test(heading.text));
|
|
36
|
+
|
|
37
|
+
/** 見出しとして書いた見出し。題の無い見出し(`## ---`)と、区切り線の上の段落は外す。 */
|
|
38
|
+
export const writtenHeadings = (doc: ProseDocument): MarkupHeading[] =>
|
|
39
|
+
(markupOf(doc)?.headings ?? []).filter((heading) => hasTitle(heading.text) && !isUnderlinedParagraph(doc.source, heading));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Detector, Finding, StructureNode } from "../plugin.ts";
|
|
2
|
+
import { inDocumentOrder } from "../structure/issues.ts";
|
|
3
|
+
import { modalConflicts, modalStatements, type Obligation } from "../structure/modal-conflict.ts";
|
|
4
|
+
import { linesOf, lineNumberAt } from "../structure/lines.ts";
|
|
5
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
6
|
+
|
|
7
|
+
const obligationsOf = (tree: StructureNode): Obligation[] =>
|
|
8
|
+
inDocumentOrder(tree).flatMap((node) =>
|
|
9
|
+
node.kind === "obligation"
|
|
10
|
+
? [{ start: node.span.start, end: node.span.end, type: String(node.attrs["type"] ?? ""), marker: String(node.attrs["marker"] ?? "") }]
|
|
11
|
+
: [],
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/** 同じ主語と行為に、前の文と逆の様相(しなければならない と してはならない、may と must not)を書いた文。 */
|
|
15
|
+
export const modalConflict: Detector = (doc): Finding[] => {
|
|
16
|
+
if (doc.structure === undefined) return [];
|
|
17
|
+
const lines = linesOf(doc.source);
|
|
18
|
+
return modalConflicts(modalStatements(obligationsOf(doc.structure), doc.sentences)).map(({ statement, earlier }) => ({
|
|
19
|
+
rule: "",
|
|
20
|
+
severity: "warning",
|
|
21
|
+
line: 0,
|
|
22
|
+
column: 0,
|
|
23
|
+
quote: quoteAt(doc.source, statement.offset),
|
|
24
|
+
values: { marker: statement.marker, other: earlier.marker, otherLine: lineNumberAt(lines, earlier.offset) ?? 0, offset: statement.offset },
|
|
25
|
+
}));
|
|
26
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
2
|
+
import { mentionsIn, nameVariants } from "../name-variants.ts";
|
|
3
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
4
|
+
|
|
5
|
+
/** 同じ名前を、文書の中で少しだけ違う形に書いた所(GitHub と Github、山田太郎 と 山田太朗)。少ないほうを指す。 */
|
|
6
|
+
export const nameVariant: Detector = (doc): Finding[] =>
|
|
7
|
+
nameVariants(doc.sentences.flatMap((sentence) => mentionsIn(sentence.tokens ?? [], doc.source))).map(({ mention, usual, kind }) => ({
|
|
8
|
+
rule: "",
|
|
9
|
+
severity: "warning",
|
|
10
|
+
line: 0,
|
|
11
|
+
column: 0,
|
|
12
|
+
quote: quoteAt(doc.source, mention.offset),
|
|
13
|
+
values: { name: mention.surface, usual, offset: mention.offset },
|
|
14
|
+
variant: kind,
|
|
15
|
+
}));
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Detector, Finding, Lexicon, ProseDocument, Sentence, Token } from "../plugin.ts";
|
|
2
|
+
import { entryRanges, type TokenRange } from "./lexicon-match.ts";
|
|
3
|
+
import { rateOver } from "./lexicon.ts";
|
|
4
|
+
|
|
5
|
+
// A verb written as a noun and carried by another verb: 調査を実施した for 調査した, "make a decision" for "decide"
|
|
6
|
+
// (the やさしい日本語 guideline; the Federal Plain Language Guidelines' hidden verbs; GOV.UK). Two shapes, each from a
|
|
7
|
+
// lexicon the language may or may not have: a whole phrase with its verb (nominalization-phrase), or a verbal noun
|
|
8
|
+
// (the adapter's VerbForm=Vnoun) followed by a carrying verb (nominalization-light-verb). Counted as a density.
|
|
9
|
+
|
|
10
|
+
export type Hidden = { readonly sentence: Sentence; readonly offset: number; readonly matched: string; readonly preferred: string };
|
|
11
|
+
|
|
12
|
+
const PHRASES = "nominalization-phrase";
|
|
13
|
+
const LIGHT_VERBS = "nominalization-light-verb";
|
|
14
|
+
/** Verbal nouns whose carrying verb means "hold" (研修を実施する is not 研修する): not hidden verbs. */
|
|
15
|
+
const EVENT_NOUNS = "nominalization-event-noun";
|
|
16
|
+
|
|
17
|
+
const isVerbalNoun = (token: Token | undefined): token is Token => token?.features?.["VerbForm"] === "Vnoun";
|
|
18
|
+
|
|
19
|
+
const writtenBetween = (source: string, tokens: readonly Token[], range: TokenRange): string => {
|
|
20
|
+
const [first, last] = [tokens[range.start], tokens[range.end - 1]];
|
|
21
|
+
return first === undefined || last === undefined ? "" : source.slice(first.span.start, last.span.end);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** A phrase of the lexicon, with the verb it hides (instead_of). */
|
|
25
|
+
const phrasesIn = (sentence: Sentence, source: string, phrases: Lexicon): Hidden[] =>
|
|
26
|
+
phrases.flatMap((entry) =>
|
|
27
|
+
entryRanges(sentence, entry).map((range) => ({
|
|
28
|
+
sentence,
|
|
29
|
+
offset: sentence.tokens?.[range.start]?.span.start ?? sentence.span.start,
|
|
30
|
+
matched: writtenBetween(source, sentence.tokens ?? [], range),
|
|
31
|
+
preferred: entry.instead_of ?? "",
|
|
32
|
+
})),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A carrying verb right after a verbal noun: 調査 + を実施した. Both sides are named in the dictionary form, the noun and the
|
|
37
|
+
* entry (調査を実施する), and the verb to write is the noun and the entry's instead_of (調査 + する).
|
|
38
|
+
*/
|
|
39
|
+
const lightVerbsIn = (sentence: Sentence, lightVerbs: Lexicon, eventNouns: ReadonlySet<string>): Hidden[] => {
|
|
40
|
+
const tokens = sentence.tokens ?? [];
|
|
41
|
+
return lightVerbs.flatMap((entry) =>
|
|
42
|
+
entryRanges(sentence, entry).flatMap((range): Hidden[] => {
|
|
43
|
+
const noun = tokens[range.start - 1];
|
|
44
|
+
if (!isVerbalNoun(noun) || eventNouns.has(noun.surface)) return [];
|
|
45
|
+
return [{ sentence, offset: noun.span.start, matched: `${noun.surface}${entry.pattern}`, preferred: `${noun.surface}${entry.instead_of ?? ""}` }];
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Pure: every hidden verb in the document, in the order they are written. */
|
|
51
|
+
export const hiddenVerbs = (doc: Pick<ProseDocument, "sentences" | "source" | "lexicons">): Hidden[] => {
|
|
52
|
+
const eventNouns = new Set((doc.lexicons[EVENT_NOUNS] ?? []).map((entry) => entry.pattern));
|
|
53
|
+
return doc.sentences
|
|
54
|
+
.flatMap((sentence) => [
|
|
55
|
+
...phrasesIn(sentence, doc.source, doc.lexicons[PHRASES] ?? []),
|
|
56
|
+
...lightVerbsIn(sentence, doc.lexicons[LIGHT_VERBS] ?? [], eventNouns),
|
|
57
|
+
])
|
|
58
|
+
.toSorted((left, right) => left.offset - right.offset);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const nominalization: Detector = (doc, options): Finding[] => {
|
|
62
|
+
const hidden = hiddenVerbs(doc);
|
|
63
|
+
const rate = rateOver(doc, hidden.length, options.limit);
|
|
64
|
+
if (rate === undefined) return [];
|
|
65
|
+
return hidden.map((found) => ({
|
|
66
|
+
rule: "",
|
|
67
|
+
severity: "info",
|
|
68
|
+
line: 0,
|
|
69
|
+
column: 0,
|
|
70
|
+
quote: found.sentence.text.trim(),
|
|
71
|
+
values: { matched: found.matched, preferred: found.preferred, count: hidden.length, density: rate, limit: options.limit, offset: found.offset },
|
|
72
|
+
}));
|
|
73
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Detector, Finding, ProseDocument, Sentence, Span } from "../plugin.ts";
|
|
2
2
|
import { calendarRuns, calendarUnitsOf, type CalendarUnits } from "../calendar-number.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { escapeRegExp, latinBoundaries, occurrencesOutside, type Boundary, type SpacingKind } from "../orthography.ts";
|
|
4
|
+
import { minorityReport } from "../spacing-minority.ts";
|
|
4
5
|
import { isWithinAny, quotedSpans } from "../quoted-span.ts";
|
|
5
6
|
import { digitRunAround, endsWithDivisionLabel, isNumberName, sequenceLabelStarts, type NameContext } from "../number-name.ts";
|
|
6
7
|
|
|
@@ -36,17 +37,43 @@ const digitBeside = (boundary: Boundary): number => {
|
|
|
36
37
|
* 文書全体で一度だけ読むもの(number-name.ts の NameContext に加えて)。calendar は日付・時刻の単位、
|
|
37
38
|
* divisions は「第1節」のように「第」と番号の後ろに書く区切りの語。
|
|
38
39
|
*/
|
|
39
|
-
type NumberContext = NameContext & {
|
|
40
|
+
type NumberContext = NameContext & {
|
|
41
|
+
readonly calendar: CalendarUnits;
|
|
42
|
+
readonly divisions: ReadonlySet<string>;
|
|
43
|
+
readonly itemNumbers: ReadonlySet<string>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** 文頭の項目の番号の後ろと見る境目の位置の上限。番号は短く文の頭にあるので、これより後ろの境目は番号の後ろではない。長い文で文頭からの切り出しを繰り返さない。 */
|
|
47
|
+
const ITEM_NUMBER_REACH = 8;
|
|
48
|
+
|
|
49
|
+
/** 行の頭の字下げと箇条書きの印。 */
|
|
50
|
+
const ITEM_LEAD = /^[\s\-*+]*/u;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 文書が項目の番号として行の頭に並べたもの(語彙表 item-number は並びの順)。行の頭に空白で本文と区切って書かれ、
|
|
54
|
+
* 前か次の番号も同じように書かれているものだけ。「一」「二」は番号、前後の無い「十 GBまで」の十は数量。
|
|
55
|
+
*/
|
|
56
|
+
const numberedItems = (ordered: readonly string[], source: string): ReadonlySet<string> => {
|
|
57
|
+
if (ordered.length === 0) return new Set();
|
|
58
|
+
const labels = ordered.toSorted((left, right) => right.length - left.length).map(escapeRegExp);
|
|
59
|
+
const atHead = new Set([...source.matchAll(new RegExp(`^[ \\t\\-*+]*(${labels.join("|")})[ \\u3000]`, "gmu"))].map((match) => match[1]));
|
|
60
|
+
return new Set(ordered.filter((label, at) => atHead.has(label) && (atHead.has(ordered[at - 1]) || atHead.has(ordered[at + 1]))));
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** 境目が、文頭の項目の番号と本文を分ける空白か(「一 JIS」)。 */
|
|
64
|
+
const followsItemNumber = (text: string, boundary: Boundary, itemNumbers: ReadonlySet<string>): boolean =>
|
|
65
|
+
boundary.spaced && boundary.offset <= ITEM_NUMBER_REACH && itemNumbers.has(text.slice(0, boundary.offset).replace(ITEM_LEAD, ""));
|
|
40
66
|
|
|
41
67
|
/** 文の中の日付・時刻の数の、並びの頭の位置。 */
|
|
42
68
|
const calendarStarts = (sentence: Sentence, units: CalendarUnits): ReadonlySet<number> =>
|
|
43
69
|
new Set(calendarRuns(sentence.text, sentence.tokens, sentence.span.start, units).map(({ run }) => run.start));
|
|
44
70
|
|
|
45
71
|
/**
|
|
46
|
-
* 番号・識別子として書かれた数(number-name.ts)、日付・時刻の数、「第1
|
|
72
|
+
* 番号・識別子として書かれた数(number-name.ts)、日付・時刻の数、「第1節」の後ろの境目、文頭の項目の番号(「一 JIS」)の後ろの境目は、空け方の好みではないので数えない。
|
|
47
73
|
* 日付・時刻は前の境目(「は 9月」「午後3時」「令和 3 年」)も数えない。日付はまとめて一つの書き方で、数量の空け方の票にはしない。
|
|
48
74
|
*/
|
|
49
75
|
const isCounted = (sentence: Sentence, boundary: Boundary, context: NumberContext, calendar: ReadonlySet<number>): boolean => {
|
|
76
|
+
if (followsItemNumber(sentence.text, boundary, context.itemNumbers)) return false;
|
|
50
77
|
if (boundary.kind !== "after-digit" && endsWithDivisionLabel(sentence.text.slice(0, boundary.offset), context.divisions)) return false;
|
|
51
78
|
if (boundary.kind === "letter") return true;
|
|
52
79
|
const run = digitRunAround(sentence.text, digitBeside(boundary));
|
|
@@ -68,6 +95,43 @@ const labelsAt = (doc: ProseDocument, position: "before" | "after"): ReadonlySet
|
|
|
68
95
|
*/
|
|
69
96
|
const isQuoted = (quoted: readonly Span[], boundary: Boundary): boolean => isWithinAny(quoted, { start: boundary.offset, end: boundary.offset });
|
|
70
97
|
|
|
98
|
+
/**
|
|
99
|
+
* リンクの文字の中の境目。リンクの文字は引いた記事や資料の題であることが多く、空け方は元のものなので、鉤括弧の中と同じに数えない。
|
|
100
|
+
* リンクの外側の端(「を [記事]」の空白)は書き手の空け方なので数える。at は文書全体の位置。
|
|
101
|
+
*/
|
|
102
|
+
const isInsideLink = (links: readonly Span[], at: number): boolean => links.some((link) => link.start < at && at < link.end);
|
|
103
|
+
|
|
104
|
+
const findingAt = (entry: Located, values: Finding["values"], variant?: string): Finding => ({
|
|
105
|
+
rule: "",
|
|
106
|
+
severity: "warning",
|
|
107
|
+
line: 0,
|
|
108
|
+
column: 0,
|
|
109
|
+
quote: entry.sentence.text.trim(),
|
|
110
|
+
...(variant === undefined ? {} : { variant }),
|
|
111
|
+
values: { ...values, offset: entry.sentence.span.start + entry.offset },
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/** 一つの種類の境目の指摘。少ないほうを 1 箇所ずつか、書き方が二通りあれば 1 件で(spacing-minority.ts)。 */
|
|
115
|
+
const findingsOf = (kind: SpacingKind, ofKind: readonly Located[], limit: number): Finding[] => {
|
|
116
|
+
const report = minorityReport(ofKind, limit);
|
|
117
|
+
if (report === undefined) return [];
|
|
118
|
+
if (report.mode === "mixed") {
|
|
119
|
+
const { first, odd, spaced, touching } = report;
|
|
120
|
+
return [findingAt(first, { kind: KIND_NAME[kind], spaced, touching, count: odd, of: ofKind.length, limit }, "mixed")];
|
|
121
|
+
}
|
|
122
|
+
const minority = report.odd[0]?.spaced ?? false;
|
|
123
|
+
return report.odd.map((entry) =>
|
|
124
|
+
findingAt(entry, {
|
|
125
|
+
kind: KIND_NAME[kind],
|
|
126
|
+
style: minority ? "空けています" : "詰めています",
|
|
127
|
+
usual: minority ? "詰める" : "空ける",
|
|
128
|
+
count: report.odd.length,
|
|
129
|
+
of: ofKind.length,
|
|
130
|
+
limit,
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
71
135
|
/**
|
|
72
136
|
* 日本語と英字・数字のあいだを、空けるか詰めるか。文書の中で混ざっていたら、少ないほうを指摘する。
|
|
73
137
|
* どちらが正しいかは決めない。決めるのはチームで、chaff はそろっているかだけを見る。
|
|
@@ -80,35 +144,21 @@ export const latinSpacing: Detector = (doc, options): Finding[] => {
|
|
|
80
144
|
labelWords: labelsAt(doc, "before"),
|
|
81
145
|
calendar: calendarUnitsOf(doc),
|
|
82
146
|
divisions: labelsAt(doc, "after"),
|
|
147
|
+
itemNumbers: numberedItems(patternList(doc, "item-number"), doc.prose ?? doc.source),
|
|
83
148
|
};
|
|
84
149
|
const located: Located[] = doc.sentences.flatMap((sentence) => {
|
|
85
150
|
const quoted = quotedSpans(sentence.text);
|
|
86
151
|
const calendar = calendarStarts(sentence, context.calendar);
|
|
87
152
|
return latinBoundaries(sentence.text, doc.source.slice(sentence.span.start, sentence.span.end))
|
|
88
|
-
.filter((boundary) => !isQuoted(quoted, boundary) &&
|
|
153
|
+
.filter((boundary) => !isQuoted(quoted, boundary) && !isInsideLink(doc.links, sentence.span.start + boundary.offset))
|
|
154
|
+
.filter((boundary) => isCounted(sentence, boundary, context, calendar))
|
|
89
155
|
.map((boundary) => ({ sentence, ...boundary }));
|
|
90
156
|
});
|
|
91
|
-
return KINDS.flatMap((kind) =>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
rule: "",
|
|
99
|
-
severity: "warning",
|
|
100
|
-
line: 0,
|
|
101
|
-
column: 0,
|
|
102
|
-
quote: entry.sentence.text.trim(),
|
|
103
|
-
values: {
|
|
104
|
-
kind: KIND_NAME[kind],
|
|
105
|
-
style: minority ? "空けています" : "詰めています",
|
|
106
|
-
usual: minority ? "詰める" : "空ける",
|
|
107
|
-
count: odd.length,
|
|
108
|
-
of: ofKind.length,
|
|
109
|
-
limit: options.limit,
|
|
110
|
-
offset: entry.sentence.span.start + entry.offset,
|
|
111
|
-
},
|
|
112
|
-
}));
|
|
113
|
-
});
|
|
157
|
+
return KINDS.flatMap((kind) =>
|
|
158
|
+
findingsOf(
|
|
159
|
+
kind,
|
|
160
|
+
located.filter((entry) => entry.kind === kind),
|
|
161
|
+
options.limit,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
114
164
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
2
|
+
import { listStatementsIn, outsideMembers } from "../announced-list.ts";
|
|
3
|
+
import { linesOf, lineNumberAt } from "../structure/lines.ts";
|
|
4
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
5
|
+
|
|
6
|
+
/** 最初に挙げた一覧(対応 OS は Windows と macOS)に無い名前を、後の文が同じ語で言う所(Linux にも対応)。 */
|
|
7
|
+
export const outsideAnnouncedList: Detector = (doc): Finding[] => {
|
|
8
|
+
const lowered = (id: string): Set<string> => new Set((doc.lexicons[id] ?? []).map((entry) => entry.pattern.toLowerCase()));
|
|
9
|
+
const words = { frames: doc.lexicons["enumeration-frame"] ?? [], joiners: lowered("enumeration-joiner"), negations: lowered("enumeration-negation") };
|
|
10
|
+
const statements = doc.sentences.flatMap((sentence) => listStatementsIn(sentence, words, doc.source));
|
|
11
|
+
const lines = linesOf(doc.source);
|
|
12
|
+
return outsideMembers(statements).map(({ member, announced }) => ({
|
|
13
|
+
rule: "",
|
|
14
|
+
severity: "warning",
|
|
15
|
+
line: 0,
|
|
16
|
+
column: 0,
|
|
17
|
+
quote: quoteAt(doc.source, member.offset),
|
|
18
|
+
values: {
|
|
19
|
+
name: member.name,
|
|
20
|
+
list: announced.members.map((listed) => listed.name).join(", "),
|
|
21
|
+
listLine: lineNumberAt(lines, announced.offset) ?? 0,
|
|
22
|
+
offset: member.offset,
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
};
|
|
@@ -274,6 +274,7 @@ export const oxfordComma: Detector = (doc, options): Finding[] => {
|
|
|
274
274
|
participle: patternsOf(doc.lexicons["participle-word"]),
|
|
275
275
|
example: doc.lexicons["example-marker"] ?? [],
|
|
276
276
|
pair: patternsOf(doc.lexicons["pair-opener"]),
|
|
277
|
+
region: doc.lexicons["place-region"] ?? [],
|
|
277
278
|
};
|
|
278
279
|
const judged = doc.sentences.flatMap((sentence) => {
|
|
279
280
|
const oxford = oxfordIn(sentence.tokens ?? [], words, doc.source);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Detector, DetectorOptions, Finding, Lexicon, ProseDocument, Sentence } from "../plugin.ts";
|
|
2
|
-
import { entryIn } from "./lexicon-match.ts";
|
|
2
|
+
import { entryEnds, entryIn } from "./lexicon-match.ts";
|
|
3
|
+
import { closingSentences } from "../closing-paragraph.ts";
|
|
3
4
|
|
|
4
5
|
/** 冒頭は先頭 2 段落ぶん。「どの記事にも当てはまる書き出し」は冒頭にあるときだけ問題。 */
|
|
5
6
|
const OPENING_SENTENCES = 4;
|
|
@@ -10,7 +11,7 @@ const OPENING_SENTENCES = 4;
|
|
|
10
11
|
*/
|
|
11
12
|
const inScope = (doc: ProseDocument, where: string | undefined): readonly Sentence[] => {
|
|
12
13
|
if (where === "opening") return doc.sentences.slice(0, OPENING_SENTENCES);
|
|
13
|
-
if (where === "closing") return doc.sections.
|
|
14
|
+
if (where === "closing") return closingSentences(doc.sections, doc.paragraphs);
|
|
14
15
|
return doc.sentences;
|
|
15
16
|
};
|
|
16
17
|
|
|
@@ -22,14 +23,14 @@ const hitsIn = (sentences: readonly Sentence[], lexicon: Lexicon): Hit[] =>
|
|
|
22
23
|
return matched === undefined ? [] : [{ sentence, matched: matched.pattern }];
|
|
23
24
|
});
|
|
24
25
|
|
|
25
|
-
const findingsOf = (hits: readonly Hit[], limit: number): Finding[] =>
|
|
26
|
+
const findingsOf = (hits: readonly Hit[], limit: number, count = hits.length): Finding[] =>
|
|
26
27
|
hits.map((hit) => ({
|
|
27
28
|
rule: "",
|
|
28
29
|
severity: "warning",
|
|
29
30
|
line: 0,
|
|
30
31
|
column: 0,
|
|
31
32
|
quote: hit.sentence.text.trim(),
|
|
32
|
-
values: { matched: hit.matched, count
|
|
33
|
+
values: { matched: hit.matched, count, limit, offset: hit.sentence.span.start },
|
|
33
34
|
}));
|
|
34
35
|
|
|
35
36
|
const phraseHits = (doc: ProseDocument, options: DetectorOptions): Hit[] => {
|
|
@@ -46,8 +47,27 @@ export const phraseMatch: Detector = (doc, options): Finding[] => {
|
|
|
46
47
|
return hits.length < options.limit ? [] : findingsOf(hits, options.limit);
|
|
47
48
|
};
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
type Uses = { readonly sentence: Sentence; readonly matched: string; readonly count: number };
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 文の中の出現の数。語彙の語が重なっても(「させていただく」と「せていただく」)、終わる位置が同じなら一回。
|
|
54
|
+
* 指摘が言う語は文の最初の出現のもの。同じ位置なら語彙表で先に書いた語(させていただく)。
|
|
55
|
+
*/
|
|
56
|
+
const usesIn = (sentence: Sentence, lexicon: Lexicon): Uses | undefined => {
|
|
57
|
+
const found = lexicon.map((entry) => ({ entry, ends: entryEnds(sentence, entry) })).filter(({ ends }) => ends.length > 0);
|
|
58
|
+
const first = found.toSorted((a, b) => Math.min(...a.ends) - Math.min(...b.ends))[0];
|
|
59
|
+
if (first === undefined) return undefined;
|
|
60
|
+
return { sentence, matched: first.entry.pattern, count: new Set(found.flatMap(({ ends }) => ends)).size };
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 回数に上限がある語。数えるのは文ではなく出現で、一文に二度あれば二回。limit は許す回数で、それを超えたときだけ言う。
|
|
65
|
+
* message の「N 回まで」と同じ向き。指摘は出現のある文ごとに一つ。
|
|
66
|
+
*/
|
|
50
67
|
export const phraseCount: Detector = (doc, options): Finding[] => {
|
|
51
|
-
const
|
|
52
|
-
|
|
68
|
+
const lexicon = options.lexicon ?? [];
|
|
69
|
+
const uses = inScope(doc, options.where).flatMap((sentence) => usesIn(sentence, lexicon) ?? []);
|
|
70
|
+
const total = uses.reduce((sum, use) => sum + use.count, 0);
|
|
71
|
+
if (total <= options.limit) return [];
|
|
72
|
+
return findingsOf(uses, options.limit, total);
|
|
53
73
|
};
|