chaffjs 0.35.0 → 0.37.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 +42 -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 +19 -0
- package/dist/detectors/acronym-link.d.ts.map +1 -0
- package/dist/detectors/acronym-link.js +65 -0
- package/dist/detectors/acronym-link.js.map +1 -0
- package/dist/detectors/acronym-mention.d.ts +5 -0
- package/dist/detectors/acronym-mention.d.ts.map +1 -0
- package/dist/detectors/acronym-mention.js +34 -0
- package/dist/detectors/acronym-mention.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 +25 -6
- 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/addressee-title-edge.d.ts +21 -0
- package/dist/detectors/addressee-title-edge.d.ts.map +1 -0
- package/dist/detectors/addressee-title-edge.js +22 -0
- package/dist/detectors/addressee-title-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/capitalised-term.d.ts +4 -0
- package/dist/detectors/capitalised-term.d.ts.map +1 -1
- package/dist/detectors/capitalised-term.js +18 -1
- package/dist/detectors/capitalised-term.js.map +1 -1
- package/dist/detectors/caps-caption.d.ts +17 -6
- package/dist/detectors/caps-caption.d.ts.map +1 -1
- package/dist/detectors/caps-caption.js +65 -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 +56 -20
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/citation-sentence.d.ts +8 -0
- package/dist/detectors/citation-sentence.d.ts.map +1 -0
- package/dist/detectors/citation-sentence.js +40 -0
- package/dist/detectors/citation-sentence.js.map +1 -0
- 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/contraction-mention.d.ts +3 -0
- package/dist/detectors/contraction-mention.d.ts.map +1 -0
- package/dist/detectors/contraction-mention.js +22 -0
- package/dist/detectors/contraction-mention.js.map +1 -0
- 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/dash-break.d.ts +7 -0
- package/dist/detectors/dash-break.d.ts.map +1 -0
- package/dist/detectors/dash-break.js +30 -0
- package/dist/detectors/dash-break.js.map +1 -0
- 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 +30 -8
- 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 +14 -6
- 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/document-shape.d.ts +5 -0
- package/dist/detectors/document-shape.d.ts.map +1 -1
- package/dist/detectors/document-shape.js +15 -1
- package/dist/detectors/document-shape.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/duplicate-heading.d.ts +1 -0
- package/dist/detectors/duplicate-heading.d.ts.map +1 -1
- package/dist/detectors/duplicate-heading.js +25 -3
- package/dist/detectors/duplicate-heading.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 +40 -3
- package/dist/detectors/email-letter.d.ts.map +1 -1
- package/dist/detectors/email-letter.js +110 -17
- 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/fullwidth-alnum.d.ts.map +1 -1
- package/dist/detectors/fullwidth-alnum.js +7 -1
- package/dist/detectors/fullwidth-alnum.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 +9 -0
- package/dist/detectors/gram-openers.d.ts.map +1 -0
- package/dist/detectors/gram-openers.js +40 -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/heading-record-rhythm.d.ts +9 -0
- package/dist/detectors/heading-record-rhythm.d.ts.map +1 -0
- package/dist/detectors/heading-record-rhythm.js +57 -0
- package/dist/detectors/heading-record-rhythm.js.map +1 -0
- 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 +83 -12
- package/dist/detectors/kutoten-consistency.js.map +1 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +13 -4
- 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 +13 -4
- package/dist/detectors/mark-shape.d.ts.map +1 -1
- package/dist/detectors/mark-shape.js +73 -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/name-variant.d.ts.map +1 -1
- package/dist/detectors/name-variant.js +6 -0
- package/dist/detectors/name-variant.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 -7
- package/dist/detectors/organisation-run.d.ts.map +1 -1
- package/dist/detectors/organisation-run.js +10 -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 +85 -20
- package/dist/detectors/orthographic-variant.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +9 -2
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/oxford-comma.d.ts.map +1 -1
- package/dist/detectors/oxford-comma.js +70 -3
- 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/range-notation.d.ts +2 -2
- package/dist/detectors/range-notation.d.ts.map +1 -1
- package/dist/detectors/range-notation.js +18 -7
- package/dist/detectors/range-notation.js.map +1 -1
- 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 +35 -7
- 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 +12 -2
- package/dist/detectors/sentence-counts.d.ts.map +1 -1
- package/dist/detectors/sentence-counts.js +52 -11
- 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-length.d.ts.map +1 -1
- package/dist/detectors/sentence-length.js +13 -4
- package/dist/detectors/sentence-length.js.map +1 -1
- package/dist/detectors/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 +44 -52
- 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/superlative-name.d.ts +5 -0
- package/dist/detectors/superlative-name.d.ts.map +1 -1
- package/dist/detectors/superlative-name.js +9 -0
- package/dist/detectors/superlative-name.js.map +1 -1
- 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 +15 -5
- package/dist/detectors/token-shape.js.map +1 -1
- package/dist/detectors/undefined-term.d.ts.map +1 -1
- package/dist/detectors/undefined-term.js +5 -0
- package/dist/detectors/undefined-term.js.map +1 -1
- package/dist/detectors/unknown-word.d.ts +4 -1
- package/dist/detectors/unknown-word.d.ts.map +1 -1
- package/dist/detectors/unknown-word.js +1 -1
- package/dist/detectors/unknown-word.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 +56 -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 +20 -0
- package/dist/latin-word-boundary.d.ts.map +1 -0
- package/dist/latin-word-boundary.js +57 -0
- package/dist/latin-word-boundary.js.map +1 -0
- package/dist/leading-label.d.ts +4 -0
- package/dist/leading-label.d.ts.map +1 -0
- package/dist/leading-label.js +14 -0
- package/dist/leading-label.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 +6 -0
- package/dist/link-shape.d.ts.map +1 -1
- package/dist/link-shape.js +27 -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-misspelt-usual.d.ts +5 -0
- package/dist/name-misspelt-usual.d.ts.map +1 -0
- package/dist/name-misspelt-usual.js +19 -0
- package/dist/name-misspelt-usual.js.map +1 -0
- 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/notice-header.d.ts +19 -0
- package/dist/notice-header.d.ts.map +1 -0
- package/dist/notice-header.js +31 -0
- package/dist/notice-header.js.map +1 -0
- 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/sentence-load.d.ts +2 -1
- package/dist/sentence-load.d.ts.map +1 -1
- package/dist/sentence-load.js +11 -3
- package/dist/sentence-load.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 +12 -0
- package/dist/structure/attached-parts.d.ts.map +1 -0
- package/dist/structure/attached-parts.js +44 -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 +8 -4
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +123 -38
- package/dist/structure/definition-use.js.map +1 -1
- package/dist/structure/gerund-phrase.d.ts +8 -0
- package/dist/structure/gerund-phrase.d.ts.map +1 -0
- package/dist/structure/gerund-phrase.js +30 -0
- package/dist/structure/gerund-phrase.js.map +1 -0
- 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 +10 -4
- package/dist/structure/universal.d.ts.map +1 -1
- package/dist/structure/universal.js +26 -7
- 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 +23 -0
- package/dist/title-line.d.ts.map +1 -0
- package/dist/title-line.js +28 -0
- package/dist/title-line.js.map +1 -0
- package/dist/topic-clause.d.ts +7 -0
- package/dist/topic-clause.d.ts.map +1 -0
- package/dist/topic-clause.js +87 -0
- package/dist/topic-clause.js.map +1 -0
- package/dist/uncounted-particles.d.ts +18 -0
- package/dist/uncounted-particles.d.ts.map +1 -0
- package/dist/uncounted-particles.js +47 -0
- package/dist/uncounted-particles.js.map +1 -0
- package/package.json +3 -3
- package/rules/adversative-ga-repeat.yaml +1 -0
- 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/concrete-evidence-density.yaml +1 -0
- package/rules/contraction-consistency.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/duplicate-heading.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/fullwidth-alnum-consistency.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/max-sentence-length.yaml +2 -2
- 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 +3 -2
- package/rules/range-notation-consistency.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/title-length.yaml +2 -2
- package/rules/topic-predicate-distance.yaml +2 -2
- package/rules/total-mismatch.yaml +2 -2
- package/rules/translationese-density.yaml +2 -2
- package/rules/undefined-acronym.yaml +5 -2
- package/rules/undefined-term.yaml +2 -2
- package/rules/unfilled-placeholder.yaml +4 -4
- package/rules/unqualified-superlative.yaml +1 -1
- package/rules/unused-definition.yaml +2 -2
- 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 +54 -6
- package/src/detectors/acronym-known.ts +40 -0
- package/src/detectors/acronym-link.ts +75 -0
- package/src/detectors/acronym-mention.ts +44 -0
- package/src/detectors/acronym-name.ts +29 -6
- package/src/detectors/addressee-edge.ts +16 -0
- package/src/detectors/addressee-title-edge.ts +39 -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/capitalised-term.ts +26 -2
- package/src/detectors/caps-caption.ts +76 -0
- package/src/detectors/caps-phrase.ts +17 -0
- package/src/detectors/char-shape.ts +73 -14
- package/src/detectors/citation-sentence.ts +44 -0
- package/src/detectors/cited-title.ts +15 -3
- package/src/detectors/contraction-mention.ts +24 -0
- package/src/detectors/counter-edge.ts +17 -2
- package/src/detectors/dash-break.ts +45 -0
- package/src/detectors/date-any-year.ts +34 -9
- 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 +17 -9
- package/src/detectors/derived-numbers.ts +19 -4
- package/src/detectors/document-shape.ts +20 -1
- 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/duplicate-heading.ts +26 -3
- package/src/detectors/ellipsis.ts +16 -1
- package/src/detectors/email-letter.ts +142 -23
- package/src/detectors/field-label.ts +25 -0
- package/src/detectors/footnote-mismatch.ts +39 -7
- package/src/detectors/fullwidth-alnum.ts +9 -1
- package/src/detectors/graded-step.ts +52 -0
- package/src/detectors/gram-openers.ts +50 -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/heading-record-rhythm.ts +57 -0
- package/src/detectors/ime-residue.ts +4 -3
- package/src/detectors/kanji-compound-slip.ts +61 -0
- package/src/detectors/kutoten-consistency.ts +102 -14
- package/src/detectors/lexicon.ts +18 -5
- 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 +89 -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/name-variant.ts +6 -0
- 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 +18 -2
- package/src/detectors/orthographic-variant.ts +124 -25
- package/src/detectors/orthography.ts +15 -2
- package/src/detectors/oxford-comma.ts +74 -3
- 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/range-notation.ts +26 -6
- 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 +45 -8
- package/src/detectors/scaled-figure-unit.ts +103 -0
- package/src/detectors/sentence-counts.ts +64 -12
- package/src/detectors/sentence-ending.ts +12 -3
- package/src/detectors/sentence-length.ts +17 -4
- package/src/detectors/sentence-load.ts +9 -2
- package/src/detectors/signals.ts +50 -53
- 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/superlative-name.ts +10 -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 +16 -5
- package/src/detectors/undefined-term.ts +8 -0
- package/src/detectors/unknown-word.ts +1 -1
- 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 +104 -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 +64 -0
- package/src/leading-label.ts +15 -0
- package/src/lexicon-genres.ts +1 -1
- package/src/link-shape.ts +31 -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-misspelt-usual.ts +25 -0
- package/src/name-separator.ts +27 -2
- package/src/nominal-stem.ts +62 -5
- package/src/notice-header.ts +57 -0
- package/src/person-forms.ts +15 -0
- package/src/plugin.ts +5 -0
- package/src/preamble-paragraphs.ts +13 -3
- package/src/sentence-load.ts +14 -3
- package/src/spacing-code.ts +5 -1
- package/src/split-noun.ts +63 -0
- package/src/structure/attached-parts.ts +47 -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 +149 -32
- package/src/structure/gerund-phrase.ts +31 -0
- 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 +33 -9
- 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 +53 -0
- package/src/topic-clause.ts +109 -0
- package/src/uncounted-particles.ts +72 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// A work email or letter's own parts: a greeting and a closing, a subject line, and an attachment the text mentions.
|
|
2
2
|
// Pure. The words (お世話になっております, Dear, Best regards, 件名, attached) come from the language's email-greeting,
|
|
3
|
-
// email-closing, email-sentence-end, email-subject-field, attachment-mention, attachment-not-mention and attachment-line lexicons. The
|
|
3
|
+
// email-closing, email-sentence-end, memo-header-label, notice-header, email-subject-field, attachment-mention, attachment-not-mention and attachment-line lexicons. The
|
|
4
4
|
// header and the signature are masked in doc.prose; a quoted reply is someone else's words and is left out.
|
|
5
5
|
import { escapeRegExp } from "../orthography.ts";
|
|
6
6
|
import { quoteAt } from "./structure-tree.ts";
|
|
7
|
+
import { isNoticeHead, noticeWordsOf } from "../notice-header.ts";
|
|
7
8
|
import type { Detector, Finding, ProseDocument, Span } from "../plugin.ts";
|
|
8
9
|
|
|
9
10
|
/** A greeting comes before the body: past the subject, the addressee (株式会社… / 総務部 山田様) and the writer's name. */
|
|
@@ -123,31 +124,109 @@ export const greetingLineCount = (lines: readonly BodyLine[], sentenceEnds: read
|
|
|
123
124
|
return Math.max(GREETING_LINES, firstSentence + 1);
|
|
124
125
|
};
|
|
125
126
|
|
|
126
|
-
/** A
|
|
127
|
+
/** A signing line: a rule of underscores the writer signs on, alone on its line (not "Date: ____", a field to fill in). */
|
|
128
|
+
const SIGNING_LINE = /^[ \t]*_{5,}[ \t]*$/u;
|
|
129
|
+
|
|
130
|
+
/** The signer's name or title under a signing line is short; a paragraph there means the underscores were a section break. */
|
|
131
|
+
const MAX_SIGNER_LENGTH = 60;
|
|
132
|
+
|
|
133
|
+
/** Whether the next line with text is a signer's line: short, holding a letter, not a heading. */
|
|
134
|
+
const signerBelow = (lines: readonly SourceLine[], index: number): boolean => {
|
|
135
|
+
const below = nextText(lines, index);
|
|
136
|
+
const signer = withoutMarks(below);
|
|
137
|
+
return !below.startsWith("#") && [...signer].length <= MAX_SIGNER_LENGTH && LETTER.test(signer);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/** Where each signing line starts in the source: underscores alone on a line, a signer's line below, outside a quoted reply. */
|
|
141
|
+
export const signingLines = (source: string, replyQuotes: readonly Span[] = []): number[] => {
|
|
142
|
+
const quoted = insideCursor(replyQuotes);
|
|
143
|
+
const lines = linesWithOffsets(source);
|
|
144
|
+
return lines.flatMap(({ start, text }, index) => (!quoted(start) && SIGNING_LINE.test(text) && signerBelow(lines, index) ? [start] : []));
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/** Whether a signing line stands among the part's last lines or between them and the next part: the part is signed off. */
|
|
148
|
+
const signedOff = (part: readonly BodyLine[], next: BodyLine | undefined, signings: readonly number[]): boolean => {
|
|
149
|
+
const from = part.slice(-CLOSING_LINES)[0]?.start ?? Infinity;
|
|
150
|
+
return signings.some((offset) => offset >= from && offset < (next?.start ?? Infinity));
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* A missing greeting (none in the first lines, or past the letter's header) and a missing closing: none in the last lines
|
|
155
|
+
* of any part, and no part signed off on a signing line (a letter signed before an acceptance block the recipient signs).
|
|
156
|
+
*/
|
|
127
157
|
export const frameSlips = (
|
|
128
158
|
lines: readonly BodyLine[],
|
|
129
159
|
greetings: readonly string[],
|
|
130
160
|
closings: readonly string[],
|
|
131
161
|
sentenceEnds: readonly string[],
|
|
162
|
+
signings: readonly number[] = [],
|
|
132
163
|
): FrameSlip[] => {
|
|
133
164
|
const first = lines[0];
|
|
134
165
|
const last = lines.at(-1);
|
|
135
166
|
if (first === undefined || last === undefined) return [];
|
|
136
167
|
const greeted = lines.slice(0, greetingLineCount(lines, sentenceEnds)).some((line) => lineHas(line.text, greetings));
|
|
137
|
-
const
|
|
168
|
+
const parts = partsOf(lines);
|
|
169
|
+
const closed = parts.some(
|
|
170
|
+
(part, index) => part.slice(-CLOSING_LINES).some((line) => lineHas(line.text, closings)) || signedOff(part, parts[index + 1]?.[0], signings),
|
|
171
|
+
);
|
|
138
172
|
return [
|
|
139
173
|
...(greeted ? [] : [{ variant: "greeting" as const, offset: first.start }]),
|
|
140
174
|
...(closed ? [] : [{ variant: "closing" as const, offset: last.start }]),
|
|
141
175
|
];
|
|
142
176
|
};
|
|
143
177
|
|
|
178
|
+
/** The marks around a label line: a heading's #, emphasis, 【】. */
|
|
179
|
+
const LINE_MARKS = new Set("#*_【】 \t\u3000");
|
|
180
|
+
|
|
181
|
+
const withoutMarks = (line: string): string => {
|
|
182
|
+
const chars = [...line];
|
|
183
|
+
const first = chars.findIndex((char) => !LINE_MARKS.has(char));
|
|
184
|
+
return first === -1 ? "" : chars.slice(first, chars.findLastIndex((char) => !LINE_MARKS.has(char)) + 1).join("");
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const LABEL_END = /^(?:[::]|$)/u;
|
|
188
|
+
|
|
189
|
+
/** An inline HTML tag around a label (<h3> FROM: <br/>, <b>TO</b>:), dropped so the colon still follows the label. */
|
|
190
|
+
const INLINE_HTML_TAG = /<\/?[A-Za-z][A-Za-z0-9-]*(?:\s[^<>]*)?\/?>/gu;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Whether a line is a memo's header label (TO:, SUBJECT:, MEMORANDUM, 発信者:): a label as the lexicon writes it, case
|
|
194
|
+
* included, then a colon or the line's end. A memo sets its labels in capitals; a mail program writes "To:" and "Subject:".
|
|
195
|
+
*/
|
|
196
|
+
export const isMemoLabel = (line: string, labels: readonly string[]): boolean => {
|
|
197
|
+
const bare = withoutMarks(line.replace(INLINE_HTML_TAG, ""));
|
|
198
|
+
return labels.some((label) => bare.startsWith(label) && LABEL_END.test(bare.slice(label.length)));
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* A memo: one of its header labels among the source's lines before the first sentence (the first lines, when no line ends
|
|
203
|
+
* one). The source, not the body, since a block of TO: / FROM: lines is masked as an email's header. A memo takes no
|
|
204
|
+
* greeting and no closing.
|
|
205
|
+
*/
|
|
206
|
+
export const isMemo = (source: string, labels: readonly string[], sentenceEnds: readonly string[]): boolean =>
|
|
207
|
+
headLines(source, sentenceEnds).some((line) => isMemoLabel(line, labels));
|
|
208
|
+
|
|
209
|
+
/** The source's lines before the first sentence (the first lines, when no line ends one), past blank lines and a quoted reply. */
|
|
210
|
+
export const headLines = (source: string, sentenceEnds: readonly string[]): string[] => {
|
|
211
|
+
const lines = source.split("\n").filter((line) => line.trim() !== "" && !line.trimStart().startsWith(">"));
|
|
212
|
+
const firstSentence = lines.findIndex((line) => endsSentence(line, sentenceEnds));
|
|
213
|
+
return lines.slice(0, firstSentence === -1 ? HEADER_LINES : firstSentence);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/** A memo (TO: / 発信者:) or an official notice (課資2-7 / 各国税局長 殿) takes no greeting and no closing. */
|
|
217
|
+
const takesNoFrame = (doc: ProseDocument, sentenceEnds: readonly string[]): boolean =>
|
|
218
|
+
isMemo(doc.source, patternsOf(doc, "memo-header-label"), sentenceEnds) ||
|
|
219
|
+
isNoticeHead(headLines(doc.source, sentenceEnds), noticeWordsOf(doc.lexicons["notice-header"] ?? []));
|
|
220
|
+
|
|
221
|
+
const frameSlipsOf = (doc: ProseDocument): FrameSlip[] => {
|
|
222
|
+
const sentenceEnds = patternsOf(doc, "email-sentence-end");
|
|
223
|
+
if (takesNoFrame(doc, sentenceEnds)) return [];
|
|
224
|
+
const lines = bodyLines(doc.source, doc.prose ?? doc.source, doc.replyQuotes ?? []);
|
|
225
|
+
return frameSlips(lines, patternsOf(doc, "email-greeting"), patternsOf(doc, "email-closing"), sentenceEnds, signingLines(doc.source, doc.replyQuotes ?? []));
|
|
226
|
+
};
|
|
227
|
+
|
|
144
228
|
export const emailFrame: Detector = (doc): Finding[] =>
|
|
145
|
-
|
|
146
|
-
bodyLines(doc.source, doc.prose ?? doc.source, doc.replyQuotes ?? []),
|
|
147
|
-
patternsOf(doc, "email-greeting"),
|
|
148
|
-
patternsOf(doc, "email-closing"),
|
|
149
|
-
patternsOf(doc, "email-sentence-end"),
|
|
150
|
-
).map((slip) => ({
|
|
229
|
+
frameSlipsOf(doc).map((slip) => ({
|
|
151
230
|
rule: "email-greeting-closing",
|
|
152
231
|
severity: "info",
|
|
153
232
|
line: 0,
|
|
@@ -180,14 +259,53 @@ export const fieldOf = (line: string): { readonly name: string; readonly value:
|
|
|
180
259
|
};
|
|
181
260
|
};
|
|
182
261
|
|
|
262
|
+
/** The subject field's names and reply marks, and what tells the body's first line from a subject: a greeting, a sentence's end. */
|
|
263
|
+
export type SubjectVocabulary = {
|
|
264
|
+
readonly fields: readonly string[];
|
|
265
|
+
readonly replyMarks: readonly string[];
|
|
266
|
+
readonly headerFields: readonly string[];
|
|
267
|
+
readonly greetings: readonly string[];
|
|
268
|
+
readonly sentenceEnds: readonly string[];
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/** The text of the first line with text after `index`, trimmed. Scans only the blank lines between, so many empty subjects stay linear. */
|
|
272
|
+
const nextText = (lines: readonly SourceLine[], index: number): string => {
|
|
273
|
+
for (let at = index + 1; at < lines.length; at += 1) {
|
|
274
|
+
const text = lines[at]?.text.trim() ?? "";
|
|
275
|
+
if (text !== "") return text;
|
|
276
|
+
}
|
|
277
|
+
return "";
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/** A header field's line (From: Ann). Not any colon: a subject may hold one (Re: Lunch, 10:00 meeting, Q3: budget). */
|
|
281
|
+
const isHeaderField = (line: string, headerFields: readonly string[]): boolean => {
|
|
282
|
+
const name = fieldOf(line)?.name.toLowerCase();
|
|
283
|
+
return name !== undefined && headerFields.some((field) => field.toLowerCase() === name);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The value under a subject label with nothing after its colon: the next line with text, as a form that sets the label and
|
|
288
|
+
* the value in two columns reads once it is text ("SUBJECT:" over "Car park repairs"). A quoted line, a header field, a
|
|
289
|
+
* greeting or a sentence there is the body, and the subject stays empty.
|
|
290
|
+
*/
|
|
291
|
+
export const valueBelow = (lines: readonly SourceLine[], index: number, vocabulary: SubjectVocabulary): string => {
|
|
292
|
+
const text = nextText(lines, index);
|
|
293
|
+
const isBody =
|
|
294
|
+
text.startsWith(">") || isHeaderField(text, vocabulary.headerFields) || lineHas(text, vocabulary.greetings) || endsSentence(text, vocabulary.sentenceEnds);
|
|
295
|
+
return isBody ? "" : text;
|
|
296
|
+
};
|
|
297
|
+
|
|
183
298
|
/** The subject lines (Subject: …, 件名:…), outside a quoted reply, with reply and forward marks (Re:, Fwd:) taken off the value. */
|
|
184
|
-
export const subjectLines = (source: string,
|
|
185
|
-
const names = new Set(fields.map((field) => field.toLowerCase()));
|
|
299
|
+
export const subjectLines = (source: string, vocabulary: SubjectVocabulary, replyQuotes: readonly Span[]): SubjectLine[] => {
|
|
300
|
+
const names = new Set(vocabulary.fields.map((field) => field.toLowerCase()));
|
|
186
301
|
const quoted = insideCursor(replyQuotes);
|
|
187
|
-
|
|
302
|
+
const lines = linesWithOffsets(source);
|
|
303
|
+
return lines.flatMap(({ start, text }, index): SubjectLine[] => {
|
|
188
304
|
const field = fieldOf(text);
|
|
189
305
|
const inQuote = quoted(start);
|
|
190
|
-
|
|
306
|
+
if (field === undefined || inQuote || !names.has(field.name.toLowerCase())) return [];
|
|
307
|
+
const value = field.value === "" ? valueBelow(lines, index, vocabulary) : field.value;
|
|
308
|
+
return [{ start, subject: withoutReplyMarks(value, vocabulary.replyMarks) }];
|
|
191
309
|
});
|
|
192
310
|
};
|
|
193
311
|
|
|
@@ -201,7 +319,17 @@ export const withoutReplyMarks = (subject: string, marks: readonly string[]): st
|
|
|
201
319
|
};
|
|
202
320
|
|
|
203
321
|
export const emailSubject: Detector = (doc, options): Finding[] =>
|
|
204
|
-
subjectLines(
|
|
322
|
+
subjectLines(
|
|
323
|
+
doc.source,
|
|
324
|
+
{
|
|
325
|
+
fields: patternsOf(doc, "email-subject-field"),
|
|
326
|
+
replyMarks: patternsOf(doc, "email-reply-mark"),
|
|
327
|
+
headerFields: patternsOf(doc, "email-header-field"),
|
|
328
|
+
greetings: patternsOf(doc, "email-greeting"),
|
|
329
|
+
sentenceEnds: patternsOf(doc, "email-sentence-end"),
|
|
330
|
+
},
|
|
331
|
+
doc.replyQuotes ?? [],
|
|
332
|
+
).flatMap((line): Finding[] => {
|
|
205
333
|
const length = [...line.subject].length;
|
|
206
334
|
if (length > 0 && length <= options.limit) return [];
|
|
207
335
|
return [
|
|
@@ -228,15 +356,6 @@ export const firstMention = (lines: readonly BodyLine[], mentions: readonly stri
|
|
|
228
356
|
return line === undefined ? undefined : line.start + line.text.length - line.text.trimStart().length;
|
|
229
357
|
};
|
|
230
358
|
|
|
231
|
-
/** The marks around a label line: a heading's #, emphasis, 【】. */
|
|
232
|
-
const LINE_MARKS = new Set("#*_【】 \t\u3000");
|
|
233
|
-
|
|
234
|
-
const withoutMarks = (line: string): string => {
|
|
235
|
-
const chars = [...line];
|
|
236
|
-
const first = chars.findIndex((char) => !LINE_MARKS.has(char));
|
|
237
|
-
return first === -1 ? "" : chars.slice(first, chars.findLastIndex((char) => !LINE_MARKS.has(char)) + 1).join("");
|
|
238
|
-
};
|
|
239
|
-
|
|
240
359
|
/** A line that labels what is attached: the label and a colon (Attachment: quote.pdf), or the label alone (### Enclosures, 【添付資料】). */
|
|
241
360
|
const labelsAttachment = (line: string, labels: readonly string[]): boolean => {
|
|
242
361
|
const bare = withoutMarks(line).toLowerCase();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// The label of a field that opens a line ("Current project status: Ongoing", 「現在の状況:継続中」). Pure.
|
|
2
|
+
|
|
3
|
+
/** A label is a short name, not a clause: this many words at most. */
|
|
4
|
+
const MAX_LABEL_WORDS = 5;
|
|
5
|
+
const MAX_LABEL_CHARS = 40;
|
|
6
|
+
const LIST_MARKER = /^\s*(?:[-*+]|\d+[.)])\s+/u;
|
|
7
|
+
const FIELD = /^([^::\n]+)[::](?!\/\/)/u;
|
|
8
|
+
const HAS_LETTER = /\p{L}/u;
|
|
9
|
+
/** A sentence ends before the colon, so what precedes it is not a label. */
|
|
10
|
+
const SENTENCE_END = /[.!?。!?]/u;
|
|
11
|
+
|
|
12
|
+
const isLabel = (label: string): boolean =>
|
|
13
|
+
HAS_LETTER.test(label) && !SENTENCE_END.test(label) && label.length <= MAX_LABEL_CHARS && label.trim().split(/\s+/u).length <= MAX_LABEL_WORDS;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Where the value of a field on the text's first line starts, just past the colon (the value may be blank), or undefined
|
|
17
|
+
* when the first line opens with no label. Whether the label is a name and not a clause ("The following apply:") is the
|
|
18
|
+
* caller's to judge from the parts of speech.
|
|
19
|
+
*/
|
|
20
|
+
export const fieldValueStart = (text: string): number | undefined => {
|
|
21
|
+
const marker = LIST_MARKER.exec(text)?.[0] ?? "";
|
|
22
|
+
const field = FIELD.exec(text.slice(marker.length));
|
|
23
|
+
if (field?.[1] === undefined || !isLabel(field[1].replaceAll("**", ""))) return undefined;
|
|
24
|
+
return marker.length + field[0].length;
|
|
25
|
+
};
|
|
@@ -26,9 +26,12 @@ const markdownMarks = (text: string): NoteMark[] =>
|
|
|
26
26
|
return { offset: match.index, label: `[^${match.groups?.["key"] ?? ""}]`, kind: MARKDOWN, key: (match.groups?.["key"] ?? "").toLowerCase(), note };
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
/**
|
|
29
|
+
/** 番号の後ろに続くと、番号が英語の序数(1st、2nd、23rd)になるもの。 */
|
|
30
|
+
const ORDINAL_SUFFIX = "(?:[sS][tT]|[nN][dD]|[rR][dD]|[tT][hH])(?![A-Za-z])";
|
|
31
|
+
|
|
32
|
+
/** 印と一桁か二桁の番号。後ろに数字や小数が続けば年や数(※2018年度、※1.2倍)、序数が続けば英語の語(※1st Party)で、注の番号ではない。 */
|
|
30
33
|
const wordMarks = (text: string, mark: string): NoteMark[] =>
|
|
31
|
-
[...text.matchAll(new RegExp(`${escapeRegExp(mark)}(?<key>[0-90-9]{1,2})(?![0-90-9]|[..,,][0-90-9])`, "gu"))].map((match) => ({
|
|
34
|
+
[...text.matchAll(new RegExp(`${escapeRegExp(mark)}(?<key>[0-90-9]{1,2})(?![0-90-9]|[..,,][0-90-9]|${ORDINAL_SUFFIX})`, "gu"))].map((match) => ({
|
|
32
35
|
offset: match.index,
|
|
33
36
|
label: match[0],
|
|
34
37
|
kind: mark,
|
|
@@ -36,11 +39,38 @@ const wordMarks = (text: string, mark: string): NoteMark[] =>
|
|
|
36
39
|
note: NOTE_LINE_HEAD.test(lineHeadOf(text, match.index)),
|
|
37
40
|
}));
|
|
38
41
|
|
|
42
|
+
const QUOTE_LINE = /^[ \t]{0,3}>/u;
|
|
43
|
+
const QUOTE_MARKS = /^(?:[ \t]{0,3}>)+/u;
|
|
44
|
+
/** 引用の段落を終わらせる行(見出し、コード、箇条書き、脚注の定義)。これ以外の空でない行は、引用の段落の続き(CommonMark の lazy continuation)。 */
|
|
45
|
+
const BLOCK_START = /^[ \t]{0,3}(?:[#`~]|[-*+][ \t]|\d{1,9}[.)][ \t]|\[\^)/u;
|
|
46
|
+
const CODE_SPAN = /(`+)[\s\S]*?\1/gu;
|
|
47
|
+
|
|
48
|
+
const quotedLines = (source: string): string[] =>
|
|
49
|
+
source.split("\n").reduce<{ lines: string[]; open: boolean }>(
|
|
50
|
+
(state, line) => {
|
|
51
|
+
const open = QUOTE_LINE.test(line) || (state.open && line.trim() !== "" && !BLOCK_START.test(line));
|
|
52
|
+
return { lines: open ? [...state.lines, line.replace(QUOTE_MARKS, "")] : state.lines, open };
|
|
53
|
+
},
|
|
54
|
+
{ lines: [], open: false },
|
|
55
|
+
).lines;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 引用(`>`)の中の Markdown の脚注の印の番号。引用は本文から覆われるが、引用の中の印も注を指している。
|
|
59
|
+
* 引用の中の印に注が無くても言わない(引用元の注かもしれない)。注が指されているかだけに使う。
|
|
60
|
+
*/
|
|
61
|
+
export const quotedFootnoteKeys = (source: string): ReadonlySet<string> =>
|
|
62
|
+
new Set(
|
|
63
|
+
markdownMarks(quotedLines(source).join("\n").replace(CODE_SPAN, ""))
|
|
64
|
+
.filter((mark) => !mark.note)
|
|
65
|
+
.map((mark) => mark.key),
|
|
66
|
+
);
|
|
67
|
+
|
|
39
68
|
/** 一つの種類の印のうち、合わないもの。印の語(※)は、その種類の注が一つも無ければ注を別に置いた文書と読んで言わない。 */
|
|
40
|
-
const slipsOfKind = (marks: readonly NoteMark[], kind: string): NoteSlip[] => {
|
|
69
|
+
const slipsOfKind = (marks: readonly NoteMark[], kind: string, quotedKeys: ReadonlySet<string>): NoteSlip[] => {
|
|
41
70
|
const ofKind = marks.filter((mark) => mark.kind === kind);
|
|
42
71
|
const notes = new Set(ofKind.filter((mark) => mark.note).map((mark) => mark.key));
|
|
43
|
-
const
|
|
72
|
+
const quoted = kind === MARKDOWN ? [...quotedKeys] : [];
|
|
73
|
+
const referenced = new Set([...ofKind.filter((mark) => !mark.note).map((mark) => mark.key), ...quoted]);
|
|
44
74
|
if (notes.size === 0 && kind !== MARKDOWN) return [];
|
|
45
75
|
const missing = ofKind
|
|
46
76
|
.filter((mark) => !mark.note && !notes.has(mark.key))
|
|
@@ -52,15 +82,17 @@ const slipsOfKind = (marks: readonly NoteMark[], kind: string): NoteSlip[] => {
|
|
|
52
82
|
};
|
|
53
83
|
|
|
54
84
|
/** 文字列の中の、注の無い印と印の無い注。 */
|
|
55
|
-
export const noteSlips = (text: string, words: readonly string[]): NoteSlip[] => {
|
|
85
|
+
export const noteSlips = (text: string, words: readonly string[], quotedKeys: ReadonlySet<string> = new Set()): NoteSlip[] => {
|
|
56
86
|
const marks = [...markdownMarks(text), ...words.flatMap((word) => wordMarks(text, word))];
|
|
57
|
-
return [...new Set(marks.map((mark) => mark.kind))]
|
|
87
|
+
return [...new Set(marks.map((mark) => mark.kind))]
|
|
88
|
+
.flatMap((kind) => slipsOfKind(marks, kind, quotedKeys))
|
|
89
|
+
.toSorted((left, right) => left.offset - right.offset);
|
|
58
90
|
};
|
|
59
91
|
|
|
60
92
|
export const footnoteMismatch: Detector = (doc): Finding[] => {
|
|
61
93
|
const text = doc.prose ?? doc.source;
|
|
62
94
|
const words = (doc.lexicons["note-mark"] ?? []).map((entry) => entry.pattern);
|
|
63
|
-
return noteSlips(text, words).map((slip) => ({
|
|
95
|
+
return noteSlips(text, words, quotedFootnoteKeys(doc.source)).map((slip) => ({
|
|
64
96
|
rule: "",
|
|
65
97
|
severity: "warning",
|
|
66
98
|
line: 0,
|
|
@@ -91,6 +91,14 @@ const otherWidth = (run: AlnumRun): string => (run.fullwidth ? run.written.norma
|
|
|
91
91
|
|
|
92
92
|
type Located = { readonly sentence: Sentence; readonly run: AlnumRun };
|
|
93
93
|
|
|
94
|
+
const HALFWIDTH_LOWER = /[a-z]/u;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 小文字を含む半角の英字の語(AI for Science の for と Science)。英語の語は、略語を全角で書く文書(AI)でも半角で書く。
|
|
98
|
+
* 文書の英字の書き方の票には入れるが、少ないほうとしては指摘しない。
|
|
99
|
+
*/
|
|
100
|
+
const isHalfwidthEnglishWord = (run: AlnumRun): boolean => run.kind === "letters" && !run.fullwidth && HALFWIDTH_LOWER.test(run.written);
|
|
101
|
+
|
|
94
102
|
const findingOf = ({ sentence, run }: Located, count: number, of: number, limit: number): Finding => ({
|
|
95
103
|
rule: "",
|
|
96
104
|
severity: "warning",
|
|
@@ -113,6 +121,6 @@ export const fullwidthAlnum: Detector = (doc, options): Finding[] => {
|
|
|
113
121
|
return KINDS.flatMap((kind) => {
|
|
114
122
|
const ofKind = located.filter(({ run }) => run.kind === kind);
|
|
115
123
|
const odd = minorityWithin(ofKind, ({ run }) => run.fullwidth, options.limit);
|
|
116
|
-
return odd.map((entry) => findingOf(entry, odd.length, ofKind.length, options.limit));
|
|
124
|
+
return odd.filter(({ run }) => !isHalfwidthEnglishWord(run)).map((entry) => findingOf(entry, odd.length, ofKind.length, options.limit));
|
|
117
125
|
});
|
|
118
126
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Span, Token } from "../plugin.ts";
|
|
2
|
+
import { isWithinAny } from "../quoted-span.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 段階の一つとしての比較(より良い(BESTな)改善 と 良い(BETTERな)改善、より良い実装例1 と 良い実装例2)。文書が同じ語を
|
|
6
|
+
* 比べる副詞なしでも書いていれば(良い改善)、「より良い」の相手はその一段下の段で、相手は書いてある。
|
|
7
|
+
* 段は、程度を言う語の原形と、その後ろの名詞で見分ける。間の括弧の添え書き((BESTな))は飛ばす。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** 程度を言う語が語の位置 at で始まるか。bare-comparative.ts の判定を受け取る。 */
|
|
11
|
+
export type IsGradable = (tokens: readonly Token[], at: number) => boolean;
|
|
12
|
+
|
|
13
|
+
/** 形容動詞の語幹の後ろに来る語(豊かな)。この語の後ろから名詞を探す。 */
|
|
14
|
+
const ADJECTIVAL_TAIL = new Set(["な", "に", "だ", "です", "で"]);
|
|
15
|
+
const OPENING = new Set(["(", "("]);
|
|
16
|
+
const CLOSING = new Set([")", ")"]);
|
|
17
|
+
|
|
18
|
+
/** 程度を言う語(at)の後ろの最初の語の位置。形容動詞の語尾と、括弧の添え書きを飛ばす。 */
|
|
19
|
+
const afterWord = (tokens: readonly Token[], at: number): number => {
|
|
20
|
+
const next = tokens[at]?.pos === "NOUN" && ADJECTIVAL_TAIL.has(tokens[at + 1]?.surface ?? "") ? at + 2 : at + 1;
|
|
21
|
+
if (!OPENING.has(tokens[next]?.surface ?? "")) return next;
|
|
22
|
+
const close = tokens.findIndex((token, index) => index > next && CLOSING.has(token.surface));
|
|
23
|
+
return close === -1 ? next : close + 1;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** 段の名前: 程度を言う語の原形と、後ろの名詞。後ろが名詞でなければ段ではない。 */
|
|
27
|
+
export const stepKeyAt = (tokens: readonly Token[], at: number): string | undefined => {
|
|
28
|
+
const [word, noun] = [tokens[at], tokens[afterWord(tokens, at)]];
|
|
29
|
+
if (word === undefined || noun === undefined || noun.pos !== "NOUN") return undefined;
|
|
30
|
+
return `${word.lemma ?? word.surface}|${noun.surface}`;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** 文の語と、引いたもの(鉤括弧の中)の範囲。引いた語(「良い対応」という表現)は文書が書いた段ではない。 */
|
|
34
|
+
export type StepSentence = { readonly tokens: readonly Token[]; readonly quoted: readonly Span[] };
|
|
35
|
+
|
|
36
|
+
/** 文書が比べる副詞(markers)なしで書いた、程度を言う語と名詞の段の名前。 */
|
|
37
|
+
export const plainStepKeys = (sentences: readonly StepSentence[], markers: ReadonlySet<string>, isGradable: IsGradable): ReadonlySet<string> =>
|
|
38
|
+
new Set(
|
|
39
|
+
sentences.flatMap(({ tokens, quoted }) =>
|
|
40
|
+
tokens.flatMap((token, at) => {
|
|
41
|
+
if (markers.has(tokens[at - 1]?.surface ?? "") || isWithinAny(quoted, token.span) || !isGradable(tokens, at)) return [];
|
|
42
|
+
const key = stepKeyAt(tokens, at);
|
|
43
|
+
return key === undefined ? [] : [key];
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
/** 比べた語(word)が、文書が一段下を書いた段の一つか。 */
|
|
49
|
+
export const isNamedStep = (tokens: readonly Token[], word: Token, steps: ReadonlySet<string>): boolean => {
|
|
50
|
+
const key = stepKeyAt(tokens, tokens.indexOf(word));
|
|
51
|
+
return key !== undefined && steps.has(key);
|
|
52
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Section, Sentence } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
/** A list item or a table row on a line after the sentence: what the sentence leads into. */
|
|
4
|
+
const LIST_OR_TABLE_NEXT = /^[ \t]*\n\s*(?:[-*+]\s|\d{1,3}[.)]\s|\|)/u;
|
|
5
|
+
|
|
6
|
+
/** How far past the sentence to look for that line: blank lines between, never the rest of a long document. */
|
|
7
|
+
const LOOKAHEAD = 200;
|
|
8
|
+
|
|
9
|
+
/** 番号の印((1)、(2)、3.、第4、⑤)。数の点の後ろに数字が続けば小数(3.14)。 */
|
|
10
|
+
const ITEM_LABEL = String.raw`(?:[((][\d0-9一二三四五六七八九十]{1,3}[))]|[\d0-9]{1,3}[..))](?![\d0-9])|第[\d0-9一二三四五六七八九十]{1,3}|[①-⑳])`;
|
|
11
|
+
/** 箇条書きの印(- 、1. )。 */
|
|
12
|
+
const LIST_MARKER = String.raw`(?:[-*+]|\d{1,3}[.)])[ \t]+`;
|
|
13
|
+
const OPENS_WITH_LABEL = new RegExp(String.raw`^\s*${ITEM_LABEL}`, "u");
|
|
14
|
+
const SENTENCE_END = /[。..!?!?]\s*$/u;
|
|
15
|
+
/** 行の頭か、箇条書きの印の後ろ。 */
|
|
16
|
+
const LINE_START = new RegExp(String.raw`(?:^|\n)[ \t]*(?:${LIST_MARKER})?$`, "u");
|
|
17
|
+
const LINE_START_REACH = 8;
|
|
18
|
+
/**
|
|
19
|
+
* 行の終わりの後ろの、次の空でない行が本文であること。次の行も番号の印で始まれば、番号を振った項目の並び((1)申請書を出す、
|
|
20
|
+
* (2)…)で、見出しではない。
|
|
21
|
+
*/
|
|
22
|
+
const FOLLOWED_BY_BODY = new RegExp(String.raw`^[ \t]*\n\s*(?!(?:${LIST_MARKER})?${ITEM_LABEL})\S`, "u");
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 行の頭の番号の印で始まり、句点で終わらず、一行を占め、後ろに本文が続く文(「(1)芸術の振興に係る規定に関する改正(第8条関係)」)。項目ごとの見出しで、
|
|
26
|
+
* 並べた見出しは同じ枠(…に係る規定に関する改正)を繰り返す。言い回しがどれもこの文にだけ出るなら見出しのひな形。
|
|
27
|
+
*/
|
|
28
|
+
export const itemTitles = (sentences: readonly Sentence[], source: string): Sentence[] =>
|
|
29
|
+
sentences.filter(
|
|
30
|
+
(sentence) =>
|
|
31
|
+
OPENS_WITH_LABEL.test(sentence.text) &&
|
|
32
|
+
!SENTENCE_END.test(sentence.text) &&
|
|
33
|
+
LINE_START.test(source.slice(Math.max(0, sentence.span.start - LINE_START_REACH), sentence.span.start)) &&
|
|
34
|
+
FOLLOWED_BY_BODY.test(source.slice(sentence.span.end, sentence.span.end + LOOKAHEAD)),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 見出しのある節の最初の文のうち、次の行から箇条書きか表が続くもの。参照用の文書は、節ごとに同じ書き出しで一覧を導く
|
|
39
|
+
* (「…によると以下の制約である。」の後ろに制約の箇条書き)。言い回しがどれもこの文にだけ出るなら節のひな形で、書き手が言い直したのではない。
|
|
40
|
+
* 後ろが本文の文なら、節ごとの口癖(正直なところ、…)と見分けられないので入れない。導入部(見出しの前)は節ではない。
|
|
41
|
+
*/
|
|
42
|
+
const leadsIntoList = (section: Pick<Section, "depth" | "sentences">, source: string): Sentence[] => {
|
|
43
|
+
const first = section.sentences[0];
|
|
44
|
+
if (section.depth === 0 || first === undefined) return [];
|
|
45
|
+
return LIST_OR_TABLE_NEXT.test(source.slice(first.span.end, first.span.end + LOOKAHEAD)) ? [first] : [];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** 節のひな形の文: 一覧を導く節の最初の文と、項目ごとの見出し(itemTitles)。 */
|
|
49
|
+
export const sectionOpeners = (sections: readonly Pick<Section, "depth" | "sentences">[], source: string): Set<Sentence> =>
|
|
50
|
+
new Set(sections.flatMap((section) => [...leadsIntoList(section, source), ...itemTitles(section.sentences, source)]));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { softBreaks } from "../soft-break.ts";
|
|
2
|
-
import type { LengthUnit, Span } from "../plugin.ts";
|
|
2
|
+
import type { LengthUnit, ProseDocument, Sentence, Span } from "../plugin.ts";
|
|
3
3
|
|
|
4
4
|
/** 数えるために詰めた文と、詰めた文の各文字が元の文のどこにあったか。 */
|
|
5
5
|
export type Compacted = { readonly text: string; readonly offsets: readonly number[] };
|
|
@@ -50,3 +50,12 @@ export const placeOf = (source: Compacted, gram: string): Span | undefined => {
|
|
|
50
50
|
const at = source.text.indexOf(gram);
|
|
51
51
|
return at === -1 ? undefined : placeAt(source, { start: at, end: at + gram.length });
|
|
52
52
|
};
|
|
53
|
+
|
|
54
|
+
/** 詰めた文の index 番目の文字が、リンクの文字か。 */
|
|
55
|
+
export const linkedIn = (doc: ProseDocument, sentence: Sentence, source: Compacted): ((index: number) => boolean) => {
|
|
56
|
+
const links = doc.links.filter((link) => link.start < sentence.span.end && sentence.span.start < link.end);
|
|
57
|
+
return (index) => {
|
|
58
|
+
const at = sentence.span.start + (source.offsets[index] ?? -1);
|
|
59
|
+
return links.some((link) => link.start <= at && at < link.end);
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -9,12 +9,28 @@ const NOUNS = new Set(["NOUN", "PROPN", "ADJ"]);
|
|
|
9
9
|
/** 中身を持たない語。名前の前後に付いても、名前の繰り返しを言い回しに変えない。 */
|
|
10
10
|
const FUNCTION_POS = new Set(["ADP", "DET", "CCONJ", "SCONJ", "PART", "PUNCT", "SYM", "X"]);
|
|
11
11
|
|
|
12
|
+
/** 形式名詞(とき、こと)。動詞が節を名詞にしているだけで、用語は作らない(承認又は断るとき)。 */
|
|
13
|
+
const isDependentNoun = (token: Token | undefined): boolean => token?.features?.["NounType"] === "Dependent";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 日本語で、名詞と接続詞(又は、及び)のすぐ後ろで名詞を飾る動詞(行為又は怠る事実)は、名詞を並べた一つの用語の中にあり、述語ではない。
|
|
17
|
+
* 用語は言い換えられないので、繰り返して当たり前。名詞に「する」が付いた動詞(承認又は拒否する)は、行為を並べた述語と見分けられないので外さない。
|
|
18
|
+
*/
|
|
19
|
+
const inCoordinatedNoun = (tokens: readonly Token[], index: number, unit: LengthUnit): boolean =>
|
|
20
|
+
unit === "char" &&
|
|
21
|
+
tokens[index]?.pos === "VERB" &&
|
|
22
|
+
tokens[index]?.features?.["VerbType"] !== "Light" &&
|
|
23
|
+
tokens[index - 1]?.pos === "CCONJ" &&
|
|
24
|
+
NOUNS.has(tokens[index - 2]?.pos ?? "") &&
|
|
25
|
+
NOUNS.has(tokens[index + 1]?.pos ?? "") &&
|
|
26
|
+
!isDependentNoun(tokens[index + 1]);
|
|
27
|
+
|
|
12
28
|
/**
|
|
13
29
|
* 英語で名詞のすぐ前の動詞は、名詞を飾る語(形容詞を挟んでも同じ)(the upcoming fiscal year、the Disclosing Party、the borrow checker)で、
|
|
14
|
-
*
|
|
30
|
+
* 述語ではない。日本語の名詞の前の動詞(〜にあるコンポーネント)は言い回しの一部になるので、接続詞の後ろの用語の中(inCoordinatedNoun)だけを外す。
|
|
15
31
|
*/
|
|
16
32
|
const modifiesNoun = (tokens: readonly Token[], index: number, unit: LengthUnit): boolean =>
|
|
17
|
-
unit === "word" && tokens[index]?.pos === "VERB" && NOUNS.has(tokens[index + 1]?.pos ?? "");
|
|
33
|
+
(unit === "word" && tokens[index]?.pos === "VERB" && NOUNS.has(tokens[index + 1]?.pos ?? "")) || inCoordinatedNoun(tokens, index, unit);
|
|
18
34
|
|
|
19
35
|
/** 英語で大文字の名前の一部になった動詞(Procedures Guide、the Location Object)も、述語ではない。 */
|
|
20
36
|
const namePartAt = (tokens: readonly Token[], index: number, unit: LengthUnit): boolean => unit === "word" && isNamePart(tokens, index);
|
|
@@ -40,10 +56,34 @@ const onlyNamesBeside = (tokens: readonly Token[], predicate: number, window: Sp
|
|
|
40
56
|
return names.length > 0 && rest.every((index) => FUNCTION_POS.has(tokens[index]?.pos ?? ""));
|
|
41
57
|
};
|
|
42
58
|
|
|
59
|
+
const COMPOUND_POS = new Set(["NOUN", "PROPN", "ADJ", "NUM"]);
|
|
60
|
+
/** 動詞の前の名詞句がこれだけの語を持てば、動詞はその名詞句の最後の名詞。the contract says は 1 語なので述語のまま。 */
|
|
61
|
+
const MIN_COMPOUND_WORDS = 2;
|
|
62
|
+
|
|
63
|
+
/** 語形を変えていない動詞(rate)か -ing 形(subcontracting)。名詞と同じ形で、名詞の読み違いになりうる。described や says は述語の形。 */
|
|
64
|
+
const isNounShaped = (token: Token): boolean =>
|
|
65
|
+
token.features?.["VerbForm"] === "Ger" || (token.lemma !== undefined && token.lemma === token.surface.toLowerCase());
|
|
66
|
+
|
|
67
|
+
/** 動詞の目的語の始まり(models generate the text の the)。後ろにこれが続く動詞は述語。 */
|
|
68
|
+
const OBJECT_START = new Set(["DET", "PRON", "NUM"]);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 英語で、窓の最後の名詞の形の動詞の前が名詞と形容詞だけ(先頭の冠詞は許す)で、後ろに目的語が続かなければ、動詞は名詞の続きの
|
|
72
|
+
* 読み違い(the federal funds rate の rate、small business subcontracting)。窓の中に機能語があれば言い回し(your contract says)。
|
|
73
|
+
*/
|
|
74
|
+
const endsNounCompound = (tokens: readonly Token[], index: number, window: Span, unit: LengthUnit): boolean => {
|
|
75
|
+
const verb = tokens[index];
|
|
76
|
+
if (unit !== "word" || verb?.pos !== "VERB" || !isNounShaped(verb) || OBJECT_START.has(tokens[index + 1]?.pos ?? "")) return false;
|
|
77
|
+
const touched = tokens.flatMap((token, at) => (overlaps(token, window) ? [at] : []));
|
|
78
|
+
if (touched.at(-1) !== index) return false;
|
|
79
|
+
const before = touched.slice(0, -1).filter((at, order) => !(order === 0 && tokens[at]?.pos === "DET"));
|
|
80
|
+
return before.length >= MIN_COMPOUND_WORDS && before.every((at) => COMPOUND_POS.has(tokens[at]?.pos ?? ""));
|
|
81
|
+
};
|
|
82
|
+
|
|
43
83
|
const countsAsPredicate = (tokens: readonly Token[], index: number, window: Span, unit: LengthUnit): boolean => {
|
|
44
84
|
const token = tokens[index];
|
|
45
85
|
if (token === undefined || !PREDICATE_POS.has(token.pos) || !overlaps(token, window)) return false;
|
|
46
|
-
if (modifiesNoun(tokens, index, unit) || namePartAt(tokens, index, unit)) return false;
|
|
86
|
+
if (modifiesNoun(tokens, index, unit) || namePartAt(tokens, index, unit) || endsNounCompound(tokens, index, window, unit)) return false;
|
|
47
87
|
return !isCut(token, window) || !onlyNamesBeside(tokens, index, window, unit);
|
|
48
88
|
};
|
|
49
89
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { lengthOf, proseText } from "../measure.ts";
|
|
2
2
|
import { newContentMorphemes } from "./content-morphemes.ts";
|
|
3
3
|
import { echoedHeadingUnits, trigrams } from "./heading-overlap.ts";
|
|
4
|
+
import { fieldValueStart } from "./field-label.ts";
|
|
4
5
|
import { formValueTokens, isFormBlock } from "./form-line.ts";
|
|
5
6
|
import { titleTokens } from "../heading-label.ts";
|
|
6
7
|
import { announcerWords, makesClaim } from "./heading-claim.ts";
|
|
7
8
|
import { handsOver } from "./lead-in.ts";
|
|
8
9
|
import { holdsLink, namesLocation } from "./location-pointer.ts";
|
|
9
10
|
import { withoutQuotedVariants } from "./quoted-variant.ts";
|
|
10
|
-
import
|
|
11
|
+
import { namesHeadingSubject } from "./subject-name-line.ts";
|
|
12
|
+
import type { Detector, Finding, LengthUnit, ProseDocument, Section, Sentence } from "../plugin.ts";
|
|
11
13
|
|
|
12
14
|
/** 見出しが短すぎると、偶然の一致で 100% になる。これ未満の見出しは見ない。 */
|
|
13
15
|
const MIN_GRAMS = 4;
|
|
@@ -105,8 +107,33 @@ const opensForm = (section: Section): boolean => {
|
|
|
105
107
|
return newContentMorphemes(heading, formValueTokens(first.text, first.span.start, first.tokens)) > 0;
|
|
106
108
|
};
|
|
107
109
|
|
|
110
|
+
/** 最初の行が、見出しが扱うものの名前だけ(リンクや添付の札、見出しの名の一覧)。見出しを言い直す文ではない。 */
|
|
111
|
+
const namesSubject = (doc: ProseDocument, section: Section): boolean => {
|
|
112
|
+
const first = section.firstSentence;
|
|
113
|
+
if (first?.tokens === undefined || section.headingTokens === undefined) return false;
|
|
114
|
+
const heading = titleTokens(section.heading, measuredHeading(section), section.headingTokens);
|
|
115
|
+
const announcing = announcerWords(doc.lexicons["heading-announcer"] ?? []).announcing;
|
|
116
|
+
return namesHeadingSubject(measuredHeading(section), heading, first.text, first.span.start, first.tokens, announcing);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/** 述語の品詞。項目名にあれば、コロンの前は名前ではなく文の頭(The following expenses require receipts:)。 */
|
|
120
|
+
const PREDICATE_POS: ReadonlySet<string> = new Set(["VERB", "AUX"]);
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 行頭の項目名(Current project status: Ongoing)を除いた文。報告の書式が見出しの語で項目を立てるのは書式で、書き手が言ったのは値。
|
|
124
|
+
* 品詞が読めなければ、項目名かどうか決められないので除かない。
|
|
125
|
+
*/
|
|
126
|
+
const withoutFieldLabel = (sentence: Sentence): string => {
|
|
127
|
+
const valueStart = fieldValueStart(sentence.text);
|
|
128
|
+
if (valueStart === undefined || sentence.tokens === undefined) return sentence.text;
|
|
129
|
+
const labelEnd = sentence.span.start + valueStart;
|
|
130
|
+
const isClause = sentence.tokens.some((token) => token.span.start < labelEnd && PREDICATE_POS.has(token.pos));
|
|
131
|
+
return isClause ? sentence.text : sentence.text.slice(valueStart);
|
|
132
|
+
};
|
|
133
|
+
|
|
108
134
|
/** 見出しとの重なりを測る文。用語集や表記の手引きは見出しの語の別の書き方を引用する(Not “datacentre”)ので、それは数えない。 */
|
|
109
|
-
const echoedText = (section: Section): string =>
|
|
135
|
+
const echoedText = (section: Section): string =>
|
|
136
|
+
section.firstSentence === undefined ? "" : withoutQuotedVariants(withoutFieldLabel(section.firstSentence), measuredHeading(section));
|
|
110
137
|
|
|
111
138
|
export const headingEcho: Detector = (doc, options): Finding[] => {
|
|
112
139
|
const leadIns = (doc.lexicons["lead-in"] ?? []).map((entry) => entry.pattern);
|
|
@@ -117,7 +144,8 @@ export const headingEcho: Detector = (doc, options): Finding[] => {
|
|
|
117
144
|
!leadsIn(doc, section, leadIns) &&
|
|
118
145
|
!pointsElsewhere(doc, section) &&
|
|
119
146
|
!statesFigure(section.heading, section.firstSentence?.text ?? "") &&
|
|
120
|
-
!opensForm(section)
|
|
147
|
+
!opensForm(section) &&
|
|
148
|
+
!namesSubject(doc, section),
|
|
121
149
|
)
|
|
122
150
|
.map((section) => ({ section, overlap: Math.round(containment(trigrams(measuredHeading(section)), trigrams(echoedText(section))) * 100) }))
|
|
123
151
|
.filter(({ overlap }) => overlap >= options.limit)
|