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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Detector, Finding, Sentence, Span, Token } from "../plugin.ts";
|
|
2
|
+
import { QUOTATION_MARKS, isWithinAny, quotedSpans } from "../quoted-span.ts";
|
|
3
|
+
|
|
4
|
+
/** 言語アダプタが、ら抜き言葉の一部の語に付ける印(lang-ja の PotentialRa=Dropped)。 */
|
|
5
|
+
const isRaDropped = (token: Token): boolean => token.features?.["PotentialRa"] === "Dropped";
|
|
6
|
+
|
|
7
|
+
/** 印の付いた語が続く並び(「食べ」「れる」)を一つにまとめた、文書の中の範囲。 */
|
|
8
|
+
const markedRuns = (tokens: readonly Token[]): Span[] =>
|
|
9
|
+
tokens.reduce<Span[]>((runs, token, index) => {
|
|
10
|
+
if (!isRaDropped(token)) return runs;
|
|
11
|
+
const last = runs.at(-1);
|
|
12
|
+
const previous = tokens[index - 1];
|
|
13
|
+
if (last !== undefined && previous !== undefined && isRaDropped(previous)) return [...runs.slice(0, -1), { start: last.start, end: token.span.end }];
|
|
14
|
+
return [...runs, token.span];
|
|
15
|
+
}, []);
|
|
16
|
+
|
|
17
|
+
export type RaDroppedWord = { readonly written: string; readonly offset: number };
|
|
18
|
+
|
|
19
|
+
/** 文の中のら抜き言葉。鉤括弧や引用符で引いた言葉(話した言葉をそのまま引いたもの)は数えない。 */
|
|
20
|
+
export const raDroppedIn = (sentence: Sentence): RaDroppedWord[] => {
|
|
21
|
+
const quoted = quotedSpans(sentence.text, QUOTATION_MARKS);
|
|
22
|
+
return markedRuns(sentence.tokens ?? [])
|
|
23
|
+
.map((run) => ({ start: run.start - sentence.span.start, end: run.end - sentence.span.start }))
|
|
24
|
+
.filter((run) => !isWithinAny(quoted, run))
|
|
25
|
+
.map((run) => ({ written: sentence.text.slice(run.start, run.end), offset: sentence.span.start + run.start }));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const raNuki: Detector = (doc): Finding[] =>
|
|
29
|
+
doc.sentences.flatMap((sentence) =>
|
|
30
|
+
raDroppedIn(sentence).map((word) => ({
|
|
31
|
+
rule: "",
|
|
32
|
+
severity: "warning",
|
|
33
|
+
line: 0,
|
|
34
|
+
column: 0,
|
|
35
|
+
quote: sentence.text.trim(),
|
|
36
|
+
values: { matched: word.written, offset: word.offset },
|
|
37
|
+
})),
|
|
38
|
+
);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Detector, Finding, Lexicon, LexiconEntry, OptionValue, Sentence } from "../plugin.ts";
|
|
2
|
+
import { entryCloses, entryIn, entryRanges, type TokenRange } from "./lexicon-match.ts";
|
|
3
|
+
import { QUOTATION_MARKS, isWithinAny, quotedIn } from "../quoted-span.ts";
|
|
4
|
+
|
|
5
|
+
// The verbal forms a house rule does not use for a provision: JIS Z 8301:2019's すべきである and a closing できる, or the
|
|
6
|
+
// Federal Plain Language Guidelines' "shall". Off until a team picks one; each choice reads one lexicon, which holds
|
|
7
|
+
// the forms and what to write instead (instead_of). A language without that lexicon has nothing to check.
|
|
8
|
+
|
|
9
|
+
/** The lexicons the rule's options turn on: requirement-modal-<standard>, and requirement-modal-must for shall: must. */
|
|
10
|
+
export const modalLexiconNames = (settings: Readonly<Record<string, OptionValue>>): string[] => [
|
|
11
|
+
...(typeof settings["standard"] === "string" && settings["standard"] !== "none" ? [`requirement-modal-${settings["standard"]}`] : []),
|
|
12
|
+
...(settings["shall"] === "must" ? ["requirement-modal-must"] : []),
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
type Use = { readonly entry: LexiconEntry; readonly offset: number };
|
|
16
|
+
|
|
17
|
+
const startOf = (sentence: Sentence, range: TokenRange | undefined): number =>
|
|
18
|
+
range === undefined ? sentence.span.start : (sentence.tokens?.[range.start]?.span.start ?? sentence.span.start);
|
|
19
|
+
|
|
20
|
+
const spanOf = (sentence: Sentence, range: TokenRange): { start: number; end: number } => ({
|
|
21
|
+
start: startOf(sentence, range),
|
|
22
|
+
end: sentence.tokens?.[range.end - 1]?.span.end ?? sentence.span.end,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/** Where the words of the form are in the sentence: only the closing one for position: after, else every one. */
|
|
26
|
+
const candidateRanges = (sentence: Sentence, entry: LexiconEntry): TokenRange[] => {
|
|
27
|
+
const ranges = entryRanges(sentence, entry);
|
|
28
|
+
if (entry.position !== "after") return ranges;
|
|
29
|
+
const closing = ranges.at(-1);
|
|
30
|
+
return entryCloses(sentence, entry) && closing !== undefined ? [closing] : [];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Whether the sentence has the form at all, read on its text: for a sentence the adapter gave no tokens. */
|
|
34
|
+
const presentInText = (sentence: Sentence, entry: LexiconEntry): boolean =>
|
|
35
|
+
entry.position === "after" ? entryCloses(sentence, entry) : entryIn(sentence, entry);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Where the sentence uses the form, or undefined. A form with position: after must close the sentence. Either must stand
|
|
39
|
+
* outside quotation marks: 'The key words "MUST" and "SHALL" …' and 禁止語は「べきである」。 mention a form, not use it.
|
|
40
|
+
*/
|
|
41
|
+
const useOf = (sentence: Sentence, entry: LexiconEntry): Use | undefined => {
|
|
42
|
+
if (sentence.tokens === undefined) return presentInText(sentence, entry) ? { entry, offset: sentence.span.start } : undefined;
|
|
43
|
+
const quoted = quotedIn(sentence, QUOTATION_MARKS);
|
|
44
|
+
const used = candidateRanges(sentence, entry).find((range) => !isWithinAny(quoted, spanOf(sentence, range)));
|
|
45
|
+
return used === undefined ? undefined : { entry, offset: startOf(sentence, used) };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const findingOf = (sentence: Sentence, use: Use): Finding => ({
|
|
49
|
+
rule: "",
|
|
50
|
+
severity: "warning",
|
|
51
|
+
line: 0,
|
|
52
|
+
column: 0,
|
|
53
|
+
quote: sentence.text.trim(),
|
|
54
|
+
values: { matched: use.entry.pattern, preferred: use.entry.instead_of ?? "", offset: use.offset },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/** Each form of the lexicons the sentence uses. */
|
|
58
|
+
const formsIn = (sentence: Sentence, lexicon: Lexicon): Finding[] =>
|
|
59
|
+
lexicon.flatMap((entry) => {
|
|
60
|
+
const use = useOf(sentence, entry);
|
|
61
|
+
return use === undefined ? [] : [findingOf(sentence, use)];
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const requirementModal: Detector = (doc, options): Finding[] => {
|
|
65
|
+
const lexicon = modalLexiconNames(options.settings ?? {}).flatMap((name) => doc.lexicons[name] ?? []);
|
|
66
|
+
return lexicon.length === 0 ? [] : doc.sentences.flatMap((sentence) => formsIn(sentence, lexicon));
|
|
67
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Detector, Finding, Lexicon, LexiconEntry, ProseDocument, Sentence } from "../plugin.ts";
|
|
2
|
+
import { entryCloses, entryIn, entryRanges } from "./lexicon-match.ts";
|
|
3
|
+
|
|
4
|
+
// Requirements smells (Femmer et al. 2017; Berry et al. 2003; ISO/IEC/IEEE 29148): a loophole, an open-ended list and
|
|
5
|
+
// "and/or", in a sentence that states a requirement. What makes a sentence a requirement, and each smell's words, come
|
|
6
|
+
// from the language's lexicons; this file knows neither language.
|
|
7
|
+
|
|
8
|
+
/** Each smell: the lexicon of its words, and the finding's variant (the rule's messages). */
|
|
9
|
+
const SMELLS = [
|
|
10
|
+
{ lexicon: "requirement-loophole", variant: "loophole" },
|
|
11
|
+
{ lexicon: "requirement-open-end", variant: "open-end" },
|
|
12
|
+
{ lexicon: "requirement-either", variant: "either" },
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
const MARKERS = "requirement-marker";
|
|
16
|
+
/** Sentence ends that look like a marker and are not one (「…のこと。」 defines a term). The language may have none. */
|
|
17
|
+
const NOT_MARKERS = "requirement-not-marker";
|
|
18
|
+
|
|
19
|
+
/** A marker with position: after counts only at the end of the sentence (「…できること。」); any other, anywhere in it. */
|
|
20
|
+
const isMarkedBy = (sentence: Sentence, entry: LexiconEntry): boolean => (entry.position === "after" ? entryCloses(sentence, entry) : entryIn(sentence, entry));
|
|
21
|
+
|
|
22
|
+
export const isRequirement = (sentence: Sentence, markers: Lexicon, notMarkers: Lexicon): boolean =>
|
|
23
|
+
markers.some((entry) => isMarkedBy(sentence, entry)) && !notMarkers.some((entry) => isMarkedBy(sentence, entry));
|
|
24
|
+
|
|
25
|
+
/** Where in the document the word starts: its first token, or the sentence when there are no tokens. */
|
|
26
|
+
const offsetOf = (sentence: Sentence, entry: LexiconEntry): number => {
|
|
27
|
+
const range = entryRanges(sentence, entry)[0];
|
|
28
|
+
return range === undefined ? sentence.span.start : (sentence.tokens?.[range.start]?.span.start ?? sentence.span.start);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const findingOf = (sentence: Sentence, entry: LexiconEntry, variant: string): Finding => ({
|
|
32
|
+
rule: "",
|
|
33
|
+
severity: "warning",
|
|
34
|
+
line: 0,
|
|
35
|
+
column: 0,
|
|
36
|
+
quote: sentence.text.trim(),
|
|
37
|
+
variant,
|
|
38
|
+
values: { matched: entry.pattern, offset: offsetOf(sentence, entry) },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/** The first word of each smell in one requirement sentence: one finding per smell, not per word. */
|
|
42
|
+
const smellsIn = (sentence: Sentence, lexicons: ProseDocument["lexicons"]): Finding[] =>
|
|
43
|
+
SMELLS.flatMap(({ lexicon, variant }) => {
|
|
44
|
+
const entry = (lexicons[lexicon] ?? []).find((candidate) => entryIn(sentence, candidate));
|
|
45
|
+
return entry === undefined ? [] : [findingOf(sentence, entry, variant)];
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const requirementSmell: Detector = (doc): Finding[] => {
|
|
49
|
+
const markers = doc.lexicons[MARKERS] ?? [];
|
|
50
|
+
const notMarkers = doc.lexicons[NOT_MARKERS] ?? [];
|
|
51
|
+
return doc.sentences.filter((sentence) => isRequirement(sentence, markers, notMarkers)).flatMap((sentence) => smellsIn(sentence, doc.lexicons));
|
|
52
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
2
|
+
import { quoteAround } from "./quote-around.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 字で終わる語(閉じ括弧や閉じ引用符が一つ付いてもよい)のすぐ後ろの半角空白一つと、それに続く句読点("word ."、"(word) ,")。句読点の後ろは空白か行の終わりか閉じの記号で、
|
|
6
|
+
* ".NET" や ".5" のように次の語の頭の点は数えない。数の後ろ(式の "[ 1 , N ]")と、"Note : " "ISSN : " のように欄の印として空けるコロンは見ない。
|
|
7
|
+
*/
|
|
8
|
+
const SPACED_MARK = /(?<=\p{L}[)\]}"'”’]?) (?=[.,;?!](?:[\s)\]"'”’]|$))/gu;
|
|
9
|
+
|
|
10
|
+
/** 空白で区切った点の並び(". . .")。省略の印と、目次の点線。 */
|
|
11
|
+
const SPACED_DOTS = /^\. ?\./u;
|
|
12
|
+
|
|
13
|
+
const DOTS_REACH = 3;
|
|
14
|
+
|
|
15
|
+
const isSpacedEllipsis = (text: string, space: number): boolean => SPACED_DOTS.test(text.slice(space + 1, space + 1 + DOTS_REACH));
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 本文(prose)の中の、句読点の前の空白の位置。prose はコード・URL・強調の印を空白で覆うので、覆ってできた空白("*word* ." の "*")は
|
|
19
|
+
* 書き手が打った空白ではない。source の同じ位置も空白のときだけ数える。
|
|
20
|
+
*/
|
|
21
|
+
export const spacesBeforePunctuation = (prose: string, source: string): number[] =>
|
|
22
|
+
[...prose.matchAll(SPACED_MARK)].map((match) => match.index).filter((space) => source.charAt(space) === " " && !isSpacedEllipsis(prose, space));
|
|
23
|
+
|
|
24
|
+
export const spaceBeforePunctuation: Detector = (doc): Finding[] =>
|
|
25
|
+
spacesBeforePunctuation(doc.prose ?? doc.source, doc.source).map((space) => ({
|
|
26
|
+
rule: "",
|
|
27
|
+
severity: "warning",
|
|
28
|
+
line: 0,
|
|
29
|
+
column: 0,
|
|
30
|
+
quote: quoteAround(doc.source, space, space + 2),
|
|
31
|
+
values: { mark: doc.source.charAt(space + 1), offset: space },
|
|
32
|
+
}));
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Detector, Finding, Lexicon, ProseDocument, Sentence, Span } from "../plugin.ts";
|
|
2
|
+
import { minorityWithin } from "../orthography.ts";
|
|
3
|
+
import { QUOTATION_MARKS, isWithinAny, quotedSpans } from "../quoted-span.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 綴りの組の語彙表の名前の頭。組(spelling-variant、spelling-ize)ごとに比べる。組を分けるのは、両方の書き方が一つの
|
|
7
|
+
* 書き方の決まりの中にあるから(Oxford の綴りは colour と organize を一緒に使う)。
|
|
8
|
+
*/
|
|
9
|
+
const SPELLING_LISTS = "spelling-";
|
|
10
|
+
|
|
11
|
+
type Spelling = { readonly family: string; readonly pattern: boolean; readonly other: string };
|
|
12
|
+
|
|
13
|
+
/** 語(小文字)から、その語がどの組のどちらの綴りか。 */
|
|
14
|
+
const spellingsOf = (lexicons: ProseDocument["lexicons"]): ReadonlyMap<string, Spelling> =>
|
|
15
|
+
new Map(
|
|
16
|
+
Object.entries(lexicons)
|
|
17
|
+
.filter(([id]) => id.startsWith(SPELLING_LISTS))
|
|
18
|
+
.flatMap(([family, entries]: [string, Lexicon]) =>
|
|
19
|
+
entries.flatMap((entry): [string, Spelling][] =>
|
|
20
|
+
entry.instead_of === undefined
|
|
21
|
+
? []
|
|
22
|
+
: [
|
|
23
|
+
[entry.pattern.toLowerCase(), { family, pattern: true, other: entry.instead_of }],
|
|
24
|
+
[entry.instead_of.toLowerCase(), { family, pattern: false, other: entry.pattern }],
|
|
25
|
+
],
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const WORD = /\p{L}+/gu;
|
|
31
|
+
|
|
32
|
+
/** 語の直前の開きの引用符。引いた語(use ‘organise’ not ‘organize’)は書き手の綴りではなく、話題にした語。 */
|
|
33
|
+
const OPENING_QUOTE = /[‘'"“]/u;
|
|
34
|
+
const CAPITAL = /^\p{Lu}/u;
|
|
35
|
+
|
|
36
|
+
/** 大文字で始まる次の語。文の頭でも、大文字の語が続けば名前(Labor Day、Centre Court)。 */
|
|
37
|
+
const CAPITALISED_NEXT = /^[ \t]+\p{Lu}/u;
|
|
38
|
+
|
|
39
|
+
export type SpelledWord = { readonly written: string; readonly offset: number; readonly spelling: Spelling };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 文の中の、組に載った綴りの語。文の頭でないのに大文字で始まる語と、大文字の語が続く語(Labor Day、World Health Organization)は名前で、名前の綴りは
|
|
43
|
+
* 変えられないので数えない。引用符で引いたものの中も、引いた元の綴りなので数えない。offset は文書の中の位置。
|
|
44
|
+
*/
|
|
45
|
+
export const spelledWordsIn = (sentence: Sentence, spellings: ReadonlyMap<string, Spelling>): SpelledWord[] => {
|
|
46
|
+
const quoted: readonly Span[] = quotedSpans(sentence.text, QUOTATION_MARKS);
|
|
47
|
+
const first = sentence.text.search(/\p{L}/u);
|
|
48
|
+
return [...sentence.text.matchAll(WORD)].flatMap((match) => {
|
|
49
|
+
const spelling = spellings.get(match[0].toLowerCase());
|
|
50
|
+
const named = CAPITAL.test(match[0]) && (match.index !== first || CAPITALISED_NEXT.test(sentence.text.slice(match.index + match[0].length)));
|
|
51
|
+
const inQuote =
|
|
52
|
+
isWithinAny(quoted, { start: match.index, end: match.index + match[0].length }) || OPENING_QUOTE.test(sentence.text.charAt(match.index - 1));
|
|
53
|
+
return spelling === undefined || named || inQuote ? [] : [{ written: match[0], offset: sentence.span.start + match.index, spelling }];
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type Located = { readonly sentence: Sentence; readonly word: SpelledWord };
|
|
58
|
+
|
|
59
|
+
const findingOf = ({ sentence, word }: Located, count: number, of: number): Finding => ({
|
|
60
|
+
rule: "",
|
|
61
|
+
severity: "info",
|
|
62
|
+
line: 0,
|
|
63
|
+
column: 0,
|
|
64
|
+
quote: sentence.text.trim(),
|
|
65
|
+
values: { matched: word.written, other: word.spelling.other, count, of, offset: word.offset },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* イギリスとアメリカの綴り(colour と color、centre と center)が一つの文書で混ざっているか。組ごとに、文書の中で少ないほうを
|
|
70
|
+
* 指摘する。どちらが正しいかは決めない。少ないほうが組の limit パーセントを超えるなら、使い分けと見て言わない。
|
|
71
|
+
*/
|
|
72
|
+
export const spellingVariety: Detector = (doc, options): Finding[] => {
|
|
73
|
+
const spellings = spellingsOf(doc.lexicons);
|
|
74
|
+
const located: Located[] = doc.sentences.flatMap((sentence) => spelledWordsIn(sentence, spellings).map((word) => ({ sentence, word })));
|
|
75
|
+
const families = [...new Set(located.map(({ word }) => word.spelling.family))];
|
|
76
|
+
return families.flatMap((family) => {
|
|
77
|
+
const ofFamily = located.filter(({ word }) => word.spelling.family === family);
|
|
78
|
+
const odd = minorityWithin(ofFamily, ({ word }) => word.spelling.pattern, options.limit);
|
|
79
|
+
return odd.map((entry) => findingOf(entry, odd.length, ofFamily.length));
|
|
80
|
+
});
|
|
81
|
+
};
|
|
@@ -4,7 +4,7 @@ import { numberingBreaks } from "../structure/numbering.ts";
|
|
|
4
4
|
import { weekdayMismatches } from "../structure/weekday.ts";
|
|
5
5
|
import { dateOrderBreaks } from "../structure/date-order.ts";
|
|
6
6
|
import { totalMismatches, type Amount } from "../structure/total.ts";
|
|
7
|
-
import { reversedRanges, type DatedSpan, type RangeWords } from "../structure/date-range.ts";
|
|
7
|
+
import { rangeFrameOf, reversedRanges, type DatedSpan, type RangeWords } from "../structure/date-range.ts";
|
|
8
8
|
import { percentSumMismatches, type ShareWords } from "../structure/percent-sum.ts";
|
|
9
9
|
|
|
10
10
|
const QUOTE_LENGTH = 80;
|
|
@@ -106,6 +106,8 @@ const rangeWordsOf = (doc: ProseDocument): RangeWords => ({
|
|
|
106
106
|
connectors: (doc.lexicons["range-connector"] ?? []).map((entry) => entry.pattern),
|
|
107
107
|
openers: (doc.lexicons["range-opener"] ?? []).map((entry) => entry.pattern),
|
|
108
108
|
closers: (doc.lexicons["range-closer"] ?? []).map((entry) => entry.pattern),
|
|
109
|
+
frames: (doc.lexicons["range-frame"] ?? []).flatMap((entry) => rangeFrameOf(entry.pattern) ?? []),
|
|
110
|
+
changes: (doc.lexicons["date-change-word"] ?? []).map((entry) => entry.pattern),
|
|
109
111
|
});
|
|
110
112
|
|
|
111
113
|
/** 期間の終わりが始まりより前。範囲の記号と語は言語パッケージの語彙表(range-connector、range-opener、range-closer)から取る。 */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { charLength, lengthOf } from "../measure.ts";
|
|
2
|
-
import type { BulletList, Detector, Finding, Paragraph, ProseDocument, Section, Span } from "../plugin.ts";
|
|
2
|
+
import type { BulletList, Detector, DetectorOptions, Finding, Paragraph, ProseDocument, Section, Span } from "../plugin.ts";
|
|
3
3
|
import { dateStampIndexes, stampCandidates } from "../date-stamp.ts";
|
|
4
4
|
import { inDocumentOrder } from "../structure/issues.ts";
|
|
5
5
|
import { preambleParagraphs } from "../preamble-paragraphs.ts";
|
|
@@ -25,6 +25,18 @@ const PERCENT = 100;
|
|
|
25
25
|
|
|
26
26
|
const asPercent = (value: number): number => Math.round(value * PERCENT);
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* 揃いすぎを測るのに要る、値の数の下限(rule の options)。値が少ないと変動係数は偶然で小さく出る。
|
|
30
|
+
* 人の書いた記事では、指摘が節や段落の少ない文書に偏っていた。
|
|
31
|
+
*/
|
|
32
|
+
const minimumCount = (options: DetectorOptions, name: string, fallback: number): number => {
|
|
33
|
+
const value = options.settings?.[name];
|
|
34
|
+
return typeof value === "number" ? value : fallback;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const DEFAULT_MIN_SECTIONS = 5;
|
|
38
|
+
const DEFAULT_MIN_PARAGRAPHS = 6;
|
|
39
|
+
|
|
28
40
|
const uniformity = (doc: ProseDocument, values: readonly number[], span: { start: number }, limit: number, rule: string): Finding[] => {
|
|
29
41
|
const cv = coefficientOfVariation(values);
|
|
30
42
|
if (cv === undefined || asPercent(cv) >= limit) return [];
|
|
@@ -65,7 +77,8 @@ const charsOf = (paragraph: Paragraph): number => paragraph.sentences.reduce((su
|
|
|
65
77
|
export const paragraphVariance: Detector = (doc, options): Finding[] => {
|
|
66
78
|
const lengths = doc.paragraphs.map(charsOf).filter((length) => length > 0);
|
|
67
79
|
const first = doc.paragraphs[0];
|
|
68
|
-
|
|
80
|
+
if (first === undefined || lengths.length < minimumCount(options, "min_paragraphs", DEFAULT_MIN_PARAGRAPHS)) return [];
|
|
81
|
+
return uniformity(doc, lengths, first.span, options.limit, "paragraph-length-variance");
|
|
69
82
|
};
|
|
70
83
|
|
|
71
84
|
const sectionChars = (section: Section): number => section.sentences.reduce((sum, sentence) => sum + charLength(sentence), 0);
|
|
@@ -74,7 +87,8 @@ const sectionChars = (section: Section): number => section.sentences.reduce((sum
|
|
|
74
87
|
export const sectionUniformity: Detector = (doc, options): Finding[] => {
|
|
75
88
|
const lengths = doc.sections.map(sectionChars).filter((length) => length > 0);
|
|
76
89
|
const first = doc.sections[0];
|
|
77
|
-
|
|
90
|
+
if (first === undefined || lengths.length < minimumCount(options, "min_sections", DEFAULT_MIN_SECTIONS)) return [];
|
|
91
|
+
return uniformity(doc, lengths, first.span, options.limit, "section-length-uniformity");
|
|
78
92
|
};
|
|
79
93
|
|
|
80
94
|
/**
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Lexicon, LexiconEntry, Sentence, Span, Token } from "../plugin.ts";
|
|
2
|
+
import { isWithinAny, quotedIn, quotedSpans, QUOTATION_MARKS } from "../quoted-span.ts";
|
|
3
|
+
import { entryEndsAt, entryIn, type TokenRange } from "./lexicon-match.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 比べる相手を言う語。語彙表の position で分ける。
|
|
7
|
+
* position の無い語(より・のほうが・than)は、文のどこにあっても比べる相手を言っている。
|
|
8
|
+
* position: before の語(との)は、最上級のすぐ前にあるときだけ。「SES との最大の分岐点」は相手を言うが、
|
|
9
|
+
* 「チームとの会議で最高の成果」の「との」は最上級と関わらない。
|
|
10
|
+
*/
|
|
11
|
+
export type ComparisonMarkers = { readonly anywhere: Lexicon; readonly before: Lexicon };
|
|
12
|
+
|
|
13
|
+
export const comparisonMarkersOf = (lexicon: Lexicon): ComparisonMarkers => ({
|
|
14
|
+
anywhere: lexicon.filter((entry) => entry.position === undefined),
|
|
15
|
+
before: lexicon.filter((entry) => entry.position === "before"),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/** 最上級のすぐ前で、比べる相手を受ける語が終わっているか。 */
|
|
19
|
+
export const counterpartBefore = (tokens: readonly Token[], range: TokenRange, markers: Lexicon): boolean =>
|
|
20
|
+
markers.some((entry) => entryEndsAt(tokens, entry, range.start));
|
|
21
|
+
|
|
22
|
+
const spanOf = (tokens: readonly Token[], range: TokenRange): Span | undefined => {
|
|
23
|
+
const first = tokens[range.start];
|
|
24
|
+
const last = tokens[range.end - 1];
|
|
25
|
+
return first === undefined || last === undefined ? undefined : { start: first.span.start, end: last.span.end };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** 引用符や鉤括弧の中の最上級。人の言葉や題名を引いたもので、書き手が比べずに言い切ったものではない。 */
|
|
29
|
+
export const quotedRange = (sentence: Sentence, range: TokenRange): boolean => {
|
|
30
|
+
const span = spanOf(sentence.tokens ?? [], range);
|
|
31
|
+
return span !== undefined && isWithinAny(quotedIn(sentence, QUOTATION_MARKS), span);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** 引いた言葉の中身を空白にした文。位置は変えない。 */
|
|
35
|
+
const unquotedText = (text: string): string => {
|
|
36
|
+
const quoted = quotedSpans(text, QUOTATION_MARKS);
|
|
37
|
+
return text
|
|
38
|
+
.split("")
|
|
39
|
+
.map((char, at) => (quoted.some((span) => at >= span.start && at < span.end) ? " " : char))
|
|
40
|
+
.join("");
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** 語が、引いた言葉の中にしか無いか。字で照らすので、品詞の無い文でも言える。 */
|
|
44
|
+
export const onlyQuoted = (sentence: Sentence, entry: LexiconEntry): boolean => {
|
|
45
|
+
const wrapped = sentence.wrapBreaks === undefined ? {} : { wrapBreaks: sentence.wrapBreaks };
|
|
46
|
+
return !entryIn({ span: sentence.span, text: unquotedText(sentence.text), ...wrapped }, entry);
|
|
47
|
+
};
|
|
@@ -10,6 +10,12 @@ const BARE_URL = /https?:\/\/[!-~]+/gu;
|
|
|
10
10
|
*/
|
|
11
11
|
const RUNS_ON = /[^\s\p{Cf}]/u;
|
|
12
12
|
|
|
13
|
+
/** index から始まる一字(サロゲートの対は一字)。末尾より後ろは空。 */
|
|
14
|
+
const characterAt = (text: string, index: number): string => {
|
|
15
|
+
const point = text.codePointAt(index);
|
|
16
|
+
return point === undefined ? "" : String.fromCodePoint(point);
|
|
17
|
+
};
|
|
18
|
+
|
|
13
19
|
export type RunOnUrl = { readonly url: Span; readonly next: string };
|
|
14
20
|
|
|
15
21
|
/** 字のまま見える範囲(texts)の中の、すぐ後ろに空白を置かずに日本語や全角の記号が続く URL。 */
|
|
@@ -18,7 +24,7 @@ export const runOnUrls = (source: string, texts: readonly Span[]): RunOnUrl[] =>
|
|
|
18
24
|
const written = source.slice(text.start, text.end);
|
|
19
25
|
return [...written.matchAll(BARE_URL)].flatMap((match) => {
|
|
20
26
|
const end = match.index + match[0].length;
|
|
21
|
-
const next =
|
|
27
|
+
const next = characterAt(written, end);
|
|
22
28
|
return RUNS_ON.test(next) ? [{ url: { start: text.start + match.index, end: text.start + end }, next }] : [];
|
|
23
29
|
});
|
|
24
30
|
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Detector, Finding, Lexicon, ProseDocument } from "../plugin.ts";
|
|
2
|
+
import { FIGURE_NUMBER, labelledKindsIn } from "../figure-references.ts";
|
|
3
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
4
|
+
import { labelWordsOf } from "./dangling-figure.ts";
|
|
5
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
6
|
+
import { numbersClauses } from "../structure/numbered-clauses.ts";
|
|
7
|
+
|
|
8
|
+
// A figure or a table pointed at by where it is (上記の図, the table below) in a document that numbers that kind and
|
|
9
|
+
// could name it (図3, Table 2), and a clause (以下の箇条, the clause below) in a document that numbers its clauses.
|
|
10
|
+
// JIS Z 8301:2019 10.6. The phrases and the kind each points at come from the lexicons.
|
|
11
|
+
|
|
12
|
+
export type VaguePointer = { readonly offset: number; readonly written: string; readonly kind: string };
|
|
13
|
+
|
|
14
|
+
/** A phrase inside a longer word (向上の図, 上の図表) is not one. */
|
|
15
|
+
const EDGE = "[\\p{Script=Han}\\p{Script=Katakana}A-Za-z0-90-9]";
|
|
16
|
+
|
|
17
|
+
/** Matched in any case (The figure below). */
|
|
18
|
+
const pointerPattern = (pattern: string): RegExp => new RegExp(`(?<!${EDGE})${escapeRegExp(pattern)}(?!${EDGE})`, "giu");
|
|
19
|
+
|
|
20
|
+
/** A pointer followed by a number names the figure (上の図 1, the figure below 2, the table above IV): the numbers figure labels take. */
|
|
21
|
+
const NUMBERED = new RegExp(`^${FIGURE_NUMBER}`, "u");
|
|
22
|
+
/** Enough characters after a pointer to hold a figure's number (第十二, 3.2.1). */
|
|
23
|
+
const NUMBER_LOOKAHEAD = 16;
|
|
24
|
+
|
|
25
|
+
/** Pure: every pointer in the prose that points at a kind the document labels. */
|
|
26
|
+
export const vaguePointers = (prose: string, pointers: Lexicon, labelledKinds: ReadonlySet<string>): VaguePointer[] =>
|
|
27
|
+
pointers
|
|
28
|
+
.flatMap((entry) => {
|
|
29
|
+
const kind = entry.instead_of;
|
|
30
|
+
if (kind === undefined || !labelledKinds.has(kind)) return [];
|
|
31
|
+
return [...prose.matchAll(pointerPattern(entry.pattern))]
|
|
32
|
+
.filter((match) => !NUMBERED.test(prose.slice(match.index + match[0].length, match.index + match[0].length + NUMBER_LOOKAHEAD)))
|
|
33
|
+
.map((match) => ({ offset: match.index, written: match[0], kind }));
|
|
34
|
+
})
|
|
35
|
+
.toSorted((left, right) => left.offset - right.offset);
|
|
36
|
+
|
|
37
|
+
const kindsOf = (pointers: Lexicon): Set<string> => new Set(pointers.flatMap((entry) => entry.instead_of ?? []));
|
|
38
|
+
|
|
39
|
+
/** The clause kinds to check. The tree is built only when a clause pointer is written, so other documents do not pay for it. */
|
|
40
|
+
const clauseKindsIn = (doc: ProseDocument, prose: string, pointers: Lexicon): string[] => {
|
|
41
|
+
const kinds = kindsOf(pointers);
|
|
42
|
+
if (vaguePointers(prose, pointers, kinds).length === 0) return [];
|
|
43
|
+
return doc.structure !== undefined && numbersClauses(doc.structure) ? [...kinds] : [];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const vagueFigurePointer: Detector = (doc): Finding[] => {
|
|
47
|
+
const prose = doc.prose ?? doc.source;
|
|
48
|
+
const clausePointers = doc.lexicons["vague-clause-pointer"] ?? [];
|
|
49
|
+
const kinds = new Set([...labelledKindsIn(doc.source, labelWordsOf(doc)), ...clauseKindsIn(doc, prose, clausePointers)]);
|
|
50
|
+
return vaguePointers(prose, [...(doc.lexicons["vague-figure-pointer"] ?? []), ...clausePointers], kinds).map((pointer) => ({
|
|
51
|
+
rule: "",
|
|
52
|
+
severity: "warning",
|
|
53
|
+
line: 0,
|
|
54
|
+
column: 0,
|
|
55
|
+
quote: quoteAt(doc.source, pointer.offset),
|
|
56
|
+
values: { matched: pointer.written, kind: pointer.kind, offset: pointer.offset },
|
|
57
|
+
}));
|
|
58
|
+
};
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
const separatorOf = (language: string): string => (language === "ja" ? "、" : ", ");
|
|
2
|
+
|
|
1
3
|
/** 語の並べ方は文書の言語に合わせる。日本語は「、」、ほかは ", "。英語の画面に「Risks、Costs」と出さない。 */
|
|
2
|
-
export const joinWords = (words: readonly string[], language: string): string => words.join(language
|
|
4
|
+
export const joinWords = (words: readonly string[], language: string): string => words.join(separatorOf(language));
|
|
5
|
+
|
|
6
|
+
/** joinWords で並べた語を、元の語に戻す。 */
|
|
7
|
+
export const splitWords = (joined: string, language: string): string[] => (joined === "" ? [] : joined.split(separatorOf(language)));
|