chaffjs 0.35.0 → 0.36.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.ja.md +12 -0
- package/README.md +15 -0
- package/dist/announced-count.d.ts +2 -0
- package/dist/announced-count.d.ts.map +1 -1
- package/dist/announced-count.js +29 -7
- package/dist/announced-count.js.map +1 -1
- package/dist/chronology-rows.d.ts +9 -0
- package/dist/chronology-rows.d.ts.map +1 -0
- package/dist/chronology-rows.js +79 -0
- package/dist/chronology-rows.js.map +1 -0
- package/dist/company-name-run.d.ts +8 -0
- package/dist/company-name-run.d.ts.map +1 -0
- package/dist/company-name-run.js +30 -0
- package/dist/company-name-run.js.map +1 -0
- package/dist/compound-head.d.ts +7 -0
- package/dist/compound-head.d.ts.map +1 -0
- package/dist/compound-head.js +19 -0
- package/dist/compound-head.js.map +1 -0
- package/dist/date-format.d.ts +8 -3
- package/dist/date-format.d.ts.map +1 -1
- package/dist/date-format.js +36 -3
- package/dist/date-format.js.map +1 -1
- package/dist/derived/count-per-period.d.ts +23 -0
- package/dist/derived/count-per-period.d.ts.map +1 -0
- package/dist/derived/count-per-period.js +14 -0
- package/dist/derived/count-per-period.js.map +1 -0
- package/dist/detectors/acronym-context.d.ts +4 -0
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +29 -1
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-expansion.d.ts +5 -1
- package/dist/detectors/acronym-expansion.d.ts.map +1 -1
- package/dist/detectors/acronym-expansion.js +35 -3
- package/dist/detectors/acronym-expansion.js.map +1 -1
- package/dist/detectors/acronym-known.d.ts +19 -0
- package/dist/detectors/acronym-known.d.ts.map +1 -0
- package/dist/detectors/acronym-known.js +32 -0
- package/dist/detectors/acronym-known.js.map +1 -0
- package/dist/detectors/acronym-link.d.ts +14 -0
- package/dist/detectors/acronym-link.d.ts.map +1 -0
- package/dist/detectors/acronym-link.js +32 -0
- package/dist/detectors/acronym-link.js.map +1 -0
- package/dist/detectors/acronym-name.d.ts +8 -1
- package/dist/detectors/acronym-name.d.ts.map +1 -1
- package/dist/detectors/acronym-name.js +23 -4
- package/dist/detectors/acronym-name.js.map +1 -1
- package/dist/detectors/addressee-edge.d.ts +13 -0
- package/dist/detectors/addressee-edge.d.ts.map +1 -0
- package/dist/detectors/addressee-edge.js +13 -0
- package/dist/detectors/addressee-edge.js.map +1 -0
- package/dist/detectors/announced-count.d.ts.map +1 -1
- package/dist/detectors/announced-count.js +1 -0
- package/dist/detectors/announced-count.js.map +1 -1
- package/dist/detectors/bare-comparative.d.ts +4 -0
- package/dist/detectors/bare-comparative.d.ts.map +1 -1
- package/dist/detectors/bare-comparative.js +28 -3
- package/dist/detectors/bare-comparative.js.map +1 -1
- package/dist/detectors/blank-structure.d.ts +7 -1
- package/dist/detectors/blank-structure.d.ts.map +1 -1
- package/dist/detectors/blank-structure.js +13 -8
- package/dist/detectors/blank-structure.js.map +1 -1
- package/dist/detectors/bracket-specified.d.ts +6 -0
- package/dist/detectors/bracket-specified.d.ts.map +1 -0
- package/dist/detectors/bracket-specified.js +23 -0
- package/dist/detectors/bracket-specified.js.map +1 -0
- package/dist/detectors/broken-link.d.ts +6 -0
- package/dist/detectors/broken-link.d.ts.map +1 -1
- package/dist/detectors/broken-link.js +23 -2
- package/dist/detectors/broken-link.js.map +1 -1
- package/dist/detectors/caps-caption.d.ts +7 -6
- package/dist/detectors/caps-caption.d.ts.map +1 -1
- package/dist/detectors/caps-caption.js +38 -0
- package/dist/detectors/caps-caption.js.map +1 -1
- package/dist/detectors/caps-phrase.d.ts +6 -0
- package/dist/detectors/caps-phrase.d.ts.map +1 -0
- package/dist/detectors/caps-phrase.js +16 -0
- package/dist/detectors/caps-phrase.js.map +1 -0
- package/dist/detectors/char-shape.d.ts +1 -0
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +29 -16
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/cited-title.d.ts +3 -2
- package/dist/detectors/cited-title.d.ts.map +1 -1
- package/dist/detectors/cited-title.js +14 -3
- package/dist/detectors/cited-title.js.map +1 -1
- package/dist/detectors/counter-edge.d.ts +2 -1
- package/dist/detectors/counter-edge.d.ts.map +1 -1
- package/dist/detectors/counter-edge.js +17 -2
- package/dist/detectors/counter-edge.js.map +1 -1
- package/dist/detectors/date-any-year.d.ts +7 -3
- package/dist/detectors/date-any-year.d.ts.map +1 -1
- package/dist/detectors/date-any-year.js +25 -5
- package/dist/detectors/date-any-year.js.map +1 -1
- package/dist/detectors/date-format.d.ts.map +1 -1
- package/dist/detectors/date-format.js +2 -1
- package/dist/detectors/date-format.js.map +1 -1
- package/dist/detectors/date-year.d.ts +9 -3
- package/dist/detectors/date-year.d.ts.map +1 -1
- package/dist/detectors/date-year.js +45 -9
- package/dist/detectors/date-year.js.map +1 -1
- package/dist/detectors/deadline-unit.d.ts +20 -0
- package/dist/detectors/deadline-unit.d.ts.map +1 -0
- package/dist/detectors/deadline-unit.js +19 -0
- package/dist/detectors/deadline-unit.js.map +1 -0
- package/dist/detectors/defined-term-form.d.ts.map +1 -1
- package/dist/detectors/defined-term-form.js +33 -7
- package/dist/detectors/defined-term-form.js.map +1 -1
- package/dist/detectors/definition-use.d.ts.map +1 -1
- package/dist/detectors/definition-use.js +6 -3
- package/dist/detectors/definition-use.js.map +1 -1
- package/dist/detectors/derived-numbers.d.ts.map +1 -1
- package/dist/detectors/derived-numbers.js +17 -4
- package/dist/detectors/derived-numbers.js.map +1 -1
- package/dist/detectors/doubled-across-aside.d.ts +9 -0
- package/dist/detectors/doubled-across-aside.d.ts.map +1 -0
- package/dist/detectors/doubled-across-aside.js +27 -0
- package/dist/detectors/doubled-across-aside.js.map +1 -0
- package/dist/detectors/doubled-punctuation.d.ts +3 -3
- package/dist/detectors/doubled-punctuation.d.ts.map +1 -1
- package/dist/detectors/doubled-punctuation.js +23 -4
- package/dist/detectors/doubled-punctuation.js.map +1 -1
- package/dist/detectors/doubled-word.d.ts.map +1 -1
- package/dist/detectors/doubled-word.js +2 -1
- package/dist/detectors/doubled-word.js.map +1 -1
- package/dist/detectors/ellipsis.d.ts.map +1 -1
- package/dist/detectors/ellipsis.js +13 -1
- package/dist/detectors/ellipsis.js.map +1 -1
- package/dist/detectors/email-letter.d.ts +31 -1
- package/dist/detectors/email-letter.d.ts.map +1 -1
- package/dist/detectors/email-letter.js +76 -14
- package/dist/detectors/email-letter.js.map +1 -1
- package/dist/detectors/field-label.d.ts +7 -0
- package/dist/detectors/field-label.d.ts.map +1 -0
- package/dist/detectors/field-label.js +23 -0
- package/dist/detectors/field-label.js.map +1 -0
- package/dist/detectors/footnote-mismatch.d.ts +6 -1
- package/dist/detectors/footnote-mismatch.d.ts.map +1 -1
- package/dist/detectors/footnote-mismatch.js +28 -7
- package/dist/detectors/footnote-mismatch.js.map +1 -1
- package/dist/detectors/graded-step.d.ts +20 -0
- package/dist/detectors/graded-step.d.ts.map +1 -0
- package/dist/detectors/graded-step.js +33 -0
- package/dist/detectors/graded-step.js.map +1 -0
- package/dist/detectors/gram-openers.d.ts +8 -0
- package/dist/detectors/gram-openers.d.ts.map +1 -0
- package/dist/detectors/gram-openers.js +16 -0
- package/dist/detectors/gram-openers.js.map +1 -0
- package/dist/detectors/gram-place.d.ts +3 -1
- package/dist/detectors/gram-place.d.ts.map +1 -1
- package/dist/detectors/gram-place.js +8 -0
- package/dist/detectors/gram-place.js.map +1 -1
- package/dist/detectors/gram-predicate.d.ts.map +1 -1
- package/dist/detectors/gram-predicate.js +37 -3
- package/dist/detectors/gram-predicate.js.map +1 -1
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +28 -2
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/ime-residue.d.ts +1 -1
- package/dist/detectors/ime-residue.d.ts.map +1 -1
- package/dist/detectors/ime-residue.js +4 -3
- package/dist/detectors/ime-residue.js.map +1 -1
- package/dist/detectors/kanji-compound-slip.d.ts +3 -0
- package/dist/detectors/kanji-compound-slip.d.ts.map +1 -0
- package/dist/detectors/kanji-compound-slip.js +50 -0
- package/dist/detectors/kanji-compound-slip.js.map +1 -0
- package/dist/detectors/kutoten-consistency.d.ts +10 -2
- package/dist/detectors/kutoten-consistency.d.ts.map +1 -1
- package/dist/detectors/kutoten-consistency.js +76 -12
- package/dist/detectors/kutoten-consistency.js.map +1 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +8 -2
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/link-shape.d.ts.map +1 -1
- package/dist/detectors/link-shape.js +9 -3
- package/dist/detectors/link-shape.js.map +1 -1
- package/dist/detectors/list-item-ending.d.ts +18 -0
- package/dist/detectors/list-item-ending.d.ts.map +1 -0
- package/dist/detectors/list-item-ending.js +35 -0
- package/dist/detectors/list-item-ending.js.map +1 -0
- package/dist/detectors/list-parallel.d.ts +18 -5
- package/dist/detectors/list-parallel.d.ts.map +1 -1
- package/dist/detectors/list-parallel.js +116 -36
- package/dist/detectors/list-parallel.js.map +1 -1
- package/dist/detectors/list-sentence.d.ts +4 -0
- package/dist/detectors/list-sentence.d.ts.map +1 -1
- package/dist/detectors/list-sentence.js +1 -1
- package/dist/detectors/list-sentence.js.map +1 -1
- package/dist/detectors/mark-shape.d.ts +11 -4
- package/dist/detectors/mark-shape.d.ts.map +1 -1
- package/dist/detectors/mark-shape.js +58 -10
- package/dist/detectors/mark-shape.js.map +1 -1
- package/dist/detectors/mentioned-phrase.d.ts +9 -0
- package/dist/detectors/mentioned-phrase.d.ts.map +1 -0
- package/dist/detectors/mentioned-phrase.js +25 -0
- package/dist/detectors/mentioned-phrase.js.map +1 -0
- package/dist/detectors/middle-dot.d.ts +2 -2
- package/dist/detectors/middle-dot.d.ts.map +1 -1
- package/dist/detectors/middle-dot.js +4 -2
- package/dist/detectors/middle-dot.js.map +1 -1
- package/dist/detectors/modal-conflict.d.ts.map +1 -1
- package/dist/detectors/modal-conflict.js +5 -2
- package/dist/detectors/modal-conflict.js.map +1 -1
- package/dist/detectors/notice-paragraph.d.ts +9 -0
- package/dist/detectors/notice-paragraph.d.ts.map +1 -0
- package/dist/detectors/notice-paragraph.js +21 -0
- package/dist/detectors/notice-paragraph.js.map +1 -0
- package/dist/detectors/number-style.d.ts.map +1 -1
- package/dist/detectors/number-style.js +15 -2
- package/dist/detectors/number-style.js.map +1 -1
- package/dist/detectors/number-unit.d.ts.map +1 -1
- package/dist/detectors/number-unit.js +24 -1
- package/dist/detectors/number-unit.js.map +1 -1
- package/dist/detectors/numeral-opener.d.ts +6 -0
- package/dist/detectors/numeral-opener.d.ts.map +1 -1
- package/dist/detectors/numeral-opener.js +24 -1
- package/dist/detectors/numeral-opener.js.map +1 -1
- package/dist/detectors/obligation-without-deadline.d.ts +5 -1
- package/dist/detectors/obligation-without-deadline.d.ts.map +1 -1
- package/dist/detectors/obligation-without-deadline.js +44 -23
- package/dist/detectors/obligation-without-deadline.js.map +1 -1
- package/dist/detectors/open-end-class.d.ts +16 -0
- package/dist/detectors/open-end-class.d.ts.map +1 -0
- package/dist/detectors/open-end-class.js +65 -0
- package/dist/detectors/open-end-class.js.map +1 -0
- package/dist/detectors/open-end-condition.d.ts +7 -0
- package/dist/detectors/open-end-condition.d.ts.map +1 -0
- package/dist/detectors/open-end-condition.js +35 -0
- package/dist/detectors/open-end-condition.js.map +1 -0
- package/dist/detectors/open-end-names.d.ts +9 -3
- package/dist/detectors/open-end-names.d.ts.map +1 -1
- package/dist/detectors/open-end-names.js +5 -2
- package/dist/detectors/open-end-names.js.map +1 -1
- package/dist/detectors/open-end-question.d.ts +15 -0
- package/dist/detectors/open-end-question.d.ts.map +1 -0
- package/dist/detectors/open-end-question.js +37 -0
- package/dist/detectors/open-end-question.js.map +1 -0
- package/dist/detectors/open-end-scope.d.ts +16 -0
- package/dist/detectors/open-end-scope.d.ts.map +1 -0
- package/dist/detectors/open-end-scope.js +47 -0
- package/dist/detectors/open-end-scope.js.map +1 -0
- package/dist/detectors/opening-date.d.ts +10 -0
- package/dist/detectors/opening-date.d.ts.map +1 -0
- package/dist/detectors/opening-date.js +33 -0
- package/dist/detectors/opening-date.js.map +1 -0
- package/dist/detectors/ordinary-phrase.d.ts +20 -0
- package/dist/detectors/ordinary-phrase.d.ts.map +1 -0
- package/dist/detectors/ordinary-phrase.js +54 -0
- package/dist/detectors/ordinary-phrase.js.map +1 -0
- package/dist/detectors/organisation-run.d.ts +5 -1
- package/dist/detectors/organisation-run.d.ts.map +1 -1
- package/dist/detectors/organisation-run.js +7 -0
- package/dist/detectors/organisation-run.js.map +1 -1
- package/dist/detectors/orthographic-variant.d.ts.map +1 -1
- package/dist/detectors/orthographic-variant.js +56 -20
- package/dist/detectors/orthographic-variant.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +6 -1
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/oxford-comma.d.ts.map +1 -1
- package/dist/detectors/oxford-comma.js +38 -1
- package/dist/detectors/oxford-comma.js.map +1 -1
- package/dist/detectors/person-consistency.d.ts +2 -1
- package/dist/detectors/person-consistency.d.ts.map +1 -1
- package/dist/detectors/person-consistency.js +5 -3
- package/dist/detectors/person-consistency.js.map +1 -1
- package/dist/detectors/phrase-match.d.ts +2 -0
- package/dist/detectors/phrase-match.d.ts.map +1 -1
- package/dist/detectors/phrase-match.js +11 -4
- package/dist/detectors/phrase-match.js.map +1 -1
- package/dist/detectors/placeholder-text.d.ts.map +1 -1
- package/dist/detectors/placeholder-text.js +18 -3
- package/dist/detectors/placeholder-text.js.map +1 -1
- package/dist/detectors/placeholder.d.ts +3 -1
- package/dist/detectors/placeholder.d.ts.map +1 -1
- package/dist/detectors/placeholder.js +8 -3
- package/dist/detectors/placeholder.js.map +1 -1
- package/dist/detectors/postcode-end.d.ts +3 -0
- package/dist/detectors/postcode-end.d.ts.map +1 -0
- package/dist/detectors/postcode-end.js +15 -0
- package/dist/detectors/postcode-end.js.map +1 -0
- package/dist/detectors/prose-total-words.d.ts +5 -0
- package/dist/detectors/prose-total-words.d.ts.map +1 -0
- package/dist/detectors/prose-total-words.js +14 -0
- package/dist/detectors/prose-total-words.js.map +1 -0
- package/dist/detectors/registry/kanji-compound-slip.d.ts +3 -0
- package/dist/detectors/registry/kanji-compound-slip.d.ts.map +1 -0
- package/dist/detectors/registry/kanji-compound-slip.js +3 -0
- package/dist/detectors/registry/kanji-compound-slip.js.map +1 -0
- package/dist/detectors/registry/phrase-in-use.d.ts +3 -0
- package/dist/detectors/registry/phrase-in-use.d.ts.map +1 -0
- package/dist/detectors/registry/phrase-in-use.js +3 -0
- package/dist/detectors/registry/phrase-in-use.js.map +1 -0
- package/dist/detectors/requirement-smell.d.ts.map +1 -1
- package/dist/detectors/requirement-smell.js +29 -5
- package/dist/detectors/requirement-smell.js.map +1 -1
- package/dist/detectors/scaled-figure-unit.d.ts +28 -0
- package/dist/detectors/scaled-figure-unit.d.ts.map +1 -0
- package/dist/detectors/scaled-figure-unit.js +78 -0
- package/dist/detectors/scaled-figure-unit.js.map +1 -0
- package/dist/detectors/sentence-counts.d.ts +2 -0
- package/dist/detectors/sentence-counts.d.ts.map +1 -1
- package/dist/detectors/sentence-counts.js +18 -7
- package/dist/detectors/sentence-counts.js.map +1 -1
- package/dist/detectors/sentence-ending.d.ts +2 -0
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +10 -3
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/sentence-load.d.ts +4 -1
- package/dist/detectors/sentence-load.d.ts.map +1 -1
- package/dist/detectors/sentence-load.js +9 -2
- package/dist/detectors/sentence-load.js.map +1 -1
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +30 -50
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +14 -13
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +2 -1
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/subject-name-line.d.ts +8 -0
- package/dist/detectors/subject-name-line.d.ts.map +1 -0
- package/dist/detectors/subject-name-line.js +53 -0
- package/dist/detectors/subject-name-line.js.map +1 -0
- package/dist/detectors/table-header.d.ts.map +1 -1
- package/dist/detectors/table-header.js +13 -1
- package/dist/detectors/table-header.js.map +1 -1
- package/dist/detectors/technical-docs.d.ts.map +1 -1
- package/dist/detectors/technical-docs.js +4 -1
- package/dist/detectors/technical-docs.js.map +1 -1
- package/dist/detectors/term-mention-sentence.d.ts +4 -0
- package/dist/detectors/term-mention-sentence.d.ts.map +1 -0
- package/dist/detectors/term-mention-sentence.js +28 -0
- package/dist/detectors/term-mention-sentence.js.map +1 -0
- package/dist/detectors/titled-run.d.ts +2 -1
- package/dist/detectors/titled-run.d.ts.map +1 -1
- package/dist/detectors/titled-run.js +9 -4
- package/dist/detectors/titled-run.js.map +1 -1
- package/dist/detectors/token-shape.d.ts.map +1 -1
- package/dist/detectors/token-shape.js +13 -5
- package/dist/detectors/token-shape.js.map +1 -1
- package/dist/detectors/vague-density.d.ts +5 -2
- package/dist/detectors/vague-density.d.ts.map +1 -1
- package/dist/detectors/vague-density.js +17 -4
- package/dist/detectors/vague-density.js.map +1 -1
- package/dist/document-paragraphs.d.ts +4 -0
- package/dist/document-paragraphs.d.ts.map +1 -0
- package/dist/document-paragraphs.js +24 -0
- package/dist/document-paragraphs.js.map +1 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +2 -19
- package/dist/document.js.map +1 -1
- package/dist/figure-references.d.ts +3 -0
- package/dist/figure-references.d.ts.map +1 -1
- package/dist/figure-references.js +6 -2
- package/dist/figure-references.js.map +1 -1
- package/dist/format-template.d.ts +3 -0
- package/dist/format-template.d.ts.map +1 -0
- package/dist/format-template.js +13 -0
- package/dist/format-template.js.map +1 -0
- package/dist/formula-brackets.d.ts +7 -0
- package/dist/formula-brackets.d.ts.map +1 -0
- package/dist/formula-brackets.js +29 -0
- package/dist/formula-brackets.js.map +1 -0
- package/dist/html/html-markdown.d.ts.map +1 -1
- package/dist/html/html-markdown.js +2 -1
- package/dist/html/html-markdown.js.map +1 -1
- package/dist/html/html-site-chrome.d.ts +5 -0
- package/dist/html/html-site-chrome.d.ts.map +1 -0
- package/dist/html/html-site-chrome.js +33 -0
- package/dist/html/html-site-chrome.js.map +1 -0
- package/dist/joined-view.d.ts.map +1 -1
- package/dist/joined-view.js +1 -0
- package/dist/joined-view.js.map +1 -1
- package/dist/kanji-compound-slip.d.ts +32 -0
- package/dist/kanji-compound-slip.d.ts.map +1 -0
- package/dist/kanji-compound-slip.js +63 -0
- package/dist/kanji-compound-slip.js.map +1 -0
- package/dist/latin-company-form.d.ts +6 -0
- package/dist/latin-company-form.d.ts.map +1 -0
- package/dist/latin-company-form.js +32 -0
- package/dist/latin-company-form.js.map +1 -0
- package/dist/latin-word-boundary.d.ts +15 -0
- package/dist/latin-word-boundary.d.ts.map +1 -0
- package/dist/latin-word-boundary.js +40 -0
- package/dist/latin-word-boundary.js.map +1 -0
- package/dist/lexicon-genres.d.ts +2 -0
- package/dist/lexicon-genres.d.ts.map +1 -1
- package/dist/lexicon-genres.js +1 -1
- package/dist/lexicon-genres.js.map +1 -1
- package/dist/link-shape.d.ts +5 -0
- package/dist/link-shape.d.ts.map +1 -1
- package/dist/link-shape.js +18 -0
- package/dist/link-shape.js.map +1 -1
- package/dist/link-title.d.ts +4 -0
- package/dist/link-title.d.ts.map +1 -0
- package/dist/link-title.js +33 -0
- package/dist/link-title.js.map +1 -0
- package/dist/list-item-paragraphs.d.ts +15 -0
- package/dist/list-item-paragraphs.d.ts.map +1 -0
- package/dist/list-item-paragraphs.js +19 -0
- package/dist/list-item-paragraphs.js.map +1 -0
- package/dist/literal-quote.d.ts +12 -0
- package/dist/literal-quote.d.ts.map +1 -0
- package/dist/literal-quote.js +43 -0
- package/dist/literal-quote.js.map +1 -0
- package/dist/nado-closed-list.d.ts.map +1 -1
- package/dist/nado-closed-list.js +39 -5
- package/dist/nado-closed-list.js.map +1 -1
- package/dist/name-separator.d.ts.map +1 -1
- package/dist/name-separator.js +25 -2
- package/dist/name-separator.js.map +1 -1
- package/dist/nominal-stem.d.ts +14 -1
- package/dist/nominal-stem.d.ts.map +1 -1
- package/dist/nominal-stem.js +42 -4
- package/dist/nominal-stem.js.map +1 -1
- package/dist/person-forms.d.ts +8 -0
- package/dist/person-forms.d.ts.map +1 -1
- package/dist/person-forms.js +12 -0
- package/dist/person-forms.js.map +1 -1
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/preamble-paragraphs.d.ts +3 -2
- package/dist/preamble-paragraphs.d.ts.map +1 -1
- package/dist/preamble-paragraphs.js +8 -2
- package/dist/preamble-paragraphs.js.map +1 -1
- package/dist/spacing-code.d.ts +1 -0
- package/dist/spacing-code.d.ts.map +1 -1
- package/dist/spacing-code.js +4 -1
- package/dist/spacing-code.js.map +1 -1
- package/dist/split-noun.d.ts +10 -0
- package/dist/split-noun.d.ts.map +1 -0
- package/dist/split-noun.js +50 -0
- package/dist/split-noun.js.map +1 -0
- package/dist/structure/attached-parts.d.ts +11 -0
- package/dist/structure/attached-parts.d.ts.map +1 -0
- package/dist/structure/attached-parts.js +31 -0
- package/dist/structure/attached-parts.js.map +1 -0
- package/dist/structure/build.d.ts.map +1 -1
- package/dist/structure/build.js +7 -4
- package/dist/structure/build.js.map +1 -1
- package/dist/structure/contents-lines.d.ts +7 -0
- package/dist/structure/contents-lines.d.ts.map +1 -0
- package/dist/structure/contents-lines.js +51 -0
- package/dist/structure/contents-lines.js.map +1 -0
- package/dist/structure/defining-names.d.ts +37 -0
- package/dist/structure/defining-names.d.ts.map +1 -0
- package/dist/structure/defining-names.js +122 -0
- package/dist/structure/defining-names.js.map +1 -0
- package/dist/structure/definition-use.d.ts +3 -2
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +99 -31
- package/dist/structure/definition-use.js.map +1 -1
- package/dist/structure/issues.d.ts +4 -1
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +5 -2
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/list-lead-in.d.ts +19 -0
- package/dist/structure/list-lead-in.d.ts.map +1 -0
- package/dist/structure/list-lead-in.js +85 -0
- package/dist/structure/list-lead-in.js.map +1 -0
- package/dist/structure/modal-conflict.d.ts +7 -2
- package/dist/structure/modal-conflict.d.ts.map +1 -1
- package/dist/structure/modal-conflict.js +36 -7
- package/dist/structure/modal-conflict.js.map +1 -1
- package/dist/structure/negated-act.d.ts +17 -0
- package/dist/structure/negated-act.d.ts.map +1 -0
- package/dist/structure/negated-act.js +32 -0
- package/dist/structure/negated-act.js.map +1 -0
- package/dist/structure/numbering.d.ts +3 -1
- package/dist/structure/numbering.d.ts.map +1 -1
- package/dist/structure/numbering.js +20 -8
- package/dist/structure/numbering.js.map +1 -1
- package/dist/structure/prose-total.d.ts +4 -0
- package/dist/structure/prose-total.d.ts.map +1 -1
- package/dist/structure/prose-total.js +16 -6
- package/dist/structure/prose-total.js.map +1 -1
- package/dist/structure/repeated-number.d.ts +24 -0
- package/dist/structure/repeated-number.d.ts.map +1 -0
- package/dist/structure/repeated-number.js +89 -0
- package/dist/structure/repeated-number.js.map +1 -0
- package/dist/structure/rounded-amount.d.ts +8 -0
- package/dist/structure/rounded-amount.d.ts.map +1 -0
- package/dist/structure/rounded-amount.js +48 -0
- package/dist/structure/rounded-amount.js.map +1 -0
- package/dist/structure/side-step.d.ts +8 -0
- package/dist/structure/side-step.d.ts.map +1 -0
- package/dist/structure/side-step.js +21 -0
- package/dist/structure/side-step.js.map +1 -0
- package/dist/structure/spanned-label-blank.d.ts +8 -0
- package/dist/structure/spanned-label-blank.d.ts.map +1 -0
- package/dist/structure/spanned-label-blank.js +37 -0
- package/dist/structure/spanned-label-blank.js.map +1 -0
- package/dist/structure/universal.d.ts +3 -1
- package/dist/structure/universal.d.ts.map +1 -1
- package/dist/structure/universal.js +9 -2
- package/dist/structure/universal.js.map +1 -1
- package/dist/structure/unspaced-heading.d.ts +10 -0
- package/dist/structure/unspaced-heading.d.ts.map +1 -0
- package/dist/structure/unspaced-heading.js +24 -0
- package/dist/structure/unspaced-heading.js.map +1 -0
- package/dist/structure/written-list-path.d.ts +10 -0
- package/dist/structure/written-list-path.d.ts.map +1 -0
- package/dist/structure/written-list-path.js +37 -0
- package/dist/structure/written-list-path.js.map +1 -0
- package/dist/structure/written-resolve.d.ts +1 -1
- package/dist/structure/written-resolve.d.ts.map +1 -1
- package/dist/structure/written-resolve.js +15 -9
- package/dist/structure/written-resolve.js.map +1 -1
- package/dist/title-line.d.ts +21 -0
- package/dist/title-line.d.ts.map +1 -0
- package/dist/title-line.js +27 -0
- package/dist/title-line.js.map +1 -0
- package/package.json +3 -3
- package/rules/all-caps-shouting.yaml +2 -2
- package/rules/announced-count-mismatch.yaml +2 -2
- package/rules/bare-url-mix.yaml +2 -2
- package/rules/bracket-nesting.yaml +2 -2
- package/rules/bracket-width-consistency.yaml +2 -2
- package/rules/broken-link.yaml +2 -2
- package/rules/cliche.yaml +4 -3
- package/rules/code-fence-language-mix.yaml +2 -2
- package/rules/comparative-without-baseline.yaml +2 -2
- package/rules/dangling-figure-reference.yaml +2 -2
- package/rules/date-without-year.yaml +10 -2
- package/rules/defined-term-form.yaml +2 -2
- package/rules/doubled-punctuation.yaml +4 -4
- package/rules/doubled-word.yaml +2 -2
- package/rules/duplicate-definition.yaml +2 -2
- package/rules/duration-mismatch.yaml +2 -2
- package/rules/email-greeting-closing.yaml +2 -2
- package/rules/email-subject-length.yaml +2 -2
- package/rules/empty-table-cell.yaml +2 -2
- package/rules/footnote-mismatch.yaml +2 -2
- package/rules/heading-echo.yaml +2 -2
- package/rules/ime-residue.yaml +2 -2
- package/rules/kanji-compound-slip.yaml +67 -0
- package/rules/kutoten-consistency.yaml +4 -4
- package/rules/latin-spacing.yaml +2 -2
- package/rules/list-item-form-mix.yaml +2 -2
- package/rules/max-kanji-continuous.yaml +6 -4
- package/rules/modal-conflict.yaml +1 -0
- package/rules/nado-closed-list.yaml +2 -2
- package/rules/ngram-repetition.yaml +2 -2
- package/rules/no-doubled-joshi.yaml +2 -2
- package/rules/no-mixed-desumasu.yaml +3 -3
- package/rules/no-nakaguro-parallel.yaml +2 -0
- package/rules/number-without-unit.yaml +9 -4
- package/rules/numbering-gap.yaml +7 -2
- package/rules/numeral-sentence-start.yaml +2 -2
- package/rules/obligation-without-deadline.yaml +2 -2
- package/rules/orthographic-variant.yaml +2 -2
- package/rules/oxford-comma-consistency.yaml +3 -3
- package/rules/preamble-length.yaml +2 -2
- package/rules/requirement-smell.yaml +3 -3
- package/rules/table-header-variant.yaml +2 -2
- package/rules/teki-overuse.yaml +3 -2
- package/rules/total-mismatch.yaml +2 -2
- package/rules/translationese-density.yaml +2 -2
- package/rules/undefined-acronym.yaml +4 -2
- package/rules/unfilled-placeholder.yaml +4 -4
- package/rules/use-before-definition.yaml +2 -2
- package/rules/vague-word-density.yaml +2 -2
- package/skills/chaff/SKILL.md +7 -1
- package/src/announced-count.ts +35 -8
- package/src/chronology-rows.ts +86 -0
- package/src/company-name-run.ts +37 -0
- package/src/compound-head.ts +25 -0
- package/src/date-format.ts +43 -4
- package/src/derived/count-per-period.ts +28 -0
- package/src/detectors/acronym-context.ts +30 -1
- package/src/detectors/acronym-expansion.ts +47 -6
- package/src/detectors/acronym-known.ts +40 -0
- package/src/detectors/acronym-link.ts +37 -0
- package/src/detectors/acronym-name.ts +27 -4
- package/src/detectors/addressee-edge.ts +16 -0
- package/src/detectors/announced-count.ts +1 -0
- package/src/detectors/bare-comparative.ts +44 -3
- package/src/detectors/blank-structure.ts +21 -10
- package/src/detectors/bracket-specified.ts +25 -0
- package/src/detectors/broken-link.ts +26 -2
- package/src/detectors/caps-caption.ts +42 -0
- package/src/detectors/caps-phrase.ts +17 -0
- package/src/detectors/char-shape.ts +30 -9
- package/src/detectors/cited-title.ts +15 -3
- package/src/detectors/counter-edge.ts +17 -2
- package/src/detectors/date-any-year.ts +27 -6
- package/src/detectors/date-format.ts +2 -1
- package/src/detectors/date-year.ts +64 -16
- package/src/detectors/deadline-unit.ts +40 -0
- package/src/detectors/defined-term-form.ts +32 -12
- package/src/detectors/definition-use.ts +7 -3
- package/src/detectors/derived-numbers.ts +19 -4
- package/src/detectors/doubled-across-aside.ts +36 -0
- package/src/detectors/doubled-punctuation.ts +28 -7
- package/src/detectors/doubled-word.ts +2 -1
- package/src/detectors/ellipsis.ts +16 -1
- package/src/detectors/email-letter.ts +97 -21
- package/src/detectors/field-label.ts +25 -0
- package/src/detectors/footnote-mismatch.ts +39 -7
- package/src/detectors/graded-step.ts +52 -0
- package/src/detectors/gram-openers.ts +21 -0
- package/src/detectors/gram-place.ts +10 -1
- package/src/detectors/gram-predicate.ts +43 -3
- package/src/detectors/heading-echo.ts +31 -3
- package/src/detectors/ime-residue.ts +4 -3
- package/src/detectors/kanji-compound-slip.ts +61 -0
- package/src/detectors/kutoten-consistency.ts +93 -14
- package/src/detectors/lexicon.ts +12 -3
- package/src/detectors/link-shape.ts +10 -3
- package/src/detectors/list-item-ending.ts +51 -0
- package/src/detectors/list-parallel.ts +158 -33
- package/src/detectors/list-sentence.ts +5 -1
- package/src/detectors/mark-shape.ts +64 -10
- package/src/detectors/mentioned-phrase.ts +38 -0
- package/src/detectors/middle-dot.ts +7 -2
- package/src/detectors/modal-conflict.ts +5 -2
- package/src/detectors/notice-paragraph.ts +33 -0
- package/src/detectors/number-style.ts +14 -2
- package/src/detectors/number-unit.ts +28 -1
- package/src/detectors/numeral-opener.ts +27 -1
- package/src/detectors/obligation-without-deadline.ts +29 -4
- package/src/detectors/open-end-class.ts +78 -0
- package/src/detectors/open-end-condition.ts +40 -0
- package/src/detectors/open-end-names.ts +9 -3
- package/src/detectors/open-end-question.ts +50 -0
- package/src/detectors/open-end-scope.ts +62 -0
- package/src/detectors/opening-date.ts +47 -0
- package/src/detectors/ordinary-phrase.ts +62 -0
- package/src/detectors/organisation-run.ts +13 -2
- package/src/detectors/orthographic-variant.ts +85 -25
- package/src/detectors/orthography.ts +10 -1
- package/src/detectors/oxford-comma.ts +40 -1
- package/src/detectors/person-consistency.ts +5 -3
- package/src/detectors/phrase-match.ts +16 -5
- package/src/detectors/placeholder-text.ts +18 -3
- package/src/detectors/placeholder.ts +10 -3
- package/src/detectors/postcode-end.ts +16 -0
- package/src/detectors/prose-total-words.ts +18 -0
- package/src/detectors/registry/kanji-compound-slip.ts +4 -0
- package/src/detectors/registry/phrase-in-use.ts +4 -0
- package/src/detectors/requirement-smell.ts +38 -5
- package/src/detectors/scaled-figure-unit.ts +103 -0
- package/src/detectors/sentence-counts.ts +24 -8
- package/src/detectors/sentence-ending.ts +12 -3
- package/src/detectors/sentence-load.ts +9 -2
- package/src/detectors/signals.ts +33 -51
- package/src/detectors/structure-tree.ts +14 -14
- package/src/detectors/structure.ts +2 -1
- package/src/detectors/subject-name-line.ts +66 -0
- package/src/detectors/table-header.ts +15 -1
- package/src/detectors/technical-docs.ts +5 -1
- package/src/detectors/term-mention-sentence.ts +31 -0
- package/src/detectors/titled-run.ts +9 -4
- package/src/detectors/token-shape.ts +14 -5
- package/src/detectors/vague-density.ts +20 -4
- package/src/document-paragraphs.ts +27 -0
- package/src/document.ts +3 -23
- package/src/figure-references.ts +7 -2
- package/src/format-template.ts +15 -0
- package/src/formula-brackets.ts +36 -0
- package/src/html/html-markdown.ts +2 -1
- package/src/html/html-site-chrome.ts +47 -0
- package/src/joined-view.ts +1 -0
- package/src/kanji-compound-slip.ts +98 -0
- package/src/latin-company-form.ts +38 -0
- package/src/latin-word-boundary.ts +46 -0
- package/src/lexicon-genres.ts +1 -1
- package/src/link-shape.ts +19 -0
- package/src/link-title.ts +38 -0
- package/src/list-item-paragraphs.ts +22 -0
- package/src/literal-quote.ts +55 -0
- package/src/nado-closed-list.ts +48 -5
- package/src/name-separator.ts +27 -2
- package/src/nominal-stem.ts +62 -5
- package/src/person-forms.ts +15 -0
- package/src/plugin.ts +5 -0
- package/src/preamble-paragraphs.ts +13 -3
- package/src/spacing-code.ts +5 -1
- package/src/split-noun.ts +63 -0
- package/src/structure/attached-parts.ts +32 -0
- package/src/structure/build.ts +7 -4
- package/src/structure/contents-lines.ts +63 -0
- package/src/structure/defining-names.ts +155 -0
- package/src/structure/definition-use.ts +116 -25
- package/src/structure/issues.ts +7 -3
- package/src/structure/list-lead-in.ts +94 -0
- package/src/structure/modal-conflict.ts +42 -7
- package/src/structure/negated-act.ts +49 -0
- package/src/structure/numbering.ts +24 -9
- package/src/structure/prose-total.ts +20 -6
- package/src/structure/repeated-number.ts +110 -0
- package/src/structure/rounded-amount.ts +55 -0
- package/src/structure/side-step.ts +21 -0
- package/src/structure/spanned-label-blank.ts +39 -0
- package/src/structure/universal.ts +11 -2
- package/src/structure/unspaced-heading.ts +27 -0
- package/src/structure/written-list-path.ts +46 -0
- package/src/structure/written-resolve.ts +16 -9
- package/src/title-line.ts +52 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import type { Detector, Finding, ProseDocument, Sentence, TableCell, Token } from "../plugin.ts";
|
|
1
|
+
import type { Detector, Finding, ProseDocument, Sentence, Span, TableCell, Token } from "../plugin.ts";
|
|
2
|
+
import { externalLinkTitleSpans } from "../link-title.ts";
|
|
2
3
|
import { groupBy, oddSpellings, type KeyedWord, type OddSpelling } from "../spelling-variants.ts";
|
|
3
4
|
import { dropsOkurigana, kanjiKeyAmong, katakanaKey, lemmaReading } from "../kana-spelling.ts";
|
|
4
5
|
import { isKatakanaWord, stemOf } from "../long-vowel.ts";
|
|
6
|
+
import { withNounsAfterParticles } from "../nominal-stem.ts";
|
|
5
7
|
import { QUOTATION_MARKS, isWithinAny, quotedSpans } from "../quoted-span.ts";
|
|
6
8
|
import { nameSpans, touchesAny } from "../team-names.ts";
|
|
7
9
|
import { furiganaSpans } from "../furigana.ts";
|
|
10
|
+
import { withCutNounsJoined } from "../split-noun.ts";
|
|
11
|
+
import { japaneseCompanyNameSpans } from "../company-name-run.ts";
|
|
8
12
|
import { acronymsIn, isCapitalsNotSpelling } from "../capitals-with-small.ts";
|
|
9
13
|
import { isPartOfAddress } from "./address-word.ts";
|
|
10
14
|
import { isInCapitalsPassage } from "../capitals-passage.ts";
|
|
11
15
|
import { withoutCoinedNames } from "../coined-hyphen-name.ts";
|
|
12
16
|
import { wholeWordRuns, type WholeWordRun } from "../whole-word-runs.ts";
|
|
13
17
|
import { entriesForGenre } from "../lexicon-genres.ts";
|
|
14
|
-
import { asNounWhereNominal } from "../nominal-stem.ts";
|
|
18
|
+
import { asNounWhereNominal, documentNounKeys } from "../nominal-stem.ts";
|
|
19
|
+
import { isCompoundHead } from "../compound-head.ts";
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* A word found in the document: where it is, which sentence it is in, its key and spelling, how it is written when that differs, and
|
|
@@ -42,6 +47,8 @@ const DISTINCT = "orthographic-variant-distinct";
|
|
|
42
47
|
const FUKUSHI = "hiragana-fukushi";
|
|
43
48
|
/** Lexicon: idioms written as noun, particle and verb (気をつける). The verb there is compared apart from the verb on its own. */
|
|
44
49
|
const IDIOM = "orthographic-variant-idiom";
|
|
50
|
+
/** Lexicon: verbs whose て-form opening a sentence before a comma is a conjunction (あわせて、). */
|
|
51
|
+
const CONJUNCTION = "orthographic-variant-conjunction";
|
|
45
52
|
/** Lexicon: words the tokenizer cuts in one spelling and not the other (お客様, お客 and さま). Each is read whole, keyed by its group. */
|
|
46
53
|
const WHOLE_WORD = "orthographic-variant-whole-word";
|
|
47
54
|
/** Lexicon: suffixes written onto a word that do not make a compound of it (割当て等, 引受け後): the word keeps its okurigana there. */
|
|
@@ -51,17 +58,37 @@ const patternsOf = (doc: ProseDocument, id: string, genre: string | undefined):
|
|
|
51
58
|
entriesForGenre(doc.lexicons[id] ?? [], genre).map((entry) => entry.pattern);
|
|
52
59
|
|
|
53
60
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
61
|
+
* The team's names, the company forms (株式会社, ㈱) a registered company name is written next to, and the links that quote an
|
|
62
|
+
* outside page's title (link-title.ts), placed in the source.
|
|
56
63
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
type Names = { readonly team: readonly string[]; readonly companyForms: readonly string[]; readonly linkTitles: readonly Span[] };
|
|
65
|
+
|
|
66
|
+
/** Spans placed in the source, placed in a sentence's text instead. */
|
|
67
|
+
const inSentence = (sentence: Sentence, spans: readonly Span[]): Span[] =>
|
|
68
|
+
spans.map((span) => ({ start: span.start - sentence.span.start, end: span.end - sentence.span.start }));
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Whether a stretch of the sentence is outside a quotation, the team's names, a company's name (関東珪曹硝子㈱) and a reading in
|
|
72
|
+
* brackets (HTTP(えいちてぃーてぃーぴー)): the first three keep their own spelling, and a reading is not a spelling at all.
|
|
73
|
+
*/
|
|
74
|
+
const isOpenIn = (sentence: Sentence, names: Names): IsOpen => {
|
|
75
|
+
const closed = [
|
|
76
|
+
...quotedSpans(sentence.text, QUOTATION_MARKS),
|
|
77
|
+
...furiganaSpans(sentence.text),
|
|
78
|
+
...japaneseCompanyNameSpans(sentence.text, names.companyForms),
|
|
79
|
+
...inSentence(sentence, names.linkTitles),
|
|
80
|
+
];
|
|
81
|
+
const named = nameSpans(sentence.text, names.team);
|
|
60
82
|
return (start, end) => !isWithinAny(closed, { start, end }) && !touchesAny(named, start, end);
|
|
61
83
|
};
|
|
62
84
|
|
|
63
|
-
/** A word
|
|
64
|
-
type InContext = {
|
|
85
|
+
/** A word, the two words before it and the two after it, in its sentence. */
|
|
86
|
+
type InContext = {
|
|
87
|
+
readonly token: Token;
|
|
88
|
+
readonly previous: Token | undefined;
|
|
89
|
+
readonly before: Token | undefined;
|
|
90
|
+
readonly following?: readonly Token[];
|
|
91
|
+
};
|
|
65
92
|
|
|
66
93
|
/** A verb's て-form the tokenizer read as a conjunction (追って at the head of a sentence): a kanji stem and て or で. Connectives (そして, それで) are kana. */
|
|
67
94
|
const TE_FORM_CONJUNCTION = /^\p{Script=Han}.*[てで]$/u;
|
|
@@ -99,13 +126,32 @@ const isKanaSuffix = ({ token, previous }: InContext): boolean =>
|
|
|
99
126
|
const isIdiomVerb = ({ token, previous, before }: InContext, idioms: ReadonlySet<string>): boolean =>
|
|
100
127
|
token.pos === "VERB" && previous?.pos === "ADP" && before !== undefined && idioms.has(`${before.surface}${previous.surface}${token.lemma ?? token.surface}`);
|
|
101
128
|
|
|
129
|
+
const TE = new Set(["て", "で"]);
|
|
130
|
+
const COMMA = new Set(["、", ",", ","]);
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A listed verb's て-form that opens its sentence and is followed by a comma (あわせて、…): a conjunction ("in addition"), which
|
|
134
|
+
* many guides write in kana while the verb (日程を合わせる) keeps its kanji.
|
|
135
|
+
*/
|
|
136
|
+
const isConjunctionUse = ({ token, previous, following }: InContext, conjunctions: ReadonlySet<string>): boolean =>
|
|
137
|
+
token.pos === "VERB" &&
|
|
138
|
+
conjunctions.has(token.lemma ?? "") &&
|
|
139
|
+
(previous === undefined || previous.pos === "PUNCT") &&
|
|
140
|
+
TE.has(following?.[0]?.surface ?? "") &&
|
|
141
|
+
COMMA.has(following?.[1]?.surface ?? "");
|
|
142
|
+
|
|
143
|
+
/** The lexicons that set a verb's use apart: idioms (気をつける) and conjunctions (あわせて、). */
|
|
144
|
+
type Uses = { readonly idioms: ReadonlySet<string>; readonly conjunctions: ReadonlySet<string> };
|
|
145
|
+
|
|
102
146
|
/**
|
|
103
147
|
* A helper verb or a dependent noun (見て下さい, その事) is written kana by many guides while the full word keeps its kanji (資料を下さい).
|
|
104
148
|
* The two uses are compared apart, so a document that follows that convention is consistent. A suffix (業務用, 全員ぶん) is a third use:
|
|
105
|
-
* it is not the dependent noun of the same reading (このように). The verb of an idiom (気をつける) is a fourth
|
|
149
|
+
* it is not the dependent noun of the same reading (このように). The verb of an idiom (気をつける) is a fourth, and a
|
|
150
|
+
* て-form used as a conjunction (あわせて、) a fifth.
|
|
106
151
|
*/
|
|
107
|
-
const useOf = (word: InContext, idioms:
|
|
152
|
+
const useOf = (word: InContext, { idioms, conjunctions }: Uses): string => {
|
|
108
153
|
if (isIdiomVerb(word, idioms)) return "idiom";
|
|
154
|
+
if (isConjunctionUse(word, conjunctions)) return "conjunction";
|
|
109
155
|
if (isKanaSuffix(word)) return "suffix";
|
|
110
156
|
if (!isHelper(word)) return "free";
|
|
111
157
|
return word.token.pos === "NOUN" && word.token.features?.["NounType"] !== "Dependent" ? "suffix" : "bound";
|
|
@@ -129,17 +175,21 @@ const isCopulaReadAsVerb = ({ token, previous }: InContext): boolean =>
|
|
|
129
175
|
type Skips = {
|
|
130
176
|
readonly skip: ReadonlySet<string>;
|
|
131
177
|
readonly idioms: ReadonlySet<string>;
|
|
178
|
+
readonly conjunctions: ReadonlySet<string>;
|
|
132
179
|
readonly wholeWords: ReadonlyMap<string, string>;
|
|
133
180
|
readonly phraseSuffixes: ReadonlySet<string>;
|
|
181
|
+
/** The document's nouns, as documentNounKeys keys them. */
|
|
182
|
+
readonly nouns: ReadonlySet<string>;
|
|
134
183
|
};
|
|
135
184
|
|
|
136
|
-
const readingKeyOf = (word: InContext,
|
|
185
|
+
const readingKeyOf = (word: InContext, skips: Skips): string | undefined => {
|
|
186
|
+
const { skip } = skips;
|
|
137
187
|
const { token } = word;
|
|
138
188
|
const lemma = token.lemma;
|
|
139
189
|
if (!CONTENT.has(token.pos) || token.reading === undefined || lemma === undefined || !JAPANESE_WORD.test(lemma) || skip.has(lemma)) return undefined;
|
|
140
190
|
const reading = lemmaReading(token.surface, lemma, token.reading);
|
|
141
191
|
if (reading === undefined || [...reading].length < MIN_READING || skip.has(reading) || isCutFromKatakana(word) || isCopulaReadAsVerb(word)) return undefined;
|
|
142
|
-
return `${token.pos}|${useOf(word,
|
|
192
|
+
return `${token.pos}|${useOf(word, skips)}|${reading}`;
|
|
143
193
|
};
|
|
144
194
|
|
|
145
195
|
/**
|
|
@@ -160,7 +210,7 @@ const wholeWordOf = (
|
|
|
160
210
|
|
|
161
211
|
/** Japanese words keyed by part of speech, use and the reading of the dictionary form, spelled as the dictionary form. */
|
|
162
212
|
const readingWords = (sentence: Sentence, isOpen: IsOpen, skips: Skips): Placed[] => {
|
|
163
|
-
const tokens = sentence.tokens ?? [];
|
|
213
|
+
const tokens = withNounsAfterParticles(sentence.tokens ?? []);
|
|
164
214
|
const runs = wholeWordRuns(tokens, skips.wholeWords);
|
|
165
215
|
const inRun = new Set(runs.flatMap(({ first, last }) => Array.from({ length: last - first + 1 }, (_, extra) => first + extra)));
|
|
166
216
|
const whole = runs.flatMap((run) => wholeWordOf(sentence, tokens, run, isOpen, skips.wholeWords));
|
|
@@ -169,11 +219,11 @@ const readingWords = (sentence: Sentence, isOpen: IsOpen, skips: Skips): Placed[
|
|
|
169
219
|
...tokens.flatMap((written, at): Placed[] => {
|
|
170
220
|
if (inRun.has(at)) return [];
|
|
171
221
|
const next = tokens[at + 1];
|
|
172
|
-
const token = asNounWhereNominal(written, next, skips.phraseSuffixes);
|
|
173
|
-
const key = readingKeyOf({ token, previous: tokens[at - 1], before: tokens[at - 2] }, skips);
|
|
222
|
+
const token = asNounWhereNominal(written, next, skips.phraseSuffixes, skips.nouns);
|
|
223
|
+
const key = readingKeyOf({ token, previous: tokens[at - 1], before: tokens[at - 2], following: tokens.slice(at + 1, at + 3) }, skips);
|
|
174
224
|
const local = token.span.start - sentence.span.start;
|
|
175
225
|
if (key === undefined || token.lemma === undefined || !isOpen(local, local + token.surface.length)) return [];
|
|
176
|
-
const compoundHead =
|
|
226
|
+
const compoundHead = isCompoundHead(token, tokens, at, skips.phraseSuffixes);
|
|
177
227
|
return [{ key, spelling: token.lemma, sentence, offset: token.span.start, compoundHead }];
|
|
178
228
|
}),
|
|
179
229
|
];
|
|
@@ -300,7 +350,7 @@ const LINK_CHROME = /\]\([^)]*\)|\]\[[^\]]*\]|\[/gu;
|
|
|
300
350
|
const withoutLinkChrome = (text: string): string => text.replaceAll(LINK_CHROME, (chrome) => " ".repeat(chrome.length));
|
|
301
351
|
|
|
302
352
|
/** A body cell of a table read as a sentence of its own: the prose covers tables, so a cell's words (片栗粉 in a list of ingredients) are not in the sentences. Header rows stay out. */
|
|
303
|
-
const cellPlace = (cell: TableCell, names:
|
|
353
|
+
const cellPlace = (cell: TableCell, names: Names): Place => {
|
|
304
354
|
const text = withoutLinkChrome(cell.text);
|
|
305
355
|
const sentence: Sentence = { span: { start: cell.start, end: cell.end }, text, tokens: cell.tokens ?? [] };
|
|
306
356
|
return { sentence, isOpen: isOpenIn(sentence, names), readsLatin: !DATA_KEY_CELL.test(text.trim()) };
|
|
@@ -312,18 +362,28 @@ const cellPlace = (cell: TableCell, names: readonly string[]): Place => {
|
|
|
312
362
|
* document writes less is pointed at. No way is called right; limit is the largest share, in percent, the minority may have.
|
|
313
363
|
*/
|
|
314
364
|
export const orthographicVariant: Detector = (doc, options): Finding[] => {
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
phraseSuffixes: new Set(patternsOf(doc, PHRASE_SUFFIX, options.genre)),
|
|
365
|
+
const names: Names = {
|
|
366
|
+
team: doc.names ?? [],
|
|
367
|
+
companyForms: (doc.lexicons["company-form"] ?? []).map((entry) => entry.pattern),
|
|
368
|
+
linkTitles: externalLinkTitleSpans(doc.source, doc.links),
|
|
320
369
|
};
|
|
321
|
-
const names = doc.names ?? [];
|
|
322
370
|
const placed: Place[] = [
|
|
323
371
|
...doc.sentences.map((sentence) => ({ sentence, isOpen: isOpenIn(sentence, names), readsLatin: true })),
|
|
324
372
|
...(doc.tableCells?.() ?? []).map((cell) => cellPlace(cell, names)),
|
|
325
373
|
];
|
|
326
|
-
const
|
|
374
|
+
const phraseSuffixes = new Set(patternsOf(doc, PHRASE_SUFFIX, options.genre));
|
|
375
|
+
const skips: Skips = {
|
|
376
|
+
skip: new Set([...patternsOf(doc, DISTINCT, options.genre), ...patternsOf(doc, FUKUSHI, options.genre)]),
|
|
377
|
+
idioms: new Set(patternsOf(doc, IDIOM, options.genre)),
|
|
378
|
+
conjunctions: new Set(patternsOf(doc, CONJUNCTION, options.genre)),
|
|
379
|
+
wholeWords: new Map((doc.lexicons[WHOLE_WORD] ?? []).map((entry) => [entry.pattern, entry.group ?? entry.pattern])),
|
|
380
|
+
phraseSuffixes,
|
|
381
|
+
nouns: documentNounKeys(
|
|
382
|
+
placed.map(({ sentence }) => sentence.tokens ?? []),
|
|
383
|
+
phraseSuffixes,
|
|
384
|
+
),
|
|
385
|
+
};
|
|
386
|
+
const reading = byKanji(placed.flatMap(({ sentence, isOpen }) => readingWords(withCutNounsJoined(sentence, skips.nouns), isOpen, skips)));
|
|
327
387
|
const katakana = placed.flatMap(({ sentence, isOpen }) => katakanaWords(sentence, isOpen));
|
|
328
388
|
const runs = placed.flatMap(({ sentence, isOpen }) => katakanaRunWords(sentence, isOpen));
|
|
329
389
|
const dictionary = doc.dictionary?.();
|
|
@@ -8,6 +8,7 @@ import { digitRunAround, endsWithDivisionLabel, isNumberName, sequenceLabelStart
|
|
|
8
8
|
import { isSpacedLocationPart, type FloorWords } from "../location-part.ts";
|
|
9
9
|
import { isFieldSeparator, isNameSeparator, type OrganizationWords } from "../name-separator.ts";
|
|
10
10
|
import { addressSpans, clockTimeSpans, identifierSpans, isInsideSpan } from "../spacing-code.ts";
|
|
11
|
+
import { isBoundSuffix, isJoinerSpace } from "../latin-word-boundary.ts";
|
|
11
12
|
|
|
12
13
|
/** 書いた形の出現に、動詞の活用した形(行う → 行います)を足したもの。同じ位置は一度だけ。 */
|
|
13
14
|
const avoidedStarts = (sentence: Sentence, entry: LexiconEntry, use: string): number[] => {
|
|
@@ -55,6 +56,8 @@ type NumberContext = NameContext & {
|
|
|
55
56
|
readonly itemNumbers: ReadonlySet<string>;
|
|
56
57
|
readonly floors: FloorWords;
|
|
57
58
|
readonly organizations: OrganizationWords;
|
|
59
|
+
/** 日本語の句をつなぐ英語の語(or、vs.)と、英字の語に付ける接尾の語(版、化)。 */
|
|
60
|
+
readonly latinWords: { readonly joiners: ReadonlySet<string>; readonly boundSuffixes: ReadonlySet<string> };
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
/** 文頭の項目の番号の後ろと見る境目の位置の上限。番号は短く文の頭にあるので、これより後ろの境目は番号の後ろではない。長い文で文頭からの切り出しを繰り返さない。 */
|
|
@@ -105,7 +108,12 @@ const isCounted = (sentence: Sentence, boundary: Boundary, context: NumberContex
|
|
|
105
108
|
if (followsItemNumber(sentence.text, boundary, context.itemNumbers) || besideSpan(codes.identifiers, boundary)) return false;
|
|
106
109
|
if (boundary.kind !== "after-digit" && endsWithDivisionLabel(sentence.text.slice(0, boundary.offset), context.divisions)) return false;
|
|
107
110
|
if (boundary.kind === "letter")
|
|
108
|
-
return
|
|
111
|
+
return (
|
|
112
|
+
!besideSpan(codes.addresses, boundary) &&
|
|
113
|
+
!isNameSeparator(sentence.text, boundary, sentence.tokens, sentence.span.start, context.organizations) &&
|
|
114
|
+
!isJoinerSpace(sentence.text, boundary, context.latinWords.joiners) &&
|
|
115
|
+
!isBoundSuffix(sentence.text, boundary, sentence.tokens, sentence.span.start, context.latinWords.boundSuffixes)
|
|
116
|
+
);
|
|
109
117
|
if (isInsideSpan(codes.clockTimes, digitBeside(boundary))) return false;
|
|
110
118
|
const run = digitRunAround(sentence.text, digitBeside(boundary));
|
|
111
119
|
if (run === undefined) return true;
|
|
@@ -180,6 +188,7 @@ export const latinSpacing: Detector = (doc, options): Finding[] => {
|
|
|
180
188
|
itemNumbers: numberedItems(patternList(doc, "item-number"), doc.prose ?? doc.source),
|
|
181
189
|
floors: { units: patternsOf(doc, "floor-unit"), levels: patternsOf(doc, "floor-level") },
|
|
182
190
|
organizations: { units: patternsOf(doc, "organization-unit"), forms: patternList(doc, "company-form") },
|
|
191
|
+
latinWords: { joiners: patternsOf(doc, "latin-joiner"), boundSuffixes: patternsOf(doc, "latin-bound-suffix") },
|
|
183
192
|
};
|
|
184
193
|
const located: Located[] = doc.sentences.flatMap((sentence) => {
|
|
185
194
|
const quoted = quotedSpans(sentence.text);
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
type View,
|
|
46
46
|
} from "./list-view.ts";
|
|
47
47
|
import { lowerBound, type TokenRange } from "./token-column.ts";
|
|
48
|
+
import { followsPostcode } from "./postcode-end.ts";
|
|
48
49
|
|
|
49
50
|
const EMPTY: TokenRange = { start: 0, end: 0 };
|
|
50
51
|
|
|
@@ -55,10 +56,35 @@ const commaBefore = (scope: ItemScope, at: number): boolean => scope.sentence.to
|
|
|
55
56
|
* 節の最初の項目が前置詞・接続詞・副詞・to・過去分詞で始まり、次の項目と頭の形が違えば外す。
|
|
56
57
|
* Quickly, quietly and carefully は残る。For managers, engineers and designers, も外れるが、前置詞のあとの名詞を
|
|
57
58
|
* 項目と読むと、Over this period, the subcommittees and the full committee ... を並びと誤る。こちらのほうが多い。
|
|
59
|
+
* 順番の語(First,)のあとにもう一つ導入の句が続く(First, outside a block, …)ときは、順番の語を外してから確かめる。
|
|
58
60
|
*/
|
|
59
61
|
const LEAD_POS = new Set(["ADP", "SCONJ", "ADV", "PART"]);
|
|
60
62
|
|
|
63
|
+
const isSequenceWord = (scope: ItemScope, token: Token | undefined): boolean => scope.sentence.words.sequence?.has(token?.surface.toLowerCase() ?? "") ?? false;
|
|
64
|
+
|
|
65
|
+
const SENTENCE_MARKS = new Set(["PUNCT", "SYM"]);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 順番の語と読点(First, / Next,)で始まる最初の項目から、その語を外した並び。解析器は First を形容詞と読み、読点で項目を切らないことがある。
|
|
69
|
+
* 文頭の語だけ。文の途中の first は項目のことがある(We support first, fallback, and legacy modes)。
|
|
70
|
+
* 次の項目も順番の語なら、順番の語の並び(first, second and third)なので外さない。
|
|
71
|
+
*/
|
|
72
|
+
const withoutSequenceWord = (view: View): View | undefined => {
|
|
73
|
+
const { scope } = view.list;
|
|
74
|
+
const [first, second] = [firstOf(view), secondOf(view)];
|
|
75
|
+
if (first === undefined || second === undefined) return undefined;
|
|
76
|
+
const at = firstAt(scope, "open", first.item);
|
|
77
|
+
const { tokens } = scope.sentence;
|
|
78
|
+
const opensSentence = tokens.slice(0, at).every((token) => SENTENCE_MARKS.has(token.pos));
|
|
79
|
+
if (!opensSentence || !isSequenceWord(scope, tokens[at]) || tokens[at + 1]?.surface !== "," || isSequenceWord(scope, openingOf(scope, second.item)))
|
|
80
|
+
return undefined;
|
|
81
|
+
const rest = { start: at + 2, end: first.item.end };
|
|
82
|
+
return hasContent(scope, rest) ? { ...withoutFirst(view), pre: rest } : withoutFirst(view);
|
|
83
|
+
};
|
|
84
|
+
|
|
61
85
|
const withoutLead = (view: View): View => {
|
|
86
|
+
const afterSequence = withoutSequenceWord(view);
|
|
87
|
+
if (afterSequence !== undefined) return withoutLead(afterSequence);
|
|
62
88
|
const { scope } = view.list;
|
|
63
89
|
const [first, second] = [firstOf(view), secondOf(view)];
|
|
64
90
|
const opening = first === undefined ? undefined : openingOf(scope, first.item);
|
|
@@ -225,6 +251,15 @@ const itemsAgree = (scope: ItemScope, view: View, afterItem: TokenRange, shape:
|
|
|
225
251
|
return clausesAgree && (!VERBAL.has(shape) || every(view, "hasVerb"));
|
|
226
252
|
};
|
|
227
253
|
|
|
254
|
+
/** 否定で始まる項目(not cleaner)。 */
|
|
255
|
+
const CONTRAST = new Set(["not", "never"]);
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* and / or の前の項目が否定で始まれば、読点の前と対比している(more correct, not cleaner or more elegant)。
|
|
259
|
+
* and / or が結ぶのは否定の中の 2 つで、読点の前の項目と並ぶ 3 つではない。
|
|
260
|
+
*/
|
|
261
|
+
const opensContrast = (scope: ItemScope, item: TokenRange): boolean => CONTRAST.has(openingOf(scope, item)?.surface.toLowerCase() ?? "");
|
|
262
|
+
|
|
228
263
|
/**
|
|
229
264
|
* 読点で区切った項目が and / or の前に 2 つ以上あり、最後の項目と and の後ろが同じ形のときだけ並列。
|
|
230
265
|
* 導入の読点(After the review, the team fixed the bug and shipped it.)や、節をつなぐ読点
|
|
@@ -237,6 +272,7 @@ const listAt = (list: ItemList, at: number): boolean | undefined => {
|
|
|
237
272
|
const items = fromParticiplePhrase(fromExample(afterClosedList(withoutLead(wholeList(list)))), afterItem);
|
|
238
273
|
if (listContinues(scope, afterItem) || isAppositive(scope, at, items, afterItem) || insideLastItem(scope, at, items, afterItem)) return undefined;
|
|
239
274
|
const last = lastOf(items);
|
|
275
|
+
if (last !== undefined && opensContrast(scope, last.item)) return undefined;
|
|
240
276
|
const shape = last === undefined ? undefined : shapeOf(scope, last.item);
|
|
241
277
|
if (sizeOf(items) < 2 || shape === undefined || shape !== shapeOf(scope, afterItem)) return undefined;
|
|
242
278
|
return itemsAgree(scope, items, afterItem, shape) ? commaBefore(scope, at) : undefined;
|
|
@@ -254,7 +290,8 @@ export const listVerdicts = (tokens: readonly Token[], words: ListWords, source:
|
|
|
254
290
|
const readItems = listReader(sentence);
|
|
255
291
|
return tokens.flatMap((token, at) => {
|
|
256
292
|
if (!isJudgedConjunction(token, at)) return [];
|
|
257
|
-
|
|
293
|
+
// 郵便番号で終わる住所のあとの and / or は、住所の行を区切る読点のあと。並びの読点ではない。
|
|
294
|
+
return [sentence.inCitedTitle(at) || followsPostcode(source, token.span.start) ? undefined : listAt(readItems(at), at)];
|
|
258
295
|
});
|
|
259
296
|
};
|
|
260
297
|
|
|
@@ -275,6 +312,8 @@ export const oxfordComma: Detector = (doc, options): Finding[] => {
|
|
|
275
312
|
example: doc.lexicons["example-marker"] ?? [],
|
|
276
313
|
pair: patternsOf(doc.lexicons["pair-opener"]),
|
|
277
314
|
region: doc.lexicons["place-region"] ?? [],
|
|
315
|
+
titleCue: (doc.lexicons["title-cue"] ?? []).map((entry) => entry.pattern),
|
|
316
|
+
sequence: patternsOf(doc.lexicons["sequence-opener"]),
|
|
278
317
|
};
|
|
279
318
|
const judged = doc.sentences.flatMap((sentence) => {
|
|
280
319
|
const oxford = oxfordIn(sentence.tokens ?? [], words, doc.source);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Detector, Finding, ProseDocument, Sentence } from "../plugin.ts";
|
|
2
|
-
import { personMentions, personMinorities, type PersonMention, type PersonWords } from "../person-forms.ts";
|
|
2
|
+
import { personMentions, personMinorities, withoutOtherSenses, type PersonMention, type PersonWords } from "../person-forms.ts";
|
|
3
3
|
|
|
4
4
|
const wordsOf = (doc: ProseDocument, words: PersonWords["words"]): PersonWords => ({
|
|
5
5
|
words,
|
|
@@ -9,14 +9,16 @@ const wordsOf = (doc: ProseDocument, words: PersonWords["words"]): PersonWords =
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* One document naming itself (私たち / 弊社, 私 / 筆者) or its reader (you / one) two ways: the minority form of each slot.
|
|
12
|
-
* Sentences in another language than the document's are left out; quotations are left out by personMentions.
|
|
12
|
+
* Sentences in another language than the document's are left out; quotations are left out by personMentions. A form the
|
|
13
|
+
* language package lists in person-other-sense (本社, also the head office) counts only where it is the usual form.
|
|
13
14
|
*/
|
|
14
15
|
export const personMix: Detector = (doc, options): Finding[] => {
|
|
15
16
|
const person = wordsOf(doc, options.lexicon ?? []);
|
|
16
17
|
const entries: { readonly sentence: Sentence; readonly mention: PersonMention }[] = doc.sentences
|
|
17
18
|
.filter((sentence) => sentence.embeddedLanguage === undefined)
|
|
18
19
|
.flatMap((sentence) => personMentions(sentence.text, person).map((mention) => ({ sentence, mention })));
|
|
19
|
-
|
|
20
|
+
const otherSenses = new Set((doc.lexicons["person-other-sense"] ?? []).map((entry) => entry.pattern));
|
|
21
|
+
return personMinorities(withoutOtherSenses(entries, otherSenses), options.limit).flatMap(({ odd, usual, of }) =>
|
|
20
22
|
odd.map(({ sentence, mention }) => ({
|
|
21
23
|
rule: "",
|
|
22
24
|
severity: "info" as const,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Detector, DetectorOptions, Finding, Lexicon, ProseDocument, Sentence } from "../plugin.ts";
|
|
1
|
+
import type { Detector, DetectorOptions, Finding, Lexicon, LexiconEntry, ProseDocument, Sentence } from "../plugin.ts";
|
|
2
2
|
import { entryEnds, entryIn } from "./lexicon-match.ts";
|
|
3
|
+
import { mentionCuesOf, onlyMentioned } from "./mentioned-phrase.ts";
|
|
3
4
|
import { closingSentences } from "../closing-paragraph.ts";
|
|
4
5
|
|
|
5
6
|
/** 冒頭は先頭 2 段落ぶん。「どの記事にも当てはまる書き出し」は冒頭にあるときだけ問題。 */
|
|
@@ -17,9 +18,12 @@ const inScope = (doc: ProseDocument, where: string | undefined): readonly Senten
|
|
|
17
18
|
|
|
18
19
|
type Hit = { readonly sentence: Sentence; readonly matched: string };
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
/** Whether the entry's words in the sentence count as a use. phrase-match counts every one. */
|
|
22
|
+
type IsUsed = (sentence: Sentence, entry: LexiconEntry) => boolean;
|
|
23
|
+
|
|
24
|
+
const hitsIn = (sentences: readonly Sentence[], lexicon: Lexicon, isUsed: IsUsed = () => true): Hit[] =>
|
|
21
25
|
sentences.flatMap((sentence) => {
|
|
22
|
-
const matched = lexicon.find((entry) => entryIn(sentence, entry));
|
|
26
|
+
const matched = lexicon.find((entry) => entryIn(sentence, entry) && isUsed(sentence, entry));
|
|
23
27
|
return matched === undefined ? [] : [{ sentence, matched: matched.pattern }];
|
|
24
28
|
});
|
|
25
29
|
|
|
@@ -33,9 +37,9 @@ const findingsOf = (hits: readonly Hit[], limit: number, count = hits.length): F
|
|
|
33
37
|
values: { matched: hit.matched, count, limit, offset: hit.sentence.span.start },
|
|
34
38
|
}));
|
|
35
39
|
|
|
36
|
-
const phraseHits = (doc: ProseDocument, options: DetectorOptions): Hit[] => {
|
|
40
|
+
const phraseHits = (doc: ProseDocument, options: DetectorOptions, isUsed?: IsUsed): Hit[] => {
|
|
37
41
|
const lexicon = options.lexicon ?? [];
|
|
38
|
-
return lexicon.length === 0 ? [] : hitsIn(inScope(doc, options.where), lexicon);
|
|
42
|
+
return lexicon.length === 0 ? [] : hitsIn(inScope(doc, options.where), lexicon, isUsed);
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
/**
|
|
@@ -47,6 +51,13 @@ export const phraseMatch: Detector = (doc, options): Finding[] => {
|
|
|
47
51
|
return hits.length < options.limit ? [] : findingsOf(hits, options.limit);
|
|
48
52
|
};
|
|
49
53
|
|
|
54
|
+
/** phrase-match の、言葉として名指しただけの言い回し(the phrase "…", 「…」という言い方)を数えない版(mentioned-phrase.ts)。 */
|
|
55
|
+
export const phraseInUse: Detector = (doc, options): Finding[] => {
|
|
56
|
+
const cues = mentionCuesOf(doc.lexicons["mention-cue"] ?? []);
|
|
57
|
+
const hits = phraseHits(doc, options, (sentence, entry) => !onlyMentioned(sentence, entry, cues));
|
|
58
|
+
return hits.length < options.limit ? [] : findingsOf(hits, options.limit);
|
|
59
|
+
};
|
|
60
|
+
|
|
50
61
|
type Uses = { readonly sentence: Sentence; readonly matched: string; readonly count: number };
|
|
51
62
|
|
|
52
63
|
/**
|
|
@@ -29,6 +29,7 @@ const withoutClosers = (text: string): string => {
|
|
|
29
29
|
/** Lexicon groups of placeholder-word. An entry without a group is a word written inside a template's brackets. */
|
|
30
30
|
const MARKER = "marker";
|
|
31
31
|
const INSTRUCTION = "instruction";
|
|
32
|
+
const LABEL = "label";
|
|
32
33
|
|
|
33
34
|
const innerOf = (match: RegExpExecArray): string => (match[1] ?? match[2] ?? match[3] ?? "").trim().toLowerCase();
|
|
34
35
|
|
|
@@ -64,11 +65,24 @@ const markerSpans = (text: string, markers: Lexicon): Span[] => {
|
|
|
64
65
|
return [{ start, end: start + withoutClosers(rest).length }];
|
|
65
66
|
};
|
|
66
67
|
|
|
68
|
+
/**
|
|
69
|
+
* A template's instruction label left in the text ("OPTIONAL: General conclusions"): the label exactly as the lexicon
|
|
70
|
+
* writes it, in capitals, opening the line before a colon and some text. "Optional: bring a jacket" is a note, not a label.
|
|
71
|
+
*/
|
|
72
|
+
const labelSpans = (line: string, labels: Lexicon): Span[] => {
|
|
73
|
+
const start = OPENING.exec(line)?.[0].length ?? 0;
|
|
74
|
+
const rest = line.slice(start);
|
|
75
|
+
const label = labels.find((entry) => rest.startsWith(entry.pattern));
|
|
76
|
+
if (label === undefined) return [];
|
|
77
|
+
const after = rest.slice(label.pattern.length);
|
|
78
|
+
return COLON_NEXT.test(after) && withoutClosers(after.replace(COLON_NEXT, "")) !== "" ? [{ start, end: start + rest.trimEnd().length }] : [];
|
|
79
|
+
};
|
|
80
|
+
|
|
67
81
|
/** Each line of a sentence on its own: values a line apart ("TBD: owner" then "TBD: date") are two blanks, not one. */
|
|
68
|
-
const lineMarkerSpans = (text: string, markers: Lexicon): Span[] =>
|
|
82
|
+
const lineMarkerSpans = (text: string, markers: Lexicon, labels: Lexicon): Span[] =>
|
|
69
83
|
text.split("\n").flatMap((line, index, lines) => {
|
|
70
84
|
const offset = lines.slice(0, index).reduce((sum, previous) => sum + previous.length + 1, 0);
|
|
71
|
-
return markerSpans(line, markers).map((span) => ({ start: span.start + offset, end: span.end + offset }));
|
|
85
|
+
return [...markerSpans(line, markers), ...labelSpans(line, labels)].map((span) => ({ start: span.start + offset, end: span.end + offset }));
|
|
72
86
|
});
|
|
73
87
|
|
|
74
88
|
/** 文の中の、埋め忘れた雛形の空欄([Your Name]、【会社名】、(ここに会社名を書く)、TBD: …)の範囲。words は placeholder-word の語彙表。 */
|
|
@@ -76,9 +90,10 @@ export const placeholderSpans = (text: string, words: Lexicon): Span[] => {
|
|
|
76
90
|
const bracketWords = words.filter((word) => word.group === undefined);
|
|
77
91
|
const instructions = words.filter((word) => word.group === INSTRUCTION);
|
|
78
92
|
const markers = words.filter((word) => word.group === MARKER);
|
|
93
|
+
const labels = words.filter((word) => word.group === LABEL);
|
|
79
94
|
return [
|
|
80
95
|
...bracketedSpans(text, BRACKETED, (inner) => holdsWord(inner, bracketWords)),
|
|
81
96
|
...(instructions.length === 0 ? [] : bracketedSpans(text, PARENTHESIZED, (inner) => opensWith(inner, instructions))),
|
|
82
|
-
...lineMarkerSpans(text, markers),
|
|
97
|
+
...lineMarkerSpans(text, markers, labels),
|
|
83
98
|
].toSorted((left, right) => left.start - right.start);
|
|
84
99
|
};
|
|
@@ -5,6 +5,8 @@ import { escapeRegExp } from "../orthography.ts";
|
|
|
5
5
|
* 定型文の書式で、略語ではない。繰り返しの語が、日付・時刻の単位の語(年、月、日)の前にあるか、
|
|
6
6
|
* 区切り(/、:、-、.)で別の繰り返しの語か数字と繋がっているときだけ認める。単位の語は言語パッケージの語彙表から読む。
|
|
7
7
|
* AI時代の AI や CI/CD の CD は、同じ文字の繰り返しではないので略語のまま数える。
|
|
8
|
+
* 単位の前には空白 1 つを挟んでもよい(XX 月 XX 日)。ひな形が名前の代わりに書く O か X を 4 つ以上並べた語(OOOO、XXXX)も、
|
|
9
|
+
* 単位が無くても略語ではない。3 つまで(AAA、XXX)は略語にもあり、ほかの文字の繰り返し(IIII、MMMMM)は崩れたローマ数字にもある。
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
type Span = { readonly start: number; readonly end: number };
|
|
@@ -14,6 +16,7 @@ const PART = String.raw`(?:[A-Z]{2,}|\d+)`;
|
|
|
14
16
|
const SEPARATOR = "[//::.-]";
|
|
15
17
|
const JOINED = new RegExp(String.raw`(?<![A-Za-z0-9_&])${PART}(?:${SEPARATOR}${PART})+(?![A-Za-z0-9_&])`, "gu");
|
|
16
18
|
const CAPITALS = /[A-Z]+/gu;
|
|
19
|
+
const LONG_REPEAT = /(?<![A-Za-z0-9_&])(?<letter>[OX])\k<letter>{3,}(?![A-Za-z0-9_&])/gu;
|
|
17
20
|
|
|
18
21
|
const isRepeated = (word: string): boolean => REPEATED.test(word);
|
|
19
22
|
|
|
@@ -30,9 +33,13 @@ const joinedSpans = (text: string): Span[] =>
|
|
|
30
33
|
|
|
31
34
|
const beforeUnitSpans = (text: string, units: readonly string[]): Span[] => {
|
|
32
35
|
if (units.length === 0) return [];
|
|
33
|
-
const pattern = new RegExp(String.raw`(?<![A-Za-z0-9_&])[A-Z]{2,}(
|
|
36
|
+
const pattern = new RegExp(String.raw`(?<![A-Za-z0-9_&])[A-Z]{2,}(?= ?(?:${units.map(escapeRegExp).join("|")}))`, "gu");
|
|
34
37
|
return [...text.matchAll(pattern)].filter((match) => isRepeated(match[0])).map(spanOf);
|
|
35
38
|
};
|
|
36
39
|
|
|
37
|
-
/**
|
|
38
|
-
export const placeholderSpans = (text: string, units: readonly string[]): Span[] => [
|
|
40
|
+
/** 文の中の、日付・時刻の書式とひな形の名前に置いた大文字の範囲。units は日付・時刻の単位の語。 */
|
|
41
|
+
export const placeholderSpans = (text: string, units: readonly string[]): Span[] => [
|
|
42
|
+
...joinedSpans(text),
|
|
43
|
+
...beforeUnitSpans(text, units),
|
|
44
|
+
...[...text.matchAll(LONG_REPEAT)].map(spanOf),
|
|
45
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// A postal address closed by its postcode right before an and / or ("… Upper Street, Leeds LS1 4AB, or email us"). The
|
|
2
|
+
// commas between the address's lines are the address's, not a list's. Pure.
|
|
3
|
+
|
|
4
|
+
/** UK (LS1 4AB, TW9 4DU, EC1A 1BB), US state and ZIP (IL 62701, DC 20001-1234), Canada (K1A 0B1). */
|
|
5
|
+
const POSTCODE = String.raw`(?:[A-Z]{1,2}\d[A-Z\d]? \d[A-Z]{2}|[A-Z]{2} \d{5}(?:-\d{4})?|[A-Z]\d[A-Z] \d[A-Z]\d)`;
|
|
6
|
+
/**
|
|
7
|
+
* The place the postcode is written after: a town (Leeds, Springfield,) or a province's code (ON). A code after a
|
|
8
|
+
* lower-case word ("model X1 4AB") is a product's, not an address's.
|
|
9
|
+
*/
|
|
10
|
+
const PLACE = String.raw`(?<![\w-])(?:[A-Z][a-z]+|[A-Z]{2}),? `;
|
|
11
|
+
const POSTCODE_BEFORE = new RegExp(String.raw`${PLACE}${POSTCODE},?[ \t]*$`, "u");
|
|
12
|
+
/** How far back the place may start: a long town name, the longest postcode and its comma, with room for spacing. */
|
|
13
|
+
const REACH = 48;
|
|
14
|
+
|
|
15
|
+
/** Whether the text before offset ends with a place and its postcode, the comma after it allowed. */
|
|
16
|
+
export const followsPostcode = (source: string, offset: number): boolean => POSTCODE_BEFORE.test(source.slice(Math.max(0, offset - REACH), offset));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProseDocument } from "../plugin.ts";
|
|
2
|
+
import type { TotalWords } from "../structure/prose-total.ts";
|
|
3
|
+
|
|
4
|
+
const patternsOf = (doc: ProseDocument, id: string, group?: string): string[] =>
|
|
5
|
+
(doc.lexicons[id] ?? []).filter((entry) => group === undefined || entry.group === group).map((entry) => entry.pattern);
|
|
6
|
+
|
|
7
|
+
/** total-mismatch が文の中の合計と内訳を読む語。言語パッケージの語彙表から取る。 */
|
|
8
|
+
export const proseTotalWordsOf = (doc: ProseDocument): TotalWords => ({
|
|
9
|
+
totals: patternsOf(doc, "total-phrase"),
|
|
10
|
+
breakdowns: patternsOf(doc, "breakdown-phrase"),
|
|
11
|
+
discounts: patternsOf(doc, "discount-word"),
|
|
12
|
+
joiners: patternsOf(doc, "breakdown-gap-joiner"),
|
|
13
|
+
leads: patternsOf(doc, "total-breakdown-lead"),
|
|
14
|
+
partials: patternsOf(doc, "breakdown-partial-word"),
|
|
15
|
+
mainOnly: patternsOf(doc, "breakdown-partial-word", "main"),
|
|
16
|
+
backReferences: patternsOf(doc, "total-back-reference"),
|
|
17
|
+
roundedUnits: patternsOf(doc, "rounded-amount-unit"),
|
|
18
|
+
});
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Detector, Finding, Lexicon, LexiconEntry, ProseDocument, Sentence } from "../plugin.ts";
|
|
2
2
|
import { entryCloses, entryIn, entryRanges } from "./lexicon-match.ts";
|
|
3
|
+
import { classWordsOf, isClassCue, namesClassAfter } from "./open-end-class.ts";
|
|
4
|
+
import { glossesCondition } from "./open-end-condition.ts";
|
|
3
5
|
import { openEndAt, openEndNames, type OpenEndNames } from "./open-end-names.ts";
|
|
6
|
+
import { asksAfter, questionWordsOf } from "./open-end-question.ts";
|
|
7
|
+
import { isScopeCue, openOnPurpose, scopeWordsOf } from "./open-end-scope.ts";
|
|
4
8
|
import { statesConcrete } from "./vague-deadline.ts";
|
|
5
9
|
|
|
6
10
|
// Requirements smells (Femmer et al. 2017; Berry et al. 2003; ISO/IEC/IEEE 29148): a loophole, an open-ended list and
|
|
@@ -9,6 +13,10 @@ import { statesConcrete } from "./vague-deadline.ts";
|
|
|
9
13
|
|
|
10
14
|
const OPEN_END = "requirement-open-end";
|
|
11
15
|
const LOOPHOLE = "requirement-loophole";
|
|
16
|
+
/** The words of a question that an open list gives example answers to. */
|
|
17
|
+
const OPEN_QUESTION = "requirement-open-question";
|
|
18
|
+
/** The words of a condition whose bracketed examples an open list may give. */
|
|
19
|
+
const OPEN_CONDITION = "requirement-open-condition";
|
|
12
20
|
const TIME = "time";
|
|
13
21
|
const CONCRETE_DEADLINE = "concrete-deadline";
|
|
14
22
|
|
|
@@ -56,20 +64,45 @@ const boundedInTime = (doc: ProseDocument, sentence: Sentence, entry: LexiconEnt
|
|
|
56
64
|
(doc.lexicons[CONCRETE_DEADLINE] ?? []).map((limit) => limit.pattern),
|
|
57
65
|
);
|
|
58
66
|
|
|
59
|
-
/**
|
|
67
|
+
/** A lexicon's words; the open-end lexicon also holds the cues of a class named after the list and of what holds it, which are no smell. */
|
|
68
|
+
const smellWords = (doc: ProseDocument, lexicon: string): LexiconEntry[] =>
|
|
69
|
+
(doc.lexicons[lexicon] ?? []).filter((entry) => !isClassCue(entry) && !isScopeCue(entry));
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Where the word stands as a smell. An open-end word inside a name the document gives (業務執行取締役等), giving examples
|
|
73
|
+
* of a class named right after it (印刷等、二次的に利用), or ending a list a condition, a permission or a prohibition holds
|
|
74
|
+
* (転載等をしてはならない), is none; without tokens none of these can be told apart.
|
|
75
|
+
*/
|
|
60
76
|
const smellAt = (doc: ProseDocument, sentence: Sentence, entry: LexiconEntry, lexicon: string, names: () => OpenEndNames): number | undefined => {
|
|
61
77
|
if (!entryIn(sentence, entry) || boundedInTime(doc, sentence, entry, lexicon)) return undefined;
|
|
62
78
|
const tokenized = sentence.tokens !== undefined && (entry.tokens?.length ?? 0) > 0;
|
|
63
|
-
|
|
79
|
+
if (lexicon !== OPEN_END || !tokenized) return offsetOf(sentence, entry);
|
|
80
|
+
const classWords = classWordsOf(doc.lexicons[OPEN_END] ?? []);
|
|
81
|
+
const scopeWords = scopeWordsOf(doc.lexicons[OPEN_END] ?? []);
|
|
82
|
+
return openEndAt(doc, sentence, entry, names(), (tokens, range) => namesClassAfter(tokens, range, classWords) || openOnPurpose(tokens, range, scopeWords));
|
|
64
83
|
};
|
|
65
84
|
|
|
85
|
+
/** An open list right before a question the reader answers (…措置など、どのような措置を求めるのか): its items are example answers. */
|
|
86
|
+
const answersQuestion = (doc: ProseDocument, sentence: Sentence, entry: LexiconEntry, lexicon: string, offset: number): boolean =>
|
|
87
|
+
lexicon === OPEN_END && asksAfter(sentence, offset + entry.pattern.length, questionWordsOf(doc.lexicons[OPEN_QUESTION] ?? []));
|
|
88
|
+
|
|
89
|
+
/** An open list in brackets right after a condition word (場合(単一テーブルへの SELECT 等)): examples of when, not of what. */
|
|
90
|
+
const glossesConditionAt = (doc: ProseDocument, sentence: Sentence, lexicon: string, offset: number): boolean =>
|
|
91
|
+
lexicon === OPEN_END &&
|
|
92
|
+
glossesCondition(
|
|
93
|
+
sentence,
|
|
94
|
+
offset,
|
|
95
|
+
(doc.lexicons[OPEN_CONDITION] ?? []).map((entry) => entry.pattern),
|
|
96
|
+
);
|
|
97
|
+
|
|
66
98
|
/** The first word of each smell in one requirement sentence: one finding per smell, not per word. */
|
|
67
99
|
const smellsIn = (doc: ProseDocument, sentence: Sentence, names: () => OpenEndNames): Finding[] =>
|
|
68
100
|
SMELLS.flatMap(({ lexicon, variant }) =>
|
|
69
|
-
(doc
|
|
101
|
+
smellWords(doc, lexicon)
|
|
70
102
|
.flatMap((entry) => {
|
|
71
103
|
const offset = smellAt(doc, sentence, entry, lexicon, names);
|
|
72
|
-
|
|
104
|
+
const examples = offset !== undefined && (answersQuestion(doc, sentence, entry, lexicon, offset) || glossesConditionAt(doc, sentence, lexicon, offset));
|
|
105
|
+
return offset === undefined || examples ? [] : [findingOf(sentence, entry, variant, offset)];
|
|
73
106
|
})
|
|
74
107
|
.slice(0, 1),
|
|
75
108
|
);
|
|
@@ -80,6 +113,6 @@ export const requirementSmell: Detector = (doc): Finding[] => {
|
|
|
80
113
|
const statements = (doc.lexicons[STATEMENTS] ?? []).map((entry) => entry.pattern);
|
|
81
114
|
// Read once, and only when a requirement has an open-end word to tell apart from a name.
|
|
82
115
|
const cache: { names?: OpenEndNames } = {};
|
|
83
|
-
const names = (): OpenEndNames => (cache.names ??= openEndNames(doc, doc
|
|
116
|
+
const names = (): OpenEndNames => (cache.names ??= openEndNames(doc, smellWords(doc, OPEN_END), statements));
|
|
84
117
|
return doc.sentences.filter((sentence) => isRequirement(sentence, markers, notMarkers)).flatMap((sentence) => smellsIn(doc, sentence, names));
|
|
85
118
|
};
|