chaffjs 0.34.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/capitals-passage.d.ts +3 -0
- package/dist/capitals-passage.d.ts.map +1 -0
- package/dist/capitals-passage.js +26 -0
- package/dist/capitals-passage.js.map +1 -0
- 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/coined-hyphen-name.d.ts +13 -0
- package/dist/coined-hyphen-name.d.ts.map +1 -0
- package/dist/coined-hyphen-name.js +21 -0
- package/dist/coined-hyphen-name.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/company-names.d.ts +6 -1
- package/dist/company-names.d.ts.map +1 -1
- package/dist/company-names.js +22 -3
- package/dist/company-names.js.map +1 -1
- 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 +5 -1
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +32 -4
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-definition.d.ts +13 -0
- package/dist/detectors/acronym-definition.d.ts.map +1 -0
- package/dist/detectors/acronym-definition.js +90 -0
- package/dist/detectors/acronym-definition.js.map +1 -0
- 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-lone.d.ts +13 -0
- package/dist/detectors/acronym-lone.d.ts.map +1 -0
- package/dist/detectors/acronym-lone.js +22 -0
- package/dist/detectors/acronym-lone.js.map +1 -0
- package/dist/detectors/acronym-name.d.ts +62 -0
- package/dist/detectors/acronym-name.d.ts.map +1 -0
- package/dist/detectors/acronym-name.js +94 -0
- package/dist/detectors/acronym-name.js.map +1 -0
- 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/capitalised-term.d.ts +14 -2
- package/dist/detectors/capitalised-term.d.ts.map +1 -1
- package/dist/detectors/capitalised-term.js +115 -4
- package/dist/detectors/capitalised-term.js.map +1 -1
- package/dist/detectors/caps-caption.d.ts +12 -0
- package/dist/detectors/caps-caption.d.ts.map +1 -0
- package/dist/detectors/caps-caption.js +89 -0
- package/dist/detectors/caps-caption.js.map +1 -0
- 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 +72 -30
- 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/clause-shape.d.ts +1 -1
- package/dist/detectors/clause-shape.d.ts.map +1 -1
- package/dist/detectors/clause-shape.js +9 -4
- package/dist/detectors/clause-shape.js.map +1 -1
- package/dist/detectors/concrete-evidence.d.ts +13 -1
- package/dist/detectors/concrete-evidence.d.ts.map +1 -1
- package/dist/detectors/concrete-evidence.js +59 -0
- package/dist/detectors/concrete-evidence.js.map +1 -1
- package/dist/detectors/contraction-minority.d.ts +11 -0
- package/dist/detectors/contraction-minority.d.ts.map +1 -0
- package/dist/detectors/contraction-minority.js +10 -0
- package/dist/detectors/contraction-minority.js.map +1 -0
- package/dist/detectors/counter-edge.d.ts +7 -1
- package/dist/detectors/counter-edge.d.ts.map +1 -1
- package/dist/detectors/counter-edge.js +40 -2
- package/dist/detectors/counter-edge.js.map +1 -1
- package/dist/detectors/date-any-year.d.ts +12 -5
- package/dist/detectors/date-any-year.d.ts.map +1 -1
- package/dist/detectors/date-any-year.js +69 -12
- 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-heading-year.d.ts +18 -0
- package/dist/detectors/date-heading-year.d.ts.map +1 -0
- package/dist/detectors/date-heading-year.js +38 -0
- package/dist/detectors/date-heading-year.js.map +1 -0
- package/dist/detectors/date-year.d.ts +19 -3
- package/dist/detectors/date-year.d.ts.map +1 -1
- package/dist/detectors/date-year.js +69 -8
- 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 +59 -12
- 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/due-date.d.ts.map +1 -1
- package/dist/detectors/due-date.js +6 -0
- package/dist/detectors/due-date.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/en-shape.d.ts.map +1 -1
- package/dist/detectors/en-shape.js +5 -1
- package/dist/detectors/en-shape.js.map +1 -1
- package/dist/detectors/fact-consistency.d.ts.map +1 -1
- package/dist/detectors/fact-consistency.js +3 -2
- package/dist/detectors/fact-consistency.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-passages.d.ts +11 -0
- package/dist/detectors/gram-passages.d.ts.map +1 -0
- package/dist/detectors/gram-passages.js +26 -0
- package/dist/detectors/gram-passages.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-end-mark.d.ts +8 -3
- package/dist/detectors/heading-end-mark.d.ts.map +1 -1
- package/dist/detectors/heading-end-mark.js +18 -8
- package/dist/detectors/heading-end-mark.js.map +1 -1
- package/dist/detectors/heading-names.d.ts +7 -0
- package/dist/detectors/heading-names.d.ts.map +1 -0
- package/dist/detectors/heading-names.js +24 -0
- package/dist/detectors/heading-names.js.map +1 -0
- package/dist/detectors/heading-numbering.d.ts.map +1 -1
- package/dist/detectors/heading-numbering.js +7 -2
- package/dist/detectors/heading-numbering.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/inch-mark.d.ts +10 -0
- package/dist/detectors/inch-mark.d.ts.map +1 -0
- package/dist/detectors/inch-mark.js +48 -0
- package/dist/detectors/inch-mark.js.map +1 -0
- 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 +0 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +37 -25
- 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 +15 -5
- package/dist/detectors/mark-shape.d.ts.map +1 -1
- package/dist/detectors/mark-shape.js +64 -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-apart.d.ts +27 -0
- package/dist/detectors/name-variant-apart.d.ts.map +1 -0
- package/dist/detectors/name-variant-apart.js +51 -0
- package/dist/detectors/name-variant-apart.js.map +1 -0
- package/dist/detectors/name-variant.d.ts.map +1 -1
- package/dist/detectors/name-variant.js +18 -11
- 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/numeral-word.d.ts +15 -0
- package/dist/detectors/numeral-word.d.ts.map +1 -0
- package/dist/detectors/numeral-word.js +26 -0
- package/dist/detectors/numeral-word.js.map +1 -0
- 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 +18 -0
- package/dist/detectors/organisation-run.d.ts.map +1 -0
- package/dist/detectors/organisation-run.js +80 -0
- package/dist/detectors/organisation-run.js.map +1 -0
- package/dist/detectors/orthographic-variant.d.ts.map +1 -1
- package/dist/detectors/orthographic-variant.js +65 -21
- 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/outline-label.d.ts +14 -0
- package/dist/detectors/outline-label.d.ts.map +1 -0
- package/dist/detectors/outline-label.js +32 -0
- package/dist/detectors/outline-label.js.map +1 -0
- 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/page-marker.d.ts +6 -0
- package/dist/detectors/page-marker.d.ts.map +1 -0
- package/dist/detectors/page-marker.js +19 -0
- package/dist/detectors/page-marker.js.map +1 -0
- package/dist/detectors/parallel-definition.d.ts +16 -0
- package/dist/detectors/parallel-definition.d.ts.map +1 -0
- package/dist/detectors/parallel-definition.js +51 -0
- package/dist/detectors/parallel-definition.js.map +1 -0
- 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/reference-text.d.ts.map +1 -1
- package/dist/detectors/reference-text.js +1 -0
- package/dist/detectors/reference-text.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/registry/unfilled-placeholder.d.ts.map +1 -1
- package/dist/detectors/registry/unfilled-placeholder.js +2 -2
- package/dist/detectors/registry/unfilled-placeholder.js.map +1 -1
- package/dist/detectors/registry/vague-density.js +1 -1
- package/dist/detectors/registry/vague-density.js.map +1 -1
- package/dist/detectors/request-owner.d.ts +6 -2
- package/dist/detectors/request-owner.d.ts.map +1 -1
- package/dist/detectors/request-owner.js +57 -7
- package/dist/detectors/request-owner.js.map +1 -1
- package/dist/detectors/requirement-smell.d.ts.map +1 -1
- package/dist/detectors/requirement-smell.js +39 -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 +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-length.d.ts.map +1 -1
- package/dist/detectors/sentence-length.js +24 -16
- 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/sentence-rhythm.d.ts.map +1 -1
- package/dist/detectors/sentence-rhythm.js +6 -3
- package/dist/detectors/sentence-rhythm.js.map +1 -1
- package/dist/detectors/series-label.d.ts +2 -1
- package/dist/detectors/series-label.d.ts.map +1 -1
- package/dist/detectors/series-label.js +10 -4
- package/dist/detectors/series-label.js.map +1 -1
- package/dist/detectors/signals.d.ts +4 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +91 -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 +21 -19
- 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/template-sections.d.ts +14 -0
- package/dist/detectors/template-sections.d.ts.map +1 -0
- package/dist/detectors/template-sections.js +25 -0
- package/dist/detectors/template-sections.js.map +1 -0
- 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 +23 -0
- package/dist/detectors/titled-run.d.ts.map +1 -0
- package/dist/detectors/titled-run.js +39 -0
- package/dist/detectors/titled-run.js.map +1 -0
- 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/unbalanced-bracket.d.ts.map +1 -1
- package/dist/detectors/unbalanced-bracket.js +4 -0
- package/dist/detectors/unbalanced-bracket.js.map +1 -1
- package/dist/detectors/undefined-term.d.ts.map +1 -1
- package/dist/detectors/undefined-term.js +8 -0
- package/dist/detectors/undefined-term.js.map +1 -1
- package/dist/detectors/unfilled-placeholder.d.ts +4 -0
- package/dist/detectors/unfilled-placeholder.d.ts.map +1 -0
- package/dist/detectors/unfilled-placeholder.js +9 -0
- package/dist/detectors/unfilled-placeholder.js.map +1 -0
- package/dist/detectors/vague-density.d.ts +8 -0
- package/dist/detectors/vague-density.d.ts.map +1 -0
- package/dist/detectors/vague-density.js +65 -0
- package/dist/detectors/vague-density.js.map +1 -0
- 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/facts/fact-scope.d.ts +10 -1
- package/dist/facts/fact-scope.d.ts.map +1 -1
- package/dist/facts/fact-scope.js +34 -3
- package/dist/facts/fact-scope.js.map +1 -1
- package/dist/facts/table-facts.d.ts +12 -2
- package/dist/facts/table-facts.d.ts.map +1 -1
- package/dist/facts/table-facts.js +22 -4
- package/dist/facts/table-facts.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/grade-api.d.ts +9 -2
- package/dist/grade-api.d.ts.map +1 -1
- package/dist/grade-api.js +31 -15
- package/dist/grade-api.js.map +1 -1
- package/dist/heading-numbering.d.ts +5 -2
- package/dist/heading-numbering.d.ts.map +1 -1
- package/dist/heading-numbering.js +27 -6
- package/dist/heading-numbering.js.map +1 -1
- 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-end-letter.d.ts +5 -0
- package/dist/name-end-letter.d.ts.map +1 -1
- package/dist/name-end-letter.js +8 -0
- package/dist/name-end-letter.js.map +1 -1
- package/dist/name-given-before.d.ts +15 -0
- package/dist/name-given-before.d.ts.map +1 -0
- package/dist/name-given-before.js +30 -0
- package/dist/name-given-before.js.map +1 -0
- package/dist/name-separator.d.ts +2 -2
- package/dist/name-separator.d.ts.map +1 -1
- package/dist/name-separator.js +79 -5
- package/dist/name-separator.js.map +1 -1
- package/dist/name-variants.d.ts +3 -1
- package/dist/name-variants.d.ts.map +1 -1
- package/dist/name-variants.js +8 -7
- package/dist/name-variants.js.map +1 -1
- package/dist/name-word-order.d.ts +9 -5
- package/dist/name-word-order.d.ts.map +1 -1
- package/dist/name-word-order.js +47 -15
- package/dist/name-word-order.js.map +1 -1
- package/dist/nominal-stem.d.ts +26 -0
- package/dist/nominal-stem.d.ts.map +1 -0
- package/dist/nominal-stem.js +70 -0
- package/dist/nominal-stem.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 +6 -2
- 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 +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/cited-document-section.d.ts +7 -0
- package/dist/structure/cited-document-section.d.ts.map +1 -0
- package/dist/structure/cited-document-section.js +33 -0
- package/dist/structure/cited-document-section.js.map +1 -0
- 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/html-text-blocks.d.ts +8 -0
- package/dist/structure/html-text-blocks.d.ts.map +1 -0
- package/dist/structure/html-text-blocks.js +47 -0
- package/dist/structure/html-text-blocks.js.map +1 -0
- package/dist/structure/issues.d.ts +5 -2
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +24 -6
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/labelled-date-order.d.ts +4 -1
- package/dist/structure/labelled-date-order.d.ts.map +1 -1
- package/dist/structure/labelled-date-order.js +2 -2
- package/dist/structure/labelled-date-order.js.map +1 -1
- package/dist/structure/labelled-order.d.ts +3 -0
- package/dist/structure/labelled-order.d.ts.map +1 -1
- package/dist/structure/labelled-order.js +8 -3
- package/dist/structure/labelled-order.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/list-numbering.d.ts +20 -4
- package/dist/structure/list-numbering.d.ts.map +1 -1
- package/dist/structure/list-numbering.js +65 -9
- package/dist/structure/list-numbering.js.map +1 -1
- package/dist/structure/listed-paragraph.d.ts +16 -0
- package/dist/structure/listed-paragraph.d.ts.map +1 -0
- package/dist/structure/listed-paragraph.js +37 -0
- package/dist/structure/listed-paragraph.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 +5 -2
- package/dist/structure/numbering.d.ts.map +1 -1
- package/dist/structure/numbering.js +49 -12
- 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/reference-text.d.ts +9 -1
- package/dist/structure/reference-text.d.ts.map +1 -1
- package/dist/structure/reference-text.js +21 -3
- package/dist/structure/reference-text.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/section-names.d.ts +12 -0
- package/dist/structure/section-names.d.ts.map +1 -0
- package/dist/structure/section-names.js +26 -0
- package/dist/structure/section-names.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/versioned-label.d.ts +16 -0
- package/dist/structure/versioned-label.d.ts.map +1 -0
- package/dist/structure/versioned-label.js +48 -0
- package/dist/structure/versioned-label.js.map +1 -0
- package/dist/structure/written-headings.d.ts +31 -0
- package/dist/structure/written-headings.d.ts.map +1 -0
- package/dist/structure/written-headings.js +119 -0
- package/dist/structure/written-headings.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 +12 -0
- package/dist/structure/written-resolve.d.ts.map +1 -0
- package/dist/structure/written-resolve.js +55 -0
- package/dist/structure/written-resolve.js.map +1 -0
- 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/concrete-evidence-density.yaml +2 -2
- package/rules/contraction-consistency.yaml +13 -13
- package/rules/dangling-figure-reference.yaml +2 -2
- package/rules/dangling-reference.yaml +2 -2
- package/rules/date-without-year.yaml +10 -2
- package/rules/defined-name-repeated.yaml +2 -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/fact-conflict.yaml +2 -2
- package/rules/footnote-mismatch.yaml +2 -2
- package/rules/heading-echo.yaml +2 -2
- package/rules/heading-end-punctuation-mix.yaml +2 -2
- package/rules/heading-numbering-mix.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 +4 -4
- package/rules/list-item-form-mix.yaml +2 -2
- package/rules/max-kanji-continuous.yaml +7 -3
- package/rules/max-sentence-length.yaml +3 -2
- package/rules/modal-conflict.yaml +1 -0
- package/rules/nado-closed-list.yaml +2 -2
- package/rules/name-variant.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/reference-title-mismatch.yaml +2 -2
- package/rules/repeated-sentence-ending.yaml +3 -2
- package/rules/request-without-deadline.yaml +2 -2
- package/rules/requirement-smell.yaml +3 -3
- package/rules/sentence-rhythm.yaml +2 -2
- package/rules/table-header-variant.yaml +2 -2
- package/rules/teki-overuse.yaml +3 -2
- package/rules/title-case-consistency.yaml +2 -2
- package/rules/total-mismatch.yaml +2 -2
- package/rules/translationese-density.yaml +2 -2
- package/rules/unbalanced-bracket.yaml +2 -2
- package/rules/undefined-acronym.yaml +15 -4
- package/rules/undefined-term.yaml +2 -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/capitals-passage.ts +31 -0
- package/src/chronology-rows.ts +86 -0
- package/src/coined-hyphen-name.ts +27 -0
- package/src/company-name-run.ts +37 -0
- package/src/company-names.ts +24 -3
- 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 +34 -6
- package/src/detectors/acronym-definition.ts +123 -0
- 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-lone.ts +26 -0
- package/src/detectors/acronym-name.ts +140 -0
- 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/capitalised-term.ts +154 -4
- package/src/detectors/caps-caption.ts +103 -0
- package/src/detectors/caps-phrase.ts +17 -0
- package/src/detectors/char-shape.ts +99 -26
- package/src/detectors/cited-title.ts +15 -3
- package/src/detectors/clause-shape.ts +14 -4
- package/src/detectors/concrete-evidence.ts +77 -1
- package/src/detectors/contraction-minority.ts +11 -0
- package/src/detectors/counter-edge.ts +40 -2
- package/src/detectors/date-any-year.ts +79 -12
- package/src/detectors/date-format.ts +2 -1
- package/src/detectors/date-heading-year.ts +55 -0
- package/src/detectors/date-year.ts +107 -14
- package/src/detectors/deadline-unit.ts +40 -0
- package/src/detectors/defined-term-form.ts +58 -17
- 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/due-date.ts +10 -1
- package/src/detectors/ellipsis.ts +16 -1
- package/src/detectors/email-letter.ts +97 -21
- package/src/detectors/en-shape.ts +5 -1
- package/src/detectors/fact-consistency.ts +3 -2
- 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-passages.ts +36 -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-end-mark.ts +23 -10
- package/src/detectors/heading-names.ts +31 -0
- package/src/detectors/heading-numbering.ts +7 -2
- package/src/detectors/ime-residue.ts +4 -3
- package/src/detectors/inch-mark.ts +49 -0
- package/src/detectors/kanji-compound-slip.ts +61 -0
- package/src/detectors/kutoten-consistency.ts +93 -14
- package/src/detectors/lexicon.ts +44 -24
- 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 +70 -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-apart.ts +63 -0
- package/src/detectors/name-variant.ts +30 -12
- 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/numeral-word.ts +33 -0
- 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 +97 -0
- package/src/detectors/orthographic-variant.ts +103 -27
- package/src/detectors/orthography.ts +10 -1
- package/src/detectors/outline-label.ts +48 -0
- package/src/detectors/oxford-comma.ts +40 -1
- package/src/detectors/page-marker.ts +26 -0
- package/src/detectors/parallel-definition.ts +64 -0
- 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/reference-text.ts +1 -0
- package/src/detectors/registry/kanji-compound-slip.ts +4 -0
- package/src/detectors/registry/phrase-in-use.ts +4 -0
- package/src/detectors/registry/unfilled-placeholder.ts +2 -2
- package/src/detectors/registry/vague-density.ts +1 -1
- package/src/detectors/request-owner.ts +71 -8
- package/src/detectors/requirement-smell.ts +53 -7
- 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-length.ts +14 -6
- package/src/detectors/sentence-load.ts +9 -2
- package/src/detectors/sentence-rhythm.ts +8 -4
- package/src/detectors/series-label.ts +13 -4
- package/src/detectors/signals.ts +105 -55
- package/src/detectors/structure-tree.ts +22 -20
- 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/template-sections.ts +37 -0
- package/src/detectors/term-mention-sentence.ts +31 -0
- package/src/detectors/titled-run.ts +48 -0
- package/src/detectors/token-shape.ts +14 -5
- package/src/detectors/unbalanced-bracket.ts +3 -0
- package/src/detectors/undefined-term.ts +8 -0
- package/src/detectors/unfilled-placeholder.ts +10 -0
- package/src/detectors/vague-density.ts +84 -0
- package/src/document-paragraphs.ts +27 -0
- package/src/document.ts +3 -23
- package/src/facts/fact-scope.ts +53 -4
- package/src/facts/table-facts.ts +43 -6
- package/src/figure-references.ts +7 -2
- package/src/format-template.ts +15 -0
- package/src/formula-brackets.ts +36 -0
- package/src/grade-api.ts +38 -16
- package/src/heading-numbering.ts +35 -8
- 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-end-letter.ts +9 -0
- package/src/name-given-before.ts +40 -0
- package/src/name-separator.ts +91 -5
- package/src/name-variants.ts +21 -11
- package/src/name-word-order.ts +62 -17
- package/src/nominal-stem.ts +93 -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 +7 -2
- 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/cited-document-section.ts +42 -0
- 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/html-text-blocks.ts +45 -0
- package/src/structure/issues.ts +26 -7
- package/src/structure/labelled-date-order.ts +5 -2
- package/src/structure/labelled-order.ts +12 -3
- package/src/structure/list-lead-in.ts +94 -0
- package/src/structure/list-numbering.ts +100 -11
- package/src/structure/listed-paragraph.ts +45 -0
- package/src/structure/modal-conflict.ts +42 -7
- package/src/structure/negated-act.ts +49 -0
- package/src/structure/numbering.ts +70 -26
- package/src/structure/prose-total.ts +20 -6
- package/src/structure/reference-text.ts +25 -3
- package/src/structure/repeated-number.ts +110 -0
- package/src/structure/rounded-amount.ts +55 -0
- package/src/structure/section-names.ts +32 -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/versioned-label.ts +52 -0
- package/src/structure/written-headings.ts +137 -0
- package/src/structure/written-list-path.ts +46 -0
- package/src/structure/written-resolve.ts +64 -0
- package/src/title-line.ts +52 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Lexicon, Sentence, Token } from "../plugin.ts";
|
|
2
|
+
|
|
3
|
+
// 並べた定義: どの文も違う語を、同じ型(〜を指します、〜といいます)で定義する。同じ文末が続くのは型をそろえたからで、
|
|
4
|
+
// 書き手の調子の繰り返しではない。
|
|
5
|
+
|
|
6
|
+
const TRAILING_POS: ReadonlySet<string> = new Set(["PUNCT", "SYM"]);
|
|
7
|
+
const TAIL_POS: ReadonlySet<string> = new Set(["AUX", "PART"]);
|
|
8
|
+
|
|
9
|
+
export type DefinitionWords = { readonly frames: ReadonlySet<string>; readonly topics: ReadonlySet<string> };
|
|
10
|
+
|
|
11
|
+
const patternsOf = (lexicon: Lexicon | undefined, group: string): ReadonlySet<string> =>
|
|
12
|
+
new Set((lexicon ?? []).filter((entry) => entry.group === group).map((entry) => entry.pattern));
|
|
13
|
+
|
|
14
|
+
export const definitionWordsOf = (lexicon: Lexicon | undefined): DefinitionWords => ({
|
|
15
|
+
frames: patternsOf(lexicon, "frame"),
|
|
16
|
+
topics: patternsOf(lexicon, "topic"),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const surfacesOf = (tokens: readonly Token[]): string => tokens.map((token) => token.surface).join("");
|
|
20
|
+
|
|
21
|
+
/** 述語(文末の助動詞の前の語)の位置。助動詞で終わらない文には無い。 */
|
|
22
|
+
const predicateAt = (tokens: readonly Token[]): number | undefined => {
|
|
23
|
+
const last = tokens.findLastIndex((token) => !TRAILING_POS.has(token.pos));
|
|
24
|
+
const head = tokens.slice(0, last + 1).findLastIndex((token) => !TAIL_POS.has(token.pos));
|
|
25
|
+
return head > 0 && head < last ? head : undefined;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const PARTICLE_POS = "ADP";
|
|
29
|
+
const TERM_POS: ReadonlySet<string> = new Set(["NOUN", "PROPN"]);
|
|
30
|
+
|
|
31
|
+
/** 定義の文が定義する語と、その型(を指す)。 */
|
|
32
|
+
export type Definition = { readonly term: string; readonly frame: string };
|
|
33
|
+
|
|
34
|
+
/** topic の助詞(は)より前。無ければ、述語の前の助詞の直前の名詞(〜を台風といいます の 台風)。 */
|
|
35
|
+
const termOf = (tokens: readonly Token[], head: number, words: DefinitionWords): string => {
|
|
36
|
+
const topic = tokens.slice(0, head - 1).findIndex((token) => token.pos === PARTICLE_POS && words.topics.has(token.surface));
|
|
37
|
+
if (topic > 0) return surfacesOf(tokens.slice(0, topic));
|
|
38
|
+
const before = tokens[head - 2];
|
|
39
|
+
return before !== undefined && TERM_POS.has(before.pos) ? before.surface : "";
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** その文が定義する語と型。型の文(を指す、という)でなければ無い。 */
|
|
43
|
+
export const definitionOf = (sentence: Sentence, words: DefinitionWords): Definition | undefined => {
|
|
44
|
+
const tokens = (sentence.tokens ?? []).filter((token) => token.surface.trim() !== "");
|
|
45
|
+
const head = predicateAt(tokens);
|
|
46
|
+
const particle = head === undefined ? undefined : tokens[head - 1];
|
|
47
|
+
const predicate = head === undefined ? undefined : tokens[head];
|
|
48
|
+
if (head === undefined || particle === undefined || predicate === undefined) return undefined;
|
|
49
|
+
const frame = `${particle.surface}${predicate.lemma ?? predicate.surface}`;
|
|
50
|
+
if (!words.frames.has(frame)) return undefined;
|
|
51
|
+
const term = termOf(tokens, head, words);
|
|
52
|
+
return term === "" ? undefined : { term, frame };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const isDefinition = (definition: Definition | undefined): definition is Definition => definition !== undefined;
|
|
56
|
+
|
|
57
|
+
/** どの文も同じ型の定義で、定義する語がみな違う。 */
|
|
58
|
+
export const isParallelDefinition = (sentences: readonly Sentence[], words: DefinitionWords): boolean => {
|
|
59
|
+
const definitions = sentences.map((sentence) => definitionOf(sentence, words));
|
|
60
|
+
if (!definitions.every(isDefinition)) return false;
|
|
61
|
+
const terms = new Set(definitions.map((definition) => definition.term));
|
|
62
|
+
const frames = new Set(definitions.map((definition) => definition.frame));
|
|
63
|
+
return terms.size === definitions.length && frames.size === 1;
|
|
64
|
+
};
|
|
@@ -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
|
+
});
|
|
@@ -17,6 +17,7 @@ const inputOf = (doc: ProseDocument): ReferenceInput | undefined => {
|
|
|
17
17
|
asides: patternsOf(doc, "reference-aside"),
|
|
18
18
|
topicLinks: patternsOf(doc, "reference-topic-link"),
|
|
19
19
|
vagueTopics: patternsOf(doc, "reference-topic-vague"),
|
|
20
|
+
listJoints: patternsOf(doc, "reference-list-joint"),
|
|
20
21
|
},
|
|
21
22
|
};
|
|
22
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Detector } from "../../plugin.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { unfilledPlaceholderOutsideTemplates } from "../unfilled-placeholder.ts";
|
|
3
3
|
|
|
4
|
-
export const detector: Detector =
|
|
4
|
+
export const detector: Detector = unfilledPlaceholderOutsideTemplates;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// A request for an action (「資料をご確認ください」 "Please send the report.") with no deadline and no person or role,
|
|
2
2
|
// in its own sentence or the next. The words come from the language's lexicons; the code only combines them.
|
|
3
|
-
import type { Detector, Finding, Lexicon, ProseDocument, Sentence, Span, StructureNode } from "../plugin.ts";
|
|
3
|
+
import type { Detector, Finding, Lexicon, ProseDocument, Section, Sentence, Span, StructureNode } from "../plugin.ts";
|
|
4
4
|
import { proseText } from "../measure.ts";
|
|
5
5
|
import { comparableWords } from "./lexicon-match.ts";
|
|
6
6
|
import { escapeRegExp } from "../orthography.ts";
|
|
@@ -15,6 +15,9 @@ export const REQUEST_LEXICONS = {
|
|
|
15
15
|
owner: "request-owner",
|
|
16
16
|
pointer: "request-pointer",
|
|
17
17
|
offer: "request-offer",
|
|
18
|
+
timing: "request-timing",
|
|
19
|
+
invitation: "request-invitation",
|
|
20
|
+
contact: "request-contact",
|
|
18
21
|
} as const;
|
|
19
22
|
|
|
20
23
|
type Words = Readonly<Record<keyof typeof REQUEST_LEXICONS, readonly string[]>>;
|
|
@@ -32,6 +35,9 @@ const wordsOf = (doc: ProseDocument): Words => ({
|
|
|
32
35
|
owner: patternsOf(doc.lexicons[REQUEST_LEXICONS.owner]),
|
|
33
36
|
pointer: patternsOf(doc.lexicons[REQUEST_LEXICONS.pointer]),
|
|
34
37
|
offer: patternsOf(doc.lexicons[REQUEST_LEXICONS.offer]),
|
|
38
|
+
timing: patternsOf(doc.lexicons[REQUEST_LEXICONS.timing]),
|
|
39
|
+
invitation: patternsOf(doc.lexicons[REQUEST_LEXICONS.invitation]),
|
|
40
|
+
contact: patternsOf(doc.lexicons[REQUEST_LEXICONS.contact]),
|
|
35
41
|
});
|
|
36
42
|
|
|
37
43
|
/** How far apart, in characters, the action word and the request ending may be: the action must be what is requested. */
|
|
@@ -57,16 +63,43 @@ export const containsAny = (text: string, patterns: readonly string[]): boolean
|
|
|
57
63
|
|
|
58
64
|
const gapBetween = (left: Place, right: Place): number => Math.max(left.start - right.end, right.start - left.end, 0);
|
|
59
65
|
|
|
66
|
+
/** An invitation verb right at the request ending (「ご相談ください」 "please come"): the reader may come, nothing is to be finished. */
|
|
67
|
+
const INVITATION_REACH = 1;
|
|
68
|
+
|
|
69
|
+
/** A comma or semicolon between an action and the invitation: the action is a request of its own (「申請書を提出し、会場へお越しください」). */
|
|
70
|
+
const CLAUSE_BREAK = /[、,,;;]/u;
|
|
71
|
+
|
|
72
|
+
/** A label and a colon (「電話:」 "Fax:"): a contact line, whose request is how to reach the writer. */
|
|
73
|
+
const LABEL_COLON = /^\s*[::]/u;
|
|
74
|
+
|
|
75
|
+
/** Whether the action is what the invitation is for (「登録をしにお越しください」「入力用にご使用ください」), not a request beside it. */
|
|
76
|
+
const invitedTo = (comparable: string, action: Place, invitation: Place): boolean => {
|
|
77
|
+
const [left, right] = action.start <= invitation.start ? [action, invitation] : [invitation, action];
|
|
78
|
+
return !CLAUSE_BREAK.test(comparable.slice(left.end, right.start));
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const holdsContactLine = (text: string, words: Words): boolean => {
|
|
82
|
+
const comparable = comparableWords(text);
|
|
83
|
+
return placesOf(comparable, words.contact).some((label) => LABEL_COLON.test(comparable.slice(label.end)));
|
|
84
|
+
};
|
|
85
|
+
|
|
60
86
|
/**
|
|
61
87
|
* A request for an action: an action word next to a request ending (「確認してください」「please send」), not a condition
|
|
62
88
|
* (「ご不明な点があれば…ください」 is an offer), not an open offer to take the reader's questions (「ご質問はメールでお送りください」),
|
|
63
|
-
*
|
|
89
|
+
* not a pointer to where to read more (「詳細は資料をご確認ください」), not what an invitation is for (「登録をしにお越しください」),
|
|
90
|
+
* and not the way to reach the writer on a contact line (「ファックス番号:… 送信後、ご連絡ください」).
|
|
64
91
|
* The action has to be close to the ending, or a noun like 検討会 or 履修登録 earlier in the sentence would make one.
|
|
65
92
|
*/
|
|
66
93
|
export const isRequest = (text: string, words: Words): boolean => {
|
|
94
|
+
const comparable = comparableWords(text);
|
|
67
95
|
const endings = placesOf(text, words.ending);
|
|
68
|
-
const
|
|
69
|
-
|
|
96
|
+
const invitations = placesOf(text, words.invitation).filter((invitation) => endings.some((ending) => gapBetween(invitation, ending) <= INVITATION_REACH));
|
|
97
|
+
const asked = placesOf(text, words.action).some(
|
|
98
|
+
(action) =>
|
|
99
|
+
endings.some((ending) => gapBetween(action, ending) <= ACTION_REACH) && !invitations.some((invitation) => invitedTo(comparable, action, invitation)),
|
|
100
|
+
);
|
|
101
|
+
if (!asked || holdsContactLine(text, words)) return false;
|
|
102
|
+
return ![words.condition, words.offer, words.pointer].some((patterns) => containsAny(text, patterns));
|
|
70
103
|
};
|
|
71
104
|
|
|
72
105
|
const NAMED = new Set(["PROPN"]);
|
|
@@ -105,13 +138,16 @@ const holdsWord = (sentence: Sentence, patterns: readonly string[]): boolean =>
|
|
|
105
138
|
return placesOf(comparable, patterns).some((place) => bounds === undefined || (bounds.starts.has(place.start) && bounds.ends.has(place.end)));
|
|
106
139
|
};
|
|
107
140
|
|
|
108
|
-
/**
|
|
141
|
+
/**
|
|
142
|
+
* Whether a sentence says when or who (a role). The request itself may also say when relative to something else
|
|
143
|
+
* (「提出いただく前に」 "before you submit") or name the person; the next sentence's timing or name may be about something else.
|
|
144
|
+
*/
|
|
109
145
|
const saysWhenOrWho = (sentence: Sentence, words: Words, dates: readonly Span[], isRequestItself: boolean): boolean =>
|
|
110
146
|
datedWithin(dates, sentence.span) ||
|
|
111
147
|
CLOCK.test(proseText(sentence)) ||
|
|
112
148
|
holdsWord(sentence, words.deadline) ||
|
|
113
149
|
holdsWord(sentence, words.owner) ||
|
|
114
|
-
(isRequestItself && namesSomeone(sentence));
|
|
150
|
+
(isRequestItself && (holdsWord(sentence, words.timing) || namesSomeone(sentence)));
|
|
115
151
|
|
|
116
152
|
/** A paragraph break or a new list item between two sentences: the second does not continue the first. */
|
|
117
153
|
const BREAK = /\n[^\S\n]*\n|\n[^\S\n]*(?:[-*+]|\d+[.)])[^\S\n]/u;
|
|
@@ -122,14 +158,41 @@ const continues = (source: string, sentence: Sentence, next: Sentence | undefine
|
|
|
122
158
|
const dateSpans = (tree: StructureNode | undefined): Span[] =>
|
|
123
159
|
tree === undefined ? [] : inDocumentOrder(tree).flatMap((node) => (node.kind === "date" ? [node.span] : []));
|
|
124
160
|
|
|
125
|
-
/**
|
|
161
|
+
/** A section's heading, read as a sentence so the deadline words match it the same way. */
|
|
162
|
+
const headingOf = (section: Section): Sentence => ({
|
|
163
|
+
span: section.span,
|
|
164
|
+
text: section.heading,
|
|
165
|
+
...(section.headingTokens === undefined ? {} : { tokens: section.headingTokens }),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/** The headings an offset sits under: its own section's, then each enclosing one's up to the title. */
|
|
169
|
+
const enclosingHeadings = (sections: readonly Section[], offset: number): Sentence[] => {
|
|
170
|
+
const own = sections.findLastIndex((section) => section.span.start <= offset);
|
|
171
|
+
const chain = sections
|
|
172
|
+
.slice(0, own + 1)
|
|
173
|
+
.reduceRight<{ depth: number; found: Section[] }>(
|
|
174
|
+
(walk, section) => (section.depth < walk.depth ? { depth: section.depth, found: [...walk.found, section] } : walk),
|
|
175
|
+
{ depth: Number.POSITIVE_INFINITY, found: [] },
|
|
176
|
+
).found;
|
|
177
|
+
return chain.filter((section) => section.depth > 0 && section.heading.trim() !== "").map(headingOf);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A notice whose heading names its deadline (「見積提出期限:10月26日」「【随時受付】」): every request under it inherits it.
|
|
182
|
+
* A date alone in a heading is more often the day the notice was issued or the event it announces, so it is not enough.
|
|
183
|
+
*/
|
|
184
|
+
const underDeadlineHeading = (sections: readonly Section[], sentence: Sentence, words: Words): boolean =>
|
|
185
|
+
enclosingHeadings(sections, sentence.span.start).some((heading) => holdsWord(heading, words.deadline));
|
|
186
|
+
|
|
187
|
+
/** The request sentences with neither a deadline nor a person in them, in the sentence after (same paragraph or item), or in a heading above. */
|
|
126
188
|
export const ownerlessRequests = (doc: ProseDocument): Sentence[] => {
|
|
127
189
|
const words = wordsOf(doc);
|
|
128
190
|
const dates = dateSpans(doc.structure);
|
|
129
191
|
return doc.sentences.filter((sentence, index) => {
|
|
130
192
|
if (!isRequest(proseText(sentence), words) || saysWhenOrWho(sentence, words, dates, true)) return false;
|
|
131
193
|
const next = doc.sentences[index + 1];
|
|
132
|
-
|
|
194
|
+
if (continues(doc.source, sentence, next) && saysWhenOrWho(next, words, dates, false)) return false;
|
|
195
|
+
return !underDeadlineHeading(doc.sections, sentence, words);
|
|
133
196
|
});
|
|
134
197
|
};
|
|
135
198
|
|
|
@@ -1,16 +1,28 @@
|
|
|
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";
|
|
8
|
+
import { statesConcrete } from "./vague-deadline.ts";
|
|
4
9
|
|
|
5
10
|
// Requirements smells (Femmer et al. 2017; Berry et al. 2003; ISO/IEC/IEEE 29148): a loophole, an open-ended list and
|
|
6
11
|
// "and/or", in a sentence that states a requirement. What makes a sentence a requirement, and each smell's words, come
|
|
7
12
|
// from the language's lexicons; this file knows neither language.
|
|
8
13
|
|
|
9
14
|
const OPEN_END = "requirement-open-end";
|
|
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";
|
|
20
|
+
const TIME = "time";
|
|
21
|
+
const CONCRETE_DEADLINE = "concrete-deadline";
|
|
10
22
|
|
|
11
23
|
/** Each smell: the lexicon of its words, and the finding's variant (the rule's messages). */
|
|
12
24
|
const SMELLS = [
|
|
13
|
-
{ lexicon:
|
|
25
|
+
{ lexicon: LOOPHOLE, variant: "loophole" },
|
|
14
26
|
{ lexicon: OPEN_END, variant: "open-end" },
|
|
15
27
|
{ lexicon: "requirement-either", variant: "either" },
|
|
16
28
|
] as const;
|
|
@@ -43,20 +55,54 @@ const findingOf = (sentence: Sentence, entry: LexiconEntry, variant: string, off
|
|
|
43
55
|
values: { matched: entry.pattern, offset },
|
|
44
56
|
});
|
|
45
57
|
|
|
46
|
-
/**
|
|
58
|
+
/** A loophole about when (group: time) that the sentence bounds with a stated limit ("as soon as possible, but no later than two days after"). */
|
|
59
|
+
const boundedInTime = (doc: ProseDocument, sentence: Sentence, entry: LexiconEntry, lexicon: string): boolean =>
|
|
60
|
+
lexicon === LOOPHOLE &&
|
|
61
|
+
entry.group === TIME &&
|
|
62
|
+
statesConcrete(
|
|
63
|
+
{ start: sentence.span.start, text: sentence.text },
|
|
64
|
+
(doc.lexicons[CONCRETE_DEADLINE] ?? []).map((limit) => limit.pattern),
|
|
65
|
+
);
|
|
66
|
+
|
|
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
|
+
*/
|
|
47
76
|
const smellAt = (doc: ProseDocument, sentence: Sentence, entry: LexiconEntry, lexicon: string, names: () => OpenEndNames): number | undefined => {
|
|
48
|
-
if (!entryIn(sentence, entry)) return undefined;
|
|
77
|
+
if (!entryIn(sentence, entry) || boundedInTime(doc, sentence, entry, lexicon)) return undefined;
|
|
49
78
|
const tokenized = sentence.tokens !== undefined && (entry.tokens?.length ?? 0) > 0;
|
|
50
|
-
|
|
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));
|
|
51
83
|
};
|
|
52
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
|
+
|
|
53
98
|
/** The first word of each smell in one requirement sentence: one finding per smell, not per word. */
|
|
54
99
|
const smellsIn = (doc: ProseDocument, sentence: Sentence, names: () => OpenEndNames): Finding[] =>
|
|
55
100
|
SMELLS.flatMap(({ lexicon, variant }) =>
|
|
56
|
-
(doc
|
|
101
|
+
smellWords(doc, lexicon)
|
|
57
102
|
.flatMap((entry) => {
|
|
58
103
|
const offset = smellAt(doc, sentence, entry, lexicon, names);
|
|
59
|
-
|
|
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)];
|
|
60
106
|
})
|
|
61
107
|
.slice(0, 1),
|
|
62
108
|
);
|
|
@@ -67,6 +113,6 @@ export const requirementSmell: Detector = (doc): Finding[] => {
|
|
|
67
113
|
const statements = (doc.lexicons[STATEMENTS] ?? []).map((entry) => entry.pattern);
|
|
68
114
|
// Read once, and only when a requirement has an open-end word to tell apart from a name.
|
|
69
115
|
const cache: { names?: OpenEndNames } = {};
|
|
70
|
-
const names = (): OpenEndNames => (cache.names ??= openEndNames(doc, doc
|
|
116
|
+
const names = (): OpenEndNames => (cache.names ??= openEndNames(doc, smellWords(doc, OPEN_END), statements));
|
|
71
117
|
return doc.sentences.filter((sentence) => isRequirement(sentence, markers, notMarkers)).flatMap((sentence) => smellsIn(doc, sentence, names));
|
|
72
118
|
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// number-without-unit, in prose: a number written with a word of scale and no unit (83,494百万, 83 million) where the
|
|
2
|
+
// document writes that word of scale with one unit many times and without one nowhere else (83,494百万円, $83 million).
|
|
3
|
+
// Pure; the words of scale, the currency marks and the joiners come from the language's lexicons.
|
|
4
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
5
|
+
import type { CurrencyForm } from "./currency-notation.ts";
|
|
6
|
+
import { AMOUNT } from "./currency-notation.ts";
|
|
7
|
+
|
|
8
|
+
/** A number with a word of scale: from its currency mark (if any) to the end of its unit, and the unit ("" when bare). */
|
|
9
|
+
export type ScaledFigure = { readonly offset: number; readonly end: number; readonly written: string; readonly scale: string; readonly unit: string };
|
|
10
|
+
|
|
11
|
+
export type ScaleWords = { readonly scales: readonly string[]; readonly forms: readonly CurrencyForm[]; readonly joiners: readonly string[] };
|
|
12
|
+
|
|
13
|
+
export type ScaleGap = { readonly figure: ScaledFigure; readonly unit: string };
|
|
14
|
+
|
|
15
|
+
/** How many numbers must carry the unit before the one without it reads as a slip rather than a way of writing. */
|
|
16
|
+
export const MIN_WITH_UNIT = 5;
|
|
17
|
+
|
|
18
|
+
const LATIN = /[A-Za-z]/u;
|
|
19
|
+
const longestFirst = (words: readonly string[]): string[] => words.toSorted((left, right) => right.length - left.length);
|
|
20
|
+
|
|
21
|
+
const figurePattern = (scales: readonly string[]): RegExp => {
|
|
22
|
+
const scale = longestFirst(scales)
|
|
23
|
+
.map((word) => `${escapeRegExp(word)}${LATIN.test(word) ? "(?![A-Za-z])" : ""}`)
|
|
24
|
+
.join("|");
|
|
25
|
+
return new RegExp(`(?<![\\w.,,.0-9])${AMOUNT}\\s?(?:${scale})`, "gu");
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const formMatches = (text: string, pattern: string, side: "before" | "after"): boolean => {
|
|
29
|
+
if (side === "before") return text.endsWith(pattern) && !(LATIN.test(pattern.charAt(0)) && LATIN.test(text.charAt(text.length - pattern.length - 1)));
|
|
30
|
+
return text.startsWith(pattern) && !(LATIN.test(pattern.at(-1) ?? "") && LATIN.test(text.charAt(pattern.length)));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** The currency mark written before a number ($, US$, ¥), with the one space it may have. */
|
|
34
|
+
const markBefore = (text: string, offset: number, forms: readonly CurrencyForm[]): string => {
|
|
35
|
+
const before = text.slice(Math.max(0, offset - 8), offset);
|
|
36
|
+
const spaced = before.endsWith(" ") ? before.slice(0, -1) : before;
|
|
37
|
+
const form = longestFirst(forms.filter((entry) => entry.position === "before").map((entry) => entry.pattern)).find((pattern) =>
|
|
38
|
+
formMatches(spaced, pattern, "before"),
|
|
39
|
+
);
|
|
40
|
+
if (form === undefined) return "";
|
|
41
|
+
return spaced === before ? form : `${form} `;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** What follows a word of scale as its unit: a currency word (円, dollars), else the next word ("people", 人, ドル); "" when none. */
|
|
45
|
+
const unitAfter = (rest: string, forms: readonly CurrencyForm[]): string => {
|
|
46
|
+
const spaced = rest.startsWith(" ") ? rest.slice(1) : rest;
|
|
47
|
+
const form = longestFirst(forms.filter((entry) => entry.position === "after").map((entry) => entry.pattern)).find((pattern) =>
|
|
48
|
+
formMatches(spaced, pattern, "after"),
|
|
49
|
+
);
|
|
50
|
+
const word = form ?? /^(?:[A-Za-z]+|[\p{Script=Katakana}ー]+|\p{Script=Han})/u.exec(spaced)?.[0];
|
|
51
|
+
if (word === undefined) return "";
|
|
52
|
+
return spaced === rest ? word : ` ${word}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const figureAt = (text: string, match: RegExpExecArray, words: ScaleWords): ScaledFigure | undefined => {
|
|
56
|
+
const end = match.index + match[0].length;
|
|
57
|
+
const rest = text.slice(end);
|
|
58
|
+
if (/^\s?[0-90-9]/u.test(rest)) return undefined;
|
|
59
|
+
const mark = markBefore(text, match.index, words.forms);
|
|
60
|
+
const after = mark === "" ? unitAfter(rest, words.forms) : "";
|
|
61
|
+
const scale = longestFirst(words.scales).find((word) => match[0].endsWith(word)) ?? "";
|
|
62
|
+
return { offset: match.index - mark.length, end: end + after.length, written: match[0], scale, unit: (mark || after).trim() };
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** Every number with a word of scale in a text, in order; one that runs on into another number (1億2,000万円) is left out. */
|
|
66
|
+
export const scaledFiguresIn = (text: string, words: ScaleWords): ScaledFigure[] =>
|
|
67
|
+
words.scales.length === 0 ? [] : [...text.matchAll(figurePattern(words.scales))].flatMap((match) => figureAt(text, match, words) ?? []);
|
|
68
|
+
|
|
69
|
+
/** A bare number joined to its neighbour by a range or list word, so that one unit serves both (100百万〜200百万円). */
|
|
70
|
+
const sharesUnit = (text: string, left: ScaledFigure | undefined, right: ScaledFigure | undefined, joiners: readonly string[]): boolean => {
|
|
71
|
+
if (left === undefined || right === undefined) return false;
|
|
72
|
+
const gap = text.slice(left.end, right.offset).trim();
|
|
73
|
+
return gap === "" || joiners.includes(gap) || joiners.includes(gap.toLowerCase());
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const gapOfScale = (text: string, figures: readonly ScaledFigure[], joiners: readonly string[]): ScaleGap[] => {
|
|
77
|
+
const bare = figures.filter(
|
|
78
|
+
(figure, index) => figure.unit === "" && !sharesUnit(text, figure, figures[index + 1], joiners) && !sharesUnit(text, figures[index - 1], figure, joiners),
|
|
79
|
+
);
|
|
80
|
+
const withUnit = figures.filter((figure) => figure.unit !== "");
|
|
81
|
+
const units = new Set(withUnit.map((figure) => figure.unit));
|
|
82
|
+
const [unit] = units;
|
|
83
|
+
const [figure] = bare;
|
|
84
|
+
if (figure === undefined || unit === undefined || bare.length !== 1 || units.size !== 1 || withUnit.length < MIN_WITH_UNIT) return [];
|
|
85
|
+
return [{ figure, unit }];
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The one bare number of a word of scale whose other numbers all carry one unit, at least MIN_WITH_UNIT times. Two bare
|
|
90
|
+
* numbers, or two units (百万円 and 百万株), and the document is read as writing the word that way on purpose.
|
|
91
|
+
*/
|
|
92
|
+
export const scaleGaps = (text: string, figures: readonly ScaledFigure[], joiners: readonly string[]): ScaleGap[] => {
|
|
93
|
+
const scales = [...new Set(figures.map((figure) => figure.scale))];
|
|
94
|
+
return scales
|
|
95
|
+
.flatMap((scale) =>
|
|
96
|
+
gapOfScale(
|
|
97
|
+
text,
|
|
98
|
+
figures.filter((figure) => figure.scale === scale),
|
|
99
|
+
joiners,
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
.toSorted((left, right) => left.figure.offset - right.figure.offset);
|
|
103
|
+
};
|