chaffjs 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +12 -0
- package/README.md +15 -0
- package/dist/announced-count.d.ts +2 -0
- package/dist/announced-count.d.ts.map +1 -1
- package/dist/announced-count.js +29 -7
- package/dist/announced-count.js.map +1 -1
- package/dist/chronology-rows.d.ts +9 -0
- package/dist/chronology-rows.d.ts.map +1 -0
- package/dist/chronology-rows.js +79 -0
- package/dist/chronology-rows.js.map +1 -0
- package/dist/company-name-run.d.ts +8 -0
- package/dist/company-name-run.d.ts.map +1 -0
- package/dist/company-name-run.js +30 -0
- package/dist/company-name-run.js.map +1 -0
- package/dist/compound-head.d.ts +7 -0
- package/dist/compound-head.d.ts.map +1 -0
- package/dist/compound-head.js +19 -0
- package/dist/compound-head.js.map +1 -0
- package/dist/date-format.d.ts +8 -3
- package/dist/date-format.d.ts.map +1 -1
- package/dist/date-format.js +36 -3
- package/dist/date-format.js.map +1 -1
- package/dist/derived/count-per-period.d.ts +23 -0
- package/dist/derived/count-per-period.d.ts.map +1 -0
- package/dist/derived/count-per-period.js +14 -0
- package/dist/derived/count-per-period.js.map +1 -0
- package/dist/detectors/acronym-context.d.ts +4 -0
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +29 -1
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-expansion.d.ts +5 -1
- package/dist/detectors/acronym-expansion.d.ts.map +1 -1
- package/dist/detectors/acronym-expansion.js +35 -3
- package/dist/detectors/acronym-expansion.js.map +1 -1
- package/dist/detectors/acronym-known.d.ts +19 -0
- package/dist/detectors/acronym-known.d.ts.map +1 -0
- package/dist/detectors/acronym-known.js +32 -0
- package/dist/detectors/acronym-known.js.map +1 -0
- package/dist/detectors/acronym-link.d.ts +14 -0
- package/dist/detectors/acronym-link.d.ts.map +1 -0
- package/dist/detectors/acronym-link.js +32 -0
- package/dist/detectors/acronym-link.js.map +1 -0
- package/dist/detectors/acronym-name.d.ts +8 -1
- package/dist/detectors/acronym-name.d.ts.map +1 -1
- package/dist/detectors/acronym-name.js +23 -4
- package/dist/detectors/acronym-name.js.map +1 -1
- package/dist/detectors/addressee-edge.d.ts +13 -0
- package/dist/detectors/addressee-edge.d.ts.map +1 -0
- package/dist/detectors/addressee-edge.js +13 -0
- package/dist/detectors/addressee-edge.js.map +1 -0
- package/dist/detectors/announced-count.d.ts.map +1 -1
- package/dist/detectors/announced-count.js +1 -0
- package/dist/detectors/announced-count.js.map +1 -1
- package/dist/detectors/bare-comparative.d.ts +4 -0
- package/dist/detectors/bare-comparative.d.ts.map +1 -1
- package/dist/detectors/bare-comparative.js +28 -3
- package/dist/detectors/bare-comparative.js.map +1 -1
- package/dist/detectors/blank-structure.d.ts +7 -1
- package/dist/detectors/blank-structure.d.ts.map +1 -1
- package/dist/detectors/blank-structure.js +13 -8
- package/dist/detectors/blank-structure.js.map +1 -1
- package/dist/detectors/bracket-specified.d.ts +6 -0
- package/dist/detectors/bracket-specified.d.ts.map +1 -0
- package/dist/detectors/bracket-specified.js +23 -0
- package/dist/detectors/bracket-specified.js.map +1 -0
- package/dist/detectors/broken-link.d.ts +6 -0
- package/dist/detectors/broken-link.d.ts.map +1 -1
- package/dist/detectors/broken-link.js +23 -2
- package/dist/detectors/broken-link.js.map +1 -1
- package/dist/detectors/caps-caption.d.ts +7 -6
- package/dist/detectors/caps-caption.d.ts.map +1 -1
- package/dist/detectors/caps-caption.js +38 -0
- package/dist/detectors/caps-caption.js.map +1 -1
- package/dist/detectors/caps-phrase.d.ts +6 -0
- package/dist/detectors/caps-phrase.d.ts.map +1 -0
- package/dist/detectors/caps-phrase.js +16 -0
- package/dist/detectors/caps-phrase.js.map +1 -0
- package/dist/detectors/char-shape.d.ts +1 -0
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +29 -16
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/cited-title.d.ts +3 -2
- package/dist/detectors/cited-title.d.ts.map +1 -1
- package/dist/detectors/cited-title.js +14 -3
- package/dist/detectors/cited-title.js.map +1 -1
- package/dist/detectors/counter-edge.d.ts +2 -1
- package/dist/detectors/counter-edge.d.ts.map +1 -1
- package/dist/detectors/counter-edge.js +17 -2
- package/dist/detectors/counter-edge.js.map +1 -1
- package/dist/detectors/date-any-year.d.ts +7 -3
- package/dist/detectors/date-any-year.d.ts.map +1 -1
- package/dist/detectors/date-any-year.js +25 -5
- package/dist/detectors/date-any-year.js.map +1 -1
- package/dist/detectors/date-format.d.ts.map +1 -1
- package/dist/detectors/date-format.js +2 -1
- package/dist/detectors/date-format.js.map +1 -1
- package/dist/detectors/date-year.d.ts +9 -3
- package/dist/detectors/date-year.d.ts.map +1 -1
- package/dist/detectors/date-year.js +45 -9
- package/dist/detectors/date-year.js.map +1 -1
- package/dist/detectors/deadline-unit.d.ts +20 -0
- package/dist/detectors/deadline-unit.d.ts.map +1 -0
- package/dist/detectors/deadline-unit.js +19 -0
- package/dist/detectors/deadline-unit.js.map +1 -0
- package/dist/detectors/defined-term-form.d.ts.map +1 -1
- package/dist/detectors/defined-term-form.js +33 -7
- package/dist/detectors/defined-term-form.js.map +1 -1
- package/dist/detectors/definition-use.d.ts.map +1 -1
- package/dist/detectors/definition-use.js +6 -3
- package/dist/detectors/definition-use.js.map +1 -1
- package/dist/detectors/derived-numbers.d.ts.map +1 -1
- package/dist/detectors/derived-numbers.js +17 -4
- package/dist/detectors/derived-numbers.js.map +1 -1
- package/dist/detectors/doubled-across-aside.d.ts +9 -0
- package/dist/detectors/doubled-across-aside.d.ts.map +1 -0
- package/dist/detectors/doubled-across-aside.js +27 -0
- package/dist/detectors/doubled-across-aside.js.map +1 -0
- package/dist/detectors/doubled-punctuation.d.ts +3 -3
- package/dist/detectors/doubled-punctuation.d.ts.map +1 -1
- package/dist/detectors/doubled-punctuation.js +23 -4
- package/dist/detectors/doubled-punctuation.js.map +1 -1
- package/dist/detectors/doubled-word.d.ts.map +1 -1
- package/dist/detectors/doubled-word.js +2 -1
- package/dist/detectors/doubled-word.js.map +1 -1
- package/dist/detectors/ellipsis.d.ts.map +1 -1
- package/dist/detectors/ellipsis.js +13 -1
- package/dist/detectors/ellipsis.js.map +1 -1
- package/dist/detectors/email-letter.d.ts +31 -1
- package/dist/detectors/email-letter.d.ts.map +1 -1
- package/dist/detectors/email-letter.js +76 -14
- package/dist/detectors/email-letter.js.map +1 -1
- package/dist/detectors/field-label.d.ts +7 -0
- package/dist/detectors/field-label.d.ts.map +1 -0
- package/dist/detectors/field-label.js +23 -0
- package/dist/detectors/field-label.js.map +1 -0
- package/dist/detectors/footnote-mismatch.d.ts +6 -1
- package/dist/detectors/footnote-mismatch.d.ts.map +1 -1
- package/dist/detectors/footnote-mismatch.js +28 -7
- package/dist/detectors/footnote-mismatch.js.map +1 -1
- package/dist/detectors/graded-step.d.ts +20 -0
- package/dist/detectors/graded-step.d.ts.map +1 -0
- package/dist/detectors/graded-step.js +33 -0
- package/dist/detectors/graded-step.js.map +1 -0
- package/dist/detectors/gram-openers.d.ts +8 -0
- package/dist/detectors/gram-openers.d.ts.map +1 -0
- package/dist/detectors/gram-openers.js +16 -0
- package/dist/detectors/gram-openers.js.map +1 -0
- package/dist/detectors/gram-place.d.ts +3 -1
- package/dist/detectors/gram-place.d.ts.map +1 -1
- package/dist/detectors/gram-place.js +8 -0
- package/dist/detectors/gram-place.js.map +1 -1
- package/dist/detectors/gram-predicate.d.ts.map +1 -1
- package/dist/detectors/gram-predicate.js +37 -3
- package/dist/detectors/gram-predicate.js.map +1 -1
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +28 -2
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/ime-residue.d.ts +1 -1
- package/dist/detectors/ime-residue.d.ts.map +1 -1
- package/dist/detectors/ime-residue.js +4 -3
- package/dist/detectors/ime-residue.js.map +1 -1
- package/dist/detectors/kanji-compound-slip.d.ts +3 -0
- package/dist/detectors/kanji-compound-slip.d.ts.map +1 -0
- package/dist/detectors/kanji-compound-slip.js +50 -0
- package/dist/detectors/kanji-compound-slip.js.map +1 -0
- package/dist/detectors/kutoten-consistency.d.ts +10 -2
- package/dist/detectors/kutoten-consistency.d.ts.map +1 -1
- package/dist/detectors/kutoten-consistency.js +76 -12
- package/dist/detectors/kutoten-consistency.js.map +1 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +8 -2
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/link-shape.d.ts.map +1 -1
- package/dist/detectors/link-shape.js +9 -3
- package/dist/detectors/link-shape.js.map +1 -1
- package/dist/detectors/list-item-ending.d.ts +18 -0
- package/dist/detectors/list-item-ending.d.ts.map +1 -0
- package/dist/detectors/list-item-ending.js +35 -0
- package/dist/detectors/list-item-ending.js.map +1 -0
- package/dist/detectors/list-parallel.d.ts +18 -5
- package/dist/detectors/list-parallel.d.ts.map +1 -1
- package/dist/detectors/list-parallel.js +116 -36
- package/dist/detectors/list-parallel.js.map +1 -1
- package/dist/detectors/list-sentence.d.ts +4 -0
- package/dist/detectors/list-sentence.d.ts.map +1 -1
- package/dist/detectors/list-sentence.js +1 -1
- package/dist/detectors/list-sentence.js.map +1 -1
- package/dist/detectors/mark-shape.d.ts +11 -4
- package/dist/detectors/mark-shape.d.ts.map +1 -1
- package/dist/detectors/mark-shape.js +58 -10
- package/dist/detectors/mark-shape.js.map +1 -1
- package/dist/detectors/mentioned-phrase.d.ts +9 -0
- package/dist/detectors/mentioned-phrase.d.ts.map +1 -0
- package/dist/detectors/mentioned-phrase.js +25 -0
- package/dist/detectors/mentioned-phrase.js.map +1 -0
- package/dist/detectors/middle-dot.d.ts +2 -2
- package/dist/detectors/middle-dot.d.ts.map +1 -1
- package/dist/detectors/middle-dot.js +4 -2
- package/dist/detectors/middle-dot.js.map +1 -1
- package/dist/detectors/modal-conflict.d.ts.map +1 -1
- package/dist/detectors/modal-conflict.js +5 -2
- package/dist/detectors/modal-conflict.js.map +1 -1
- package/dist/detectors/notice-paragraph.d.ts +9 -0
- package/dist/detectors/notice-paragraph.d.ts.map +1 -0
- package/dist/detectors/notice-paragraph.js +21 -0
- package/dist/detectors/notice-paragraph.js.map +1 -0
- package/dist/detectors/number-style.d.ts.map +1 -1
- package/dist/detectors/number-style.js +15 -2
- package/dist/detectors/number-style.js.map +1 -1
- package/dist/detectors/number-unit.d.ts.map +1 -1
- package/dist/detectors/number-unit.js +24 -1
- package/dist/detectors/number-unit.js.map +1 -1
- package/dist/detectors/numeral-opener.d.ts +6 -0
- package/dist/detectors/numeral-opener.d.ts.map +1 -1
- package/dist/detectors/numeral-opener.js +24 -1
- package/dist/detectors/numeral-opener.js.map +1 -1
- package/dist/detectors/obligation-without-deadline.d.ts +5 -1
- package/dist/detectors/obligation-without-deadline.d.ts.map +1 -1
- package/dist/detectors/obligation-without-deadline.js +44 -23
- package/dist/detectors/obligation-without-deadline.js.map +1 -1
- package/dist/detectors/open-end-class.d.ts +16 -0
- package/dist/detectors/open-end-class.d.ts.map +1 -0
- package/dist/detectors/open-end-class.js +65 -0
- package/dist/detectors/open-end-class.js.map +1 -0
- package/dist/detectors/open-end-condition.d.ts +7 -0
- package/dist/detectors/open-end-condition.d.ts.map +1 -0
- package/dist/detectors/open-end-condition.js +35 -0
- package/dist/detectors/open-end-condition.js.map +1 -0
- package/dist/detectors/open-end-names.d.ts +9 -3
- package/dist/detectors/open-end-names.d.ts.map +1 -1
- package/dist/detectors/open-end-names.js +5 -2
- package/dist/detectors/open-end-names.js.map +1 -1
- package/dist/detectors/open-end-question.d.ts +15 -0
- package/dist/detectors/open-end-question.d.ts.map +1 -0
- package/dist/detectors/open-end-question.js +37 -0
- package/dist/detectors/open-end-question.js.map +1 -0
- package/dist/detectors/open-end-scope.d.ts +16 -0
- package/dist/detectors/open-end-scope.d.ts.map +1 -0
- package/dist/detectors/open-end-scope.js +47 -0
- package/dist/detectors/open-end-scope.js.map +1 -0
- package/dist/detectors/opening-date.d.ts +10 -0
- package/dist/detectors/opening-date.d.ts.map +1 -0
- package/dist/detectors/opening-date.js +33 -0
- package/dist/detectors/opening-date.js.map +1 -0
- package/dist/detectors/ordinary-phrase.d.ts +20 -0
- package/dist/detectors/ordinary-phrase.d.ts.map +1 -0
- package/dist/detectors/ordinary-phrase.js +54 -0
- package/dist/detectors/ordinary-phrase.js.map +1 -0
- package/dist/detectors/organisation-run.d.ts +5 -1
- package/dist/detectors/organisation-run.d.ts.map +1 -1
- package/dist/detectors/organisation-run.js +7 -0
- package/dist/detectors/organisation-run.js.map +1 -1
- package/dist/detectors/orthographic-variant.d.ts.map +1 -1
- package/dist/detectors/orthographic-variant.js +56 -20
- package/dist/detectors/orthographic-variant.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +6 -1
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/oxford-comma.d.ts.map +1 -1
- package/dist/detectors/oxford-comma.js +38 -1
- package/dist/detectors/oxford-comma.js.map +1 -1
- package/dist/detectors/person-consistency.d.ts +2 -1
- package/dist/detectors/person-consistency.d.ts.map +1 -1
- package/dist/detectors/person-consistency.js +5 -3
- package/dist/detectors/person-consistency.js.map +1 -1
- package/dist/detectors/phrase-match.d.ts +2 -0
- package/dist/detectors/phrase-match.d.ts.map +1 -1
- package/dist/detectors/phrase-match.js +11 -4
- package/dist/detectors/phrase-match.js.map +1 -1
- package/dist/detectors/placeholder-text.d.ts.map +1 -1
- package/dist/detectors/placeholder-text.js +18 -3
- package/dist/detectors/placeholder-text.js.map +1 -1
- package/dist/detectors/placeholder.d.ts +3 -1
- package/dist/detectors/placeholder.d.ts.map +1 -1
- package/dist/detectors/placeholder.js +8 -3
- package/dist/detectors/placeholder.js.map +1 -1
- package/dist/detectors/postcode-end.d.ts +3 -0
- package/dist/detectors/postcode-end.d.ts.map +1 -0
- package/dist/detectors/postcode-end.js +15 -0
- package/dist/detectors/postcode-end.js.map +1 -0
- package/dist/detectors/prose-total-words.d.ts +5 -0
- package/dist/detectors/prose-total-words.d.ts.map +1 -0
- package/dist/detectors/prose-total-words.js +14 -0
- package/dist/detectors/prose-total-words.js.map +1 -0
- package/dist/detectors/registry/kanji-compound-slip.d.ts +3 -0
- package/dist/detectors/registry/kanji-compound-slip.d.ts.map +1 -0
- package/dist/detectors/registry/kanji-compound-slip.js +3 -0
- package/dist/detectors/registry/kanji-compound-slip.js.map +1 -0
- package/dist/detectors/registry/phrase-in-use.d.ts +3 -0
- package/dist/detectors/registry/phrase-in-use.d.ts.map +1 -0
- package/dist/detectors/registry/phrase-in-use.js +3 -0
- package/dist/detectors/registry/phrase-in-use.js.map +1 -0
- package/dist/detectors/requirement-smell.d.ts.map +1 -1
- package/dist/detectors/requirement-smell.js +29 -5
- package/dist/detectors/requirement-smell.js.map +1 -1
- package/dist/detectors/scaled-figure-unit.d.ts +28 -0
- package/dist/detectors/scaled-figure-unit.d.ts.map +1 -0
- package/dist/detectors/scaled-figure-unit.js +78 -0
- package/dist/detectors/scaled-figure-unit.js.map +1 -0
- package/dist/detectors/sentence-counts.d.ts +2 -0
- package/dist/detectors/sentence-counts.d.ts.map +1 -1
- package/dist/detectors/sentence-counts.js +18 -7
- package/dist/detectors/sentence-counts.js.map +1 -1
- package/dist/detectors/sentence-ending.d.ts +2 -0
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +10 -3
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/sentence-load.d.ts +4 -1
- package/dist/detectors/sentence-load.d.ts.map +1 -1
- package/dist/detectors/sentence-load.js +9 -2
- package/dist/detectors/sentence-load.js.map +1 -1
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +30 -50
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +14 -13
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +2 -1
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/subject-name-line.d.ts +8 -0
- package/dist/detectors/subject-name-line.d.ts.map +1 -0
- package/dist/detectors/subject-name-line.js +53 -0
- package/dist/detectors/subject-name-line.js.map +1 -0
- package/dist/detectors/table-header.d.ts.map +1 -1
- package/dist/detectors/table-header.js +13 -1
- package/dist/detectors/table-header.js.map +1 -1
- package/dist/detectors/technical-docs.d.ts.map +1 -1
- package/dist/detectors/technical-docs.js +4 -1
- package/dist/detectors/technical-docs.js.map +1 -1
- package/dist/detectors/term-mention-sentence.d.ts +4 -0
- package/dist/detectors/term-mention-sentence.d.ts.map +1 -0
- package/dist/detectors/term-mention-sentence.js +28 -0
- package/dist/detectors/term-mention-sentence.js.map +1 -0
- package/dist/detectors/titled-run.d.ts +2 -1
- package/dist/detectors/titled-run.d.ts.map +1 -1
- package/dist/detectors/titled-run.js +9 -4
- package/dist/detectors/titled-run.js.map +1 -1
- package/dist/detectors/token-shape.d.ts.map +1 -1
- package/dist/detectors/token-shape.js +13 -5
- package/dist/detectors/token-shape.js.map +1 -1
- package/dist/detectors/vague-density.d.ts +5 -2
- package/dist/detectors/vague-density.d.ts.map +1 -1
- package/dist/detectors/vague-density.js +17 -4
- package/dist/detectors/vague-density.js.map +1 -1
- package/dist/document-paragraphs.d.ts +4 -0
- package/dist/document-paragraphs.d.ts.map +1 -0
- package/dist/document-paragraphs.js +24 -0
- package/dist/document-paragraphs.js.map +1 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +2 -19
- package/dist/document.js.map +1 -1
- package/dist/figure-references.d.ts +3 -0
- package/dist/figure-references.d.ts.map +1 -1
- package/dist/figure-references.js +6 -2
- package/dist/figure-references.js.map +1 -1
- package/dist/format-template.d.ts +3 -0
- package/dist/format-template.d.ts.map +1 -0
- package/dist/format-template.js +13 -0
- package/dist/format-template.js.map +1 -0
- package/dist/formula-brackets.d.ts +7 -0
- package/dist/formula-brackets.d.ts.map +1 -0
- package/dist/formula-brackets.js +29 -0
- package/dist/formula-brackets.js.map +1 -0
- package/dist/html/html-markdown.d.ts.map +1 -1
- package/dist/html/html-markdown.js +2 -1
- package/dist/html/html-markdown.js.map +1 -1
- package/dist/html/html-site-chrome.d.ts +5 -0
- package/dist/html/html-site-chrome.d.ts.map +1 -0
- package/dist/html/html-site-chrome.js +33 -0
- package/dist/html/html-site-chrome.js.map +1 -0
- package/dist/joined-view.d.ts.map +1 -1
- package/dist/joined-view.js +1 -0
- package/dist/joined-view.js.map +1 -1
- package/dist/kanji-compound-slip.d.ts +32 -0
- package/dist/kanji-compound-slip.d.ts.map +1 -0
- package/dist/kanji-compound-slip.js +63 -0
- package/dist/kanji-compound-slip.js.map +1 -0
- package/dist/latin-company-form.d.ts +6 -0
- package/dist/latin-company-form.d.ts.map +1 -0
- package/dist/latin-company-form.js +32 -0
- package/dist/latin-company-form.js.map +1 -0
- package/dist/latin-word-boundary.d.ts +15 -0
- package/dist/latin-word-boundary.d.ts.map +1 -0
- package/dist/latin-word-boundary.js +40 -0
- package/dist/latin-word-boundary.js.map +1 -0
- package/dist/lexicon-genres.d.ts +2 -0
- package/dist/lexicon-genres.d.ts.map +1 -1
- package/dist/lexicon-genres.js +1 -1
- package/dist/lexicon-genres.js.map +1 -1
- package/dist/link-shape.d.ts +5 -0
- package/dist/link-shape.d.ts.map +1 -1
- package/dist/link-shape.js +18 -0
- package/dist/link-shape.js.map +1 -1
- package/dist/link-title.d.ts +4 -0
- package/dist/link-title.d.ts.map +1 -0
- package/dist/link-title.js +33 -0
- package/dist/link-title.js.map +1 -0
- package/dist/list-item-paragraphs.d.ts +15 -0
- package/dist/list-item-paragraphs.d.ts.map +1 -0
- package/dist/list-item-paragraphs.js +19 -0
- package/dist/list-item-paragraphs.js.map +1 -0
- package/dist/literal-quote.d.ts +12 -0
- package/dist/literal-quote.d.ts.map +1 -0
- package/dist/literal-quote.js +43 -0
- package/dist/literal-quote.js.map +1 -0
- package/dist/nado-closed-list.d.ts.map +1 -1
- package/dist/nado-closed-list.js +39 -5
- package/dist/nado-closed-list.js.map +1 -1
- package/dist/name-separator.d.ts.map +1 -1
- package/dist/name-separator.js +25 -2
- package/dist/name-separator.js.map +1 -1
- package/dist/nominal-stem.d.ts +14 -1
- package/dist/nominal-stem.d.ts.map +1 -1
- package/dist/nominal-stem.js +42 -4
- package/dist/nominal-stem.js.map +1 -1
- package/dist/person-forms.d.ts +8 -0
- package/dist/person-forms.d.ts.map +1 -1
- package/dist/person-forms.js +12 -0
- package/dist/person-forms.js.map +1 -1
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/preamble-paragraphs.d.ts +3 -2
- package/dist/preamble-paragraphs.d.ts.map +1 -1
- package/dist/preamble-paragraphs.js +8 -2
- package/dist/preamble-paragraphs.js.map +1 -1
- package/dist/spacing-code.d.ts +1 -0
- package/dist/spacing-code.d.ts.map +1 -1
- package/dist/spacing-code.js +4 -1
- package/dist/spacing-code.js.map +1 -1
- package/dist/split-noun.d.ts +10 -0
- package/dist/split-noun.d.ts.map +1 -0
- package/dist/split-noun.js +50 -0
- package/dist/split-noun.js.map +1 -0
- package/dist/structure/attached-parts.d.ts +11 -0
- package/dist/structure/attached-parts.d.ts.map +1 -0
- package/dist/structure/attached-parts.js +31 -0
- package/dist/structure/attached-parts.js.map +1 -0
- package/dist/structure/build.d.ts.map +1 -1
- package/dist/structure/build.js +7 -4
- package/dist/structure/build.js.map +1 -1
- package/dist/structure/contents-lines.d.ts +7 -0
- package/dist/structure/contents-lines.d.ts.map +1 -0
- package/dist/structure/contents-lines.js +51 -0
- package/dist/structure/contents-lines.js.map +1 -0
- package/dist/structure/defining-names.d.ts +37 -0
- package/dist/structure/defining-names.d.ts.map +1 -0
- package/dist/structure/defining-names.js +122 -0
- package/dist/structure/defining-names.js.map +1 -0
- package/dist/structure/definition-use.d.ts +3 -2
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +99 -31
- package/dist/structure/definition-use.js.map +1 -1
- package/dist/structure/issues.d.ts +4 -1
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +5 -2
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/list-lead-in.d.ts +19 -0
- package/dist/structure/list-lead-in.d.ts.map +1 -0
- package/dist/structure/list-lead-in.js +85 -0
- package/dist/structure/list-lead-in.js.map +1 -0
- package/dist/structure/modal-conflict.d.ts +7 -2
- package/dist/structure/modal-conflict.d.ts.map +1 -1
- package/dist/structure/modal-conflict.js +36 -7
- package/dist/structure/modal-conflict.js.map +1 -1
- package/dist/structure/negated-act.d.ts +17 -0
- package/dist/structure/negated-act.d.ts.map +1 -0
- package/dist/structure/negated-act.js +32 -0
- package/dist/structure/negated-act.js.map +1 -0
- package/dist/structure/numbering.d.ts +3 -1
- package/dist/structure/numbering.d.ts.map +1 -1
- package/dist/structure/numbering.js +20 -8
- package/dist/structure/numbering.js.map +1 -1
- package/dist/structure/prose-total.d.ts +4 -0
- package/dist/structure/prose-total.d.ts.map +1 -1
- package/dist/structure/prose-total.js +16 -6
- package/dist/structure/prose-total.js.map +1 -1
- package/dist/structure/repeated-number.d.ts +24 -0
- package/dist/structure/repeated-number.d.ts.map +1 -0
- package/dist/structure/repeated-number.js +89 -0
- package/dist/structure/repeated-number.js.map +1 -0
- package/dist/structure/rounded-amount.d.ts +8 -0
- package/dist/structure/rounded-amount.d.ts.map +1 -0
- package/dist/structure/rounded-amount.js +48 -0
- package/dist/structure/rounded-amount.js.map +1 -0
- package/dist/structure/side-step.d.ts +8 -0
- package/dist/structure/side-step.d.ts.map +1 -0
- package/dist/structure/side-step.js +21 -0
- package/dist/structure/side-step.js.map +1 -0
- package/dist/structure/spanned-label-blank.d.ts +8 -0
- package/dist/structure/spanned-label-blank.d.ts.map +1 -0
- package/dist/structure/spanned-label-blank.js +37 -0
- package/dist/structure/spanned-label-blank.js.map +1 -0
- package/dist/structure/universal.d.ts +3 -1
- package/dist/structure/universal.d.ts.map +1 -1
- package/dist/structure/universal.js +9 -2
- package/dist/structure/universal.js.map +1 -1
- package/dist/structure/unspaced-heading.d.ts +10 -0
- package/dist/structure/unspaced-heading.d.ts.map +1 -0
- package/dist/structure/unspaced-heading.js +24 -0
- package/dist/structure/unspaced-heading.js.map +1 -0
- package/dist/structure/written-list-path.d.ts +10 -0
- package/dist/structure/written-list-path.d.ts.map +1 -0
- package/dist/structure/written-list-path.js +37 -0
- package/dist/structure/written-list-path.js.map +1 -0
- package/dist/structure/written-resolve.d.ts +1 -1
- package/dist/structure/written-resolve.d.ts.map +1 -1
- package/dist/structure/written-resolve.js +15 -9
- package/dist/structure/written-resolve.js.map +1 -1
- package/dist/title-line.d.ts +21 -0
- package/dist/title-line.d.ts.map +1 -0
- package/dist/title-line.js +27 -0
- package/dist/title-line.js.map +1 -0
- package/package.json +3 -3
- package/rules/all-caps-shouting.yaml +2 -2
- package/rules/announced-count-mismatch.yaml +2 -2
- package/rules/bare-url-mix.yaml +2 -2
- package/rules/bracket-nesting.yaml +2 -2
- package/rules/bracket-width-consistency.yaml +2 -2
- package/rules/broken-link.yaml +2 -2
- package/rules/cliche.yaml +4 -3
- package/rules/code-fence-language-mix.yaml +2 -2
- package/rules/comparative-without-baseline.yaml +2 -2
- package/rules/dangling-figure-reference.yaml +2 -2
- package/rules/date-without-year.yaml +10 -2
- package/rules/defined-term-form.yaml +2 -2
- package/rules/doubled-punctuation.yaml +4 -4
- package/rules/doubled-word.yaml +2 -2
- package/rules/duplicate-definition.yaml +2 -2
- package/rules/duration-mismatch.yaml +2 -2
- package/rules/email-greeting-closing.yaml +2 -2
- package/rules/email-subject-length.yaml +2 -2
- package/rules/empty-table-cell.yaml +2 -2
- package/rules/footnote-mismatch.yaml +2 -2
- package/rules/heading-echo.yaml +2 -2
- package/rules/ime-residue.yaml +2 -2
- package/rules/kanji-compound-slip.yaml +67 -0
- package/rules/kutoten-consistency.yaml +4 -4
- package/rules/latin-spacing.yaml +2 -2
- package/rules/list-item-form-mix.yaml +2 -2
- package/rules/max-kanji-continuous.yaml +6 -4
- package/rules/modal-conflict.yaml +1 -0
- package/rules/nado-closed-list.yaml +2 -2
- package/rules/ngram-repetition.yaml +2 -2
- package/rules/no-doubled-joshi.yaml +2 -2
- package/rules/no-mixed-desumasu.yaml +3 -3
- package/rules/no-nakaguro-parallel.yaml +2 -0
- package/rules/number-without-unit.yaml +9 -4
- package/rules/numbering-gap.yaml +7 -2
- package/rules/numeral-sentence-start.yaml +2 -2
- package/rules/obligation-without-deadline.yaml +2 -2
- package/rules/orthographic-variant.yaml +2 -2
- package/rules/oxford-comma-consistency.yaml +3 -3
- package/rules/preamble-length.yaml +2 -2
- package/rules/requirement-smell.yaml +3 -3
- package/rules/table-header-variant.yaml +2 -2
- package/rules/teki-overuse.yaml +3 -2
- package/rules/total-mismatch.yaml +2 -2
- package/rules/translationese-density.yaml +2 -2
- package/rules/undefined-acronym.yaml +4 -2
- package/rules/unfilled-placeholder.yaml +4 -4
- package/rules/use-before-definition.yaml +2 -2
- package/rules/vague-word-density.yaml +2 -2
- package/skills/chaff/SKILL.md +7 -1
- package/src/announced-count.ts +35 -8
- package/src/chronology-rows.ts +86 -0
- package/src/company-name-run.ts +37 -0
- package/src/compound-head.ts +25 -0
- package/src/date-format.ts +43 -4
- package/src/derived/count-per-period.ts +28 -0
- package/src/detectors/acronym-context.ts +30 -1
- package/src/detectors/acronym-expansion.ts +47 -6
- package/src/detectors/acronym-known.ts +40 -0
- package/src/detectors/acronym-link.ts +37 -0
- package/src/detectors/acronym-name.ts +27 -4
- package/src/detectors/addressee-edge.ts +16 -0
- package/src/detectors/announced-count.ts +1 -0
- package/src/detectors/bare-comparative.ts +44 -3
- package/src/detectors/blank-structure.ts +21 -10
- package/src/detectors/bracket-specified.ts +25 -0
- package/src/detectors/broken-link.ts +26 -2
- package/src/detectors/caps-caption.ts +42 -0
- package/src/detectors/caps-phrase.ts +17 -0
- package/src/detectors/char-shape.ts +30 -9
- package/src/detectors/cited-title.ts +15 -3
- package/src/detectors/counter-edge.ts +17 -2
- package/src/detectors/date-any-year.ts +27 -6
- package/src/detectors/date-format.ts +2 -1
- package/src/detectors/date-year.ts +64 -16
- package/src/detectors/deadline-unit.ts +40 -0
- package/src/detectors/defined-term-form.ts +32 -12
- package/src/detectors/definition-use.ts +7 -3
- package/src/detectors/derived-numbers.ts +19 -4
- package/src/detectors/doubled-across-aside.ts +36 -0
- package/src/detectors/doubled-punctuation.ts +28 -7
- package/src/detectors/doubled-word.ts +2 -1
- package/src/detectors/ellipsis.ts +16 -1
- package/src/detectors/email-letter.ts +97 -21
- package/src/detectors/field-label.ts +25 -0
- package/src/detectors/footnote-mismatch.ts +39 -7
- package/src/detectors/graded-step.ts +52 -0
- package/src/detectors/gram-openers.ts +21 -0
- package/src/detectors/gram-place.ts +10 -1
- package/src/detectors/gram-predicate.ts +43 -3
- package/src/detectors/heading-echo.ts +31 -3
- package/src/detectors/ime-residue.ts +4 -3
- package/src/detectors/kanji-compound-slip.ts +61 -0
- package/src/detectors/kutoten-consistency.ts +93 -14
- package/src/detectors/lexicon.ts +12 -3
- package/src/detectors/link-shape.ts +10 -3
- package/src/detectors/list-item-ending.ts +51 -0
- package/src/detectors/list-parallel.ts +158 -33
- package/src/detectors/list-sentence.ts +5 -1
- package/src/detectors/mark-shape.ts +64 -10
- package/src/detectors/mentioned-phrase.ts +38 -0
- package/src/detectors/middle-dot.ts +7 -2
- package/src/detectors/modal-conflict.ts +5 -2
- package/src/detectors/notice-paragraph.ts +33 -0
- package/src/detectors/number-style.ts +14 -2
- package/src/detectors/number-unit.ts +28 -1
- package/src/detectors/numeral-opener.ts +27 -1
- package/src/detectors/obligation-without-deadline.ts +29 -4
- package/src/detectors/open-end-class.ts +78 -0
- package/src/detectors/open-end-condition.ts +40 -0
- package/src/detectors/open-end-names.ts +9 -3
- package/src/detectors/open-end-question.ts +50 -0
- package/src/detectors/open-end-scope.ts +62 -0
- package/src/detectors/opening-date.ts +47 -0
- package/src/detectors/ordinary-phrase.ts +62 -0
- package/src/detectors/organisation-run.ts +13 -2
- package/src/detectors/orthographic-variant.ts +85 -25
- package/src/detectors/orthography.ts +10 -1
- package/src/detectors/oxford-comma.ts +40 -1
- package/src/detectors/person-consistency.ts +5 -3
- package/src/detectors/phrase-match.ts +16 -5
- package/src/detectors/placeholder-text.ts +18 -3
- package/src/detectors/placeholder.ts +10 -3
- package/src/detectors/postcode-end.ts +16 -0
- package/src/detectors/prose-total-words.ts +18 -0
- package/src/detectors/registry/kanji-compound-slip.ts +4 -0
- package/src/detectors/registry/phrase-in-use.ts +4 -0
- package/src/detectors/requirement-smell.ts +38 -5
- package/src/detectors/scaled-figure-unit.ts +103 -0
- package/src/detectors/sentence-counts.ts +24 -8
- package/src/detectors/sentence-ending.ts +12 -3
- package/src/detectors/sentence-load.ts +9 -2
- package/src/detectors/signals.ts +33 -51
- package/src/detectors/structure-tree.ts +14 -14
- package/src/detectors/structure.ts +2 -1
- package/src/detectors/subject-name-line.ts +66 -0
- package/src/detectors/table-header.ts +15 -1
- package/src/detectors/technical-docs.ts +5 -1
- package/src/detectors/term-mention-sentence.ts +31 -0
- package/src/detectors/titled-run.ts +9 -4
- package/src/detectors/token-shape.ts +14 -5
- package/src/detectors/vague-density.ts +20 -4
- package/src/document-paragraphs.ts +27 -0
- package/src/document.ts +3 -23
- package/src/figure-references.ts +7 -2
- package/src/format-template.ts +15 -0
- package/src/formula-brackets.ts +36 -0
- package/src/html/html-markdown.ts +2 -1
- package/src/html/html-site-chrome.ts +47 -0
- package/src/joined-view.ts +1 -0
- package/src/kanji-compound-slip.ts +98 -0
- package/src/latin-company-form.ts +38 -0
- package/src/latin-word-boundary.ts +46 -0
- package/src/lexicon-genres.ts +1 -1
- package/src/link-shape.ts +19 -0
- package/src/link-title.ts +38 -0
- package/src/list-item-paragraphs.ts +22 -0
- package/src/literal-quote.ts +55 -0
- package/src/nado-closed-list.ts +48 -5
- package/src/name-separator.ts +27 -2
- package/src/nominal-stem.ts +62 -5
- package/src/person-forms.ts +15 -0
- package/src/plugin.ts +5 -0
- package/src/preamble-paragraphs.ts +13 -3
- package/src/spacing-code.ts +5 -1
- package/src/split-noun.ts +63 -0
- package/src/structure/attached-parts.ts +32 -0
- package/src/structure/build.ts +7 -4
- package/src/structure/contents-lines.ts +63 -0
- package/src/structure/defining-names.ts +155 -0
- package/src/structure/definition-use.ts +116 -25
- package/src/structure/issues.ts +7 -3
- package/src/structure/list-lead-in.ts +94 -0
- package/src/structure/modal-conflict.ts +42 -7
- package/src/structure/negated-act.ts +49 -0
- package/src/structure/numbering.ts +24 -9
- package/src/structure/prose-total.ts +20 -6
- package/src/structure/repeated-number.ts +110 -0
- package/src/structure/rounded-amount.ts +55 -0
- package/src/structure/side-step.ts +21 -0
- package/src/structure/spanned-label-blank.ts +39 -0
- package/src/structure/universal.ts +11 -2
- package/src/structure/unspaced-heading.ts +27 -0
- package/src/structure/written-list-path.ts +46 -0
- package/src/structure/written-resolve.ts +16 -9
- package/src/title-line.ts +52 -0
|
@@ -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
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Detector, DetectorOptions, Finding, Lexicon, ProseDocument, Sentence, Token } from "../plugin.ts";
|
|
1
|
+
import type { Detector, DetectorOptions, Finding, Lexicon, ProseDocument, Sentence, Span, Token } from "../plugin.ts";
|
|
2
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
2
3
|
import { isWithinAny, quotedIn } from "../quoted-span.ts";
|
|
3
4
|
import { entryOpens } from "./lexicon-match.ts";
|
|
4
5
|
|
|
@@ -6,10 +7,25 @@ type TokenTest = (token: Token, at: number, tokens: readonly Token[]) => boolean
|
|
|
6
7
|
|
|
7
8
|
const wordsOf = (lexicon: Lexicon | undefined): ReadonlySet<string> => new Set((lexicon ?? []).map((entry) => entry.pattern));
|
|
8
9
|
|
|
9
|
-
/** The
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
/** The terms whose counted word belongs to the term itself (電磁的方法), not to the writer's style. */
|
|
11
|
+
export const FIXED_TERM_LEXICON = "teki-fixed-term";
|
|
12
|
+
|
|
13
|
+
/** Where the sentence holds one of the terms, in the document's coordinates. */
|
|
14
|
+
const termSpans = (sentence: Sentence, terms: Lexicon): Span[] =>
|
|
15
|
+
terms.flatMap((entry) =>
|
|
16
|
+
[...sentence.text.matchAll(new RegExp(escapeRegExp(entry.pattern), "gu"))].map((match) => ({
|
|
17
|
+
start: sentence.span.start + match.index,
|
|
18
|
+
end: sentence.span.start + match.index + entry.pattern.length,
|
|
19
|
+
})),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The tokens of a sentence that pass the test, outside anything quoted in 「」『』 and outside the fixed terms: neither a
|
|
24
|
+
* quotation nor a term the law defines (電磁的方法) is the writer's to rephrase.
|
|
25
|
+
*/
|
|
26
|
+
const countedTokens = (sentence: Sentence, test: TokenTest, fixedTerms: Lexicon): Token[] => {
|
|
27
|
+
const kept = [...quotedIn(sentence), ...termSpans(sentence, fixedTerms)];
|
|
28
|
+
return (sentence.tokens ?? []).filter((token, at, tokens) => test(token, at, tokens) && !isWithinAny(kept, token.span));
|
|
13
29
|
};
|
|
14
30
|
|
|
15
31
|
const findingOf = (sentence: Sentence, counted: readonly Token[], limit: number): Finding => ({
|
|
@@ -21,16 +37,16 @@ const findingOf = (sentence: Sentence, counted: readonly Token[], limit: number)
|
|
|
21
37
|
values: { word: counted[0]?.surface ?? "", count: counted.length, limit, offset: sentence.span.start },
|
|
22
38
|
});
|
|
23
39
|
|
|
24
|
-
const sentencesOver = (doc: ProseDocument, limit: number, test: TokenTest): Finding[] =>
|
|
40
|
+
const sentencesOver = (doc: ProseDocument, limit: number, test: TokenTest, fixedTerms: Lexicon = []): Finding[] =>
|
|
25
41
|
doc.sentences.flatMap((sentence) => {
|
|
26
|
-
const counted = countedTokens(sentence, test);
|
|
42
|
+
const counted = countedTokens(sentence, test, fixedTerms);
|
|
27
43
|
return counted.length > limit ? [findingOf(sentence, counted, limit)] : [];
|
|
28
44
|
});
|
|
29
45
|
|
|
30
46
|
/** A sentence holding more than limit tokens written as one of the lexicon's words (the suffix 的). */
|
|
31
47
|
export const sentenceWordCount: Detector = (doc, options): Finding[] => {
|
|
32
48
|
const words = wordsOf(options.lexicon);
|
|
33
|
-
return sentencesOver(doc, options.limit, (token) => words.has(token.surface));
|
|
49
|
+
return sentencesOver(doc, options.limit, (token) => words.has(token.surface), doc.lexicons[FIXED_TERM_LEXICON] ?? []);
|
|
34
50
|
};
|
|
35
51
|
|
|
36
52
|
const NOMINAL: ReadonlySet<string> = new Set(["NOUN", "PROPN", "NUM"]);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { endingTokens, isClosed } from "../sentence-shape.ts";
|
|
2
2
|
import { enumeratedRuns, enumeratorStarts, numberedStarts } from "./enumerated-runs.ts";
|
|
3
|
-
import { continuesInto, groupOf, registerOf, slipsOf, type Register } from "./register.ts";
|
|
3
|
+
import { continuesInto, groupOf, majorityOf, registerOf, slipsOf, type Register } from "./register.ts";
|
|
4
4
|
import { isRunInLabel } from "./run-in-label.ts";
|
|
5
|
+
import { noticeSentences } from "./notice-paragraph.ts";
|
|
6
|
+
import { chronologyRows } from "../chronology-rows.ts";
|
|
5
7
|
import type { Detector, Finding, LexiconEntry, ProseDocument, Sentence, Span } from "../plugin.ts";
|
|
6
8
|
|
|
7
9
|
/**
|
|
@@ -10,6 +12,8 @@ import type { Detector, Finding, LexiconEntry, ProseDocument, Sentence, Span } f
|
|
|
10
12
|
* どちらが正しいかは決めない。決めると、方針の違う書き手にそのまま無視される。
|
|
11
13
|
* 見るのは文書の中での一貫性だけで、少数派のほうを指摘する。spec §12.3 の方針を日本語にも。
|
|
12
14
|
* 終止符で終わらないもの(見出しの下の `MaaSサービス` のような名前だけの行)と、項目や段落の頭の太字の札(**速く書ける。**)は文として数えない。
|
|
15
|
+
* 年表の行(1921年信号装置の製作を開始する。)も、文書の文体と揃えない書き方なので数えない。
|
|
16
|
+
* 断り書きの段落(…ご了承ください。)も、本文とは別の声で書く決まり文句なので数えない(notice-paragraph.ts)。
|
|
13
17
|
*/
|
|
14
18
|
type Entry = { readonly sentence: Sentence; readonly register: Register; readonly group: number | undefined };
|
|
15
19
|
|
|
@@ -35,11 +39,16 @@ const runsOf = (doc: ProseDocument, registers: readonly Register[]): Span[] => {
|
|
|
35
39
|
export const judgedSentences = (doc: ProseDocument, polite: readonly LexiconEntry[]): Entry[] => {
|
|
36
40
|
const neutral = doc.lexicons["neutral-ending"] ?? [];
|
|
37
41
|
const lists = doc.lists.map((list) => list.span);
|
|
38
|
-
const
|
|
39
|
-
|
|
42
|
+
const rows = chronologyRows(doc);
|
|
43
|
+
const all = doc.sentences.flatMap((sentence, index): { sentence: Sentence; register: Register }[] => {
|
|
44
|
+
if (!isClosed(sentence) || rows.has(sentence) || continuesInto(sentence, doc.sentences[index + 1]) || isRunInLabel(doc.source, sentence.span)) return [];
|
|
40
45
|
const register = registerOfSentence(sentence, polite, neutral);
|
|
41
46
|
return register === undefined ? [] : [{ sentence, register }];
|
|
42
47
|
});
|
|
48
|
+
const registers = new Map(all.map((entry) => [entry.sentence, entry.register]));
|
|
49
|
+
const majority = majorityOf(all.map((entry) => ({ register: entry.register, group: undefined })));
|
|
50
|
+
const notices = noticeSentences(doc.paragraphs, doc.lexicons["notice-phrase"] ?? [], (sentence) => registers.get(sentence), majority);
|
|
51
|
+
const found = all.filter((entry) => !notices.has(entry.sentence));
|
|
43
52
|
const runs = runsOf(
|
|
44
53
|
doc,
|
|
45
54
|
found.map((entry) => entry.register),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Detector, Finding, Sentence, Token } from "../plugin.ts";
|
|
2
2
|
import { proseText } from "../measure.ts";
|
|
3
3
|
import { quotedSpans } from "../quoted-span.ts";
|
|
4
|
+
import { literalCues, withoutLiteralQuotes } from "../literal-quote.ts";
|
|
4
5
|
import { bracketDepth, clauseCount, topicDistance } from "../sentence-load.ts";
|
|
5
6
|
|
|
6
7
|
const findingOf = (sentence: Sentence, count: number, limit: number): Finding => ({
|
|
@@ -35,8 +36,14 @@ const ownTokens = (sentence: Sentence): Token[] => {
|
|
|
35
36
|
return (sentence.tokens ?? []).filter((token) => !inQuote(token));
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
/**
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Brackets inside brackets: 「(注(a)参照)」. The depth is read from the text, so it works in every language. A quotation of a
|
|
41
|
+
* string to type as it stands (件名に「応募(総務課)」と記載) counts as one bracket: its own brackets cannot be taken out.
|
|
42
|
+
*/
|
|
43
|
+
export const bracketNesting: Detector = (doc, options) => {
|
|
44
|
+
const cues = literalCues(doc.lexicons["literal-quote-cue"] ?? []);
|
|
45
|
+
return overLimit((sentence) => bracketDepth(withoutLiteralQuotes(sentence.text, cues)))(doc, options);
|
|
46
|
+
};
|
|
40
47
|
|
|
41
48
|
/** Clauses chained in one sentence (調べて、まとめ、報告したが、返事がないので、…). Needs the language's tokens. */
|
|
42
49
|
export const clauseChain: Detector = overLimit((sentence) => (sentence.tokens === undefined ? undefined : clauseCount(ownTokens(sentence))));
|
package/src/detectors/signals.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { proseText } from "../measure.ts";
|
|
2
2
|
import { dateSpans, wordsOf } from "./structure.ts";
|
|
3
|
-
import { compacted,
|
|
3
|
+
import { compacted, linkedIn, placeAt } from "./gram-place.ts";
|
|
4
4
|
import { charWindows, wordWindows } from "./gram-windows.ts";
|
|
5
5
|
import { furnitureMask, isFurniture } from "./gram-furniture.ts";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { abbreviates, expansionAt, termEntryAcronyms, type ExpandedAt } from "./acronym-expansion.ts";
|
|
6
|
+
import { lexiconNotationOf, type NotAcronymSpans } from "./acronym-context.ts";
|
|
7
|
+
import { abbreviates, expansionAt, termEntryAcronyms, type DefinitionWords, type ExpandedAt } from "./acronym-expansion.ts";
|
|
9
8
|
import { isExplained } from "./acronym-compound.ts";
|
|
10
9
|
import { statedAcronyms } from "./acronym-definition.ts";
|
|
11
10
|
import { isBracketed, isInHeading, isNamePart } from "./acronym-lone.ts";
|
|
11
|
+
import { linkTitleSpans } from "./acronym-link.ts";
|
|
12
12
|
import { conjugatedForms } from "./conjugated-form.ts";
|
|
13
13
|
import { evidenceSpans, hasNumeral, isClaim, isLabelOnly, startsWithin, type AdviceWords } from "./concrete-evidence.ts";
|
|
14
14
|
import { letteredIndexEntries } from "./lettered-index.ts";
|
|
15
|
+
import { knownByDocument } from "./acronym-known.ts";
|
|
15
16
|
import { outlineLabelSpans } from "./outline-label.ts";
|
|
16
17
|
import { hasPredicateIn } from "./gram-predicate.ts";
|
|
17
18
|
import { gramPassagesOf } from "./gram-passages.ts";
|
|
19
|
+
import { sectionOpeners } from "./gram-openers.ts";
|
|
18
20
|
import { nameSpans, touchesAny } from "../team-names.ts";
|
|
19
21
|
import { referenceListSpans } from "../reference-lists.ts";
|
|
20
22
|
import type { Detector, Finding, ProseDocument, Section, Sentence } from "../plugin.ts";
|
|
@@ -97,15 +99,6 @@ type FirstSeen = { readonly gram: string; readonly sentence: Sentence; readonly
|
|
|
97
99
|
|
|
98
100
|
type Tally = { readonly counts: Map<string, number>; readonly first: Map<string, FirstSeen> };
|
|
99
101
|
|
|
100
|
-
/** 詰めた文の index 番目の文字が、リンクの文字か。 */
|
|
101
|
-
const linkedIn = (doc: ProseDocument, sentence: Sentence, source: Compacted): ((index: number) => boolean) => {
|
|
102
|
-
const links = doc.links.filter((link) => link.start < sentence.span.end && sentence.span.start < link.end);
|
|
103
|
-
return (index) => {
|
|
104
|
-
const at = sentence.span.start + (source.offsets[index] ?? -1);
|
|
105
|
-
return links.some((link) => link.start <= at && at < link.end);
|
|
106
|
-
};
|
|
107
|
-
};
|
|
108
|
-
|
|
109
102
|
/** 英語は大文字と小文字を区別せずに数える。文頭の "Proposals submitted via" も文中の "proposals submitted via" も同じ言い回し。 */
|
|
110
103
|
const keyOf = (gram: string, unit: ProseDocument["lengthUnit"]): string => (unit === "word" ? gram.toLowerCase() : gram);
|
|
111
104
|
|
|
@@ -140,12 +133,16 @@ const gramsOf = (doc: ProseDocument, sentences: readonly Sentence[]): Tally => {
|
|
|
140
133
|
|
|
141
134
|
type Repeat = { readonly key: string; readonly count: number; readonly at: FirstSeen | undefined };
|
|
142
135
|
|
|
143
|
-
/** 範囲(gram-passages.ts
|
|
144
|
-
const repeatsOf = (doc: ProseDocument, limit: number): Repeat[] =>
|
|
136
|
+
/** 範囲(gram-passages.ts)ごとに数える。よくある質問の別々の答えは別の範囲。節の最初の文にだけ出るものは節のひな形(gram-openers.ts)。 */
|
|
137
|
+
const repeatsOf = (doc: ProseDocument, limit: number, openers = sectionOpeners(doc.sections, doc.source)): Repeat[] =>
|
|
145
138
|
gramPassagesOf(doc.sections).flatMap((sentences) => {
|
|
146
139
|
const tally = gramsOf(doc, sentences);
|
|
140
|
+
const opening = gramsOf(
|
|
141
|
+
doc,
|
|
142
|
+
sentences.filter((sentence) => openers.has(sentence)),
|
|
143
|
+
).counts;
|
|
147
144
|
return [...tally.counts.entries()]
|
|
148
|
-
.filter(([key, count]) => count > limit && isPhrasing(key, doc.lengthUnit))
|
|
145
|
+
.filter(([key, count]) => count > limit && isPhrasing(key, doc.lengthUnit) && (opening.get(key) ?? 0) < count)
|
|
149
146
|
.map(([key, count]) => ({ key, count, at: tally.first.get(key) }));
|
|
150
147
|
});
|
|
151
148
|
|
|
@@ -184,9 +181,10 @@ export const ngramRepetition: Detector = (doc, options): Finding[] => {
|
|
|
184
181
|
*
|
|
185
182
|
* & で繋いだ大文字は 1 語として読む(ATT&CK、M&IE)。割ると CK や IE が別の略語に見える。
|
|
186
183
|
* - で繋いだ略語どうしも 1 語(RT-PCR)。割ると RT が別の略語に見える。数字を含むもの(COVID-19)は識別子として外す。
|
|
184
|
+
* 下付きの数字が続く大文字は化学式(CO₂、SO₄)で、説明を待つ略語ではない。数字や小文字が続くもの(CO2、NOx)と同じく語の途中と読む。
|
|
187
185
|
*/
|
|
188
186
|
const EDGE_BEFORE = String.raw`(?<![A-Za-z0-9_&])`;
|
|
189
|
-
const EDGE_AFTER = String.raw`(?![A-Za-z0-9_
|
|
187
|
+
const EDGE_AFTER = String.raw`(?![A-Za-z0-9_&\u2080-\u2089])`;
|
|
190
188
|
/** 略語として読む大文字の長さの上限。これより長い大文字の語(BILLING)は、普通の語を大文字で書いたもの。 */
|
|
191
189
|
const ACRONYM_MAX = 6;
|
|
192
190
|
const ACRONYM_PART = String.raw`(?:[A-Z]+(?:&[A-Z]+)+|[A-Z]{2,${ACRONYM_MAX}})`;
|
|
@@ -274,9 +272,10 @@ const outsideSpans = (hits: readonly AcronymHit[], spans: readonly Span[]): Acro
|
|
|
274
272
|
/**
|
|
275
273
|
* どこか 1 か所で展開してあればよい。初出が節の見出し代わりの語(「5.3. DPA.」)で、
|
|
276
274
|
* 展開がその直後の文にあることが契約書では普通にある。見るのは語として現れた所だけ(CISA の中の CI は見ない)。
|
|
275
|
+
* 複数形(Special Interest Groups (SIGs))の展開は、s の無い略語(SIG)の展開でもある。
|
|
277
276
|
*/
|
|
278
277
|
const isExpanded = (body: string, acronym: string, expandedAt: ExpandedAt): boolean =>
|
|
279
|
-
[...body.matchAll(new RegExp(`${EDGE_BEFORE}${acronym}
|
|
278
|
+
[...body.matchAll(new RegExp(`${EDGE_BEFORE}${acronym}s?${EDGE_AFTER}`, "gu"))].some((match) => expandedAt(body, match[0], match.index));
|
|
280
279
|
|
|
281
280
|
/**
|
|
282
281
|
* 見出しは文にならないので、見出しの中の展開(Maximum Envelope of Water (MEOW) runs)は見出しの文字列で探す。
|
|
@@ -287,35 +286,13 @@ const expandsInHeading = (heading: string, acronym: string, expandedAt: Expanded
|
|
|
287
286
|
|
|
288
287
|
const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
|
|
289
288
|
|
|
290
|
-
const notationOf = (doc: ProseDocument): NotAcronymSpans =>
|
|
291
|
-
const notation = notAcronymSpansOf({
|
|
292
|
-
meridiem: patternsOf(doc, "meridiem"),
|
|
293
|
-
timeZones: patternsOf(doc, "time-zone"),
|
|
294
|
-
currencies: patternsOf(doc, "currency-code"),
|
|
295
|
-
usStates: patternsOf(doc, "us-state-code"),
|
|
296
|
-
emphasis: patternsOf(doc, "emphasis-word"),
|
|
297
|
-
divisions: patternsOf(doc, "numbered-division"),
|
|
298
|
-
abbreviatedLabels: patternsOf(doc, "abbreviated-label"),
|
|
299
|
-
honorifics: patternsOf(doc, "honorific"),
|
|
300
|
-
titles: patternsOf(doc, "name-title"),
|
|
301
|
-
dateTimeUnits: patternsOf(doc, "date-time-unit"),
|
|
302
|
-
});
|
|
303
|
-
const names = nameSpansOf({
|
|
304
|
-
legalForms: patternsOf(doc, "legal-form"),
|
|
305
|
-
determiners: patternsOf(doc, "name-determiner"),
|
|
306
|
-
citationSeries: patternsOf(doc, "citation-series"),
|
|
307
|
-
carriers: patternsOf(doc, "carrier-name"),
|
|
308
|
-
namePrefixes: patternsOf(doc, "name-prefix"),
|
|
309
|
-
streetSuffixes: patternsOf(doc, "street-suffix"),
|
|
310
|
-
capitalPhrases: patternsOf(doc, "capital-phrase"),
|
|
311
|
-
});
|
|
312
|
-
return (text) => [...notation(text), ...names(text)];
|
|
313
|
-
};
|
|
289
|
+
const notationOf = (doc: ProseDocument): NotAcronymSpans => lexiconNotationOf((id) => patternsOf(doc, id));
|
|
314
290
|
|
|
315
|
-
/**
|
|
316
|
-
const
|
|
291
|
+
/** 定義の語。定義の動詞は、語彙表の形(という)と、この文書で活用して書かれた形(といいます)の両方で照らす。 */
|
|
292
|
+
const definitionWordsOf = (doc: ProseDocument): DefinitionWords => {
|
|
317
293
|
const verbs = patternsOf(doc, "definition-verb");
|
|
318
|
-
|
|
294
|
+
const alternatives = patternsOf(doc, "definition-alternative");
|
|
295
|
+
return { markers: patternsOf(doc, "definition-marker"), verbs: [...verbs, ...conjugatedForms(doc.sentences, verbs)], alternatives };
|
|
319
296
|
};
|
|
320
297
|
|
|
321
298
|
const acronymFinding = (acronym: string, hit: Hit, count: number, limit: number): Finding => ({
|
|
@@ -340,32 +317,37 @@ export const undefinedAcronym: Detector = (doc, options): Finding[] => {
|
|
|
340
317
|
const body = bodyOf(doc);
|
|
341
318
|
// HTTP のメソッド名(GET)は略語ではなく、税の名前(VAT、GST)は読み手が名前として知るので、通じる略語と同じく展開を求めない。
|
|
342
319
|
// 並べた名前(JAXA)も、繋いだ略語(JAXA-ISAS)の片割れとして説明済みに数える。
|
|
320
|
+
// 文書が自分で知らせた語(select を書いた文書の SELECT、リンクで引いた講演の場 [Jane Roe, FOSDEM 2024](…))も同じ。
|
|
343
321
|
const common = new Set([
|
|
344
322
|
...(options.lexicon ?? []).map((entry) => entry.pattern),
|
|
345
|
-
...patternsOf(doc, "http-method"),
|
|
346
|
-
...patternsOf(doc, "tax-code"),
|
|
323
|
+
...knownByDocument(doc.source, doc.links).concat(patternsOf(doc, "http-method"), patternsOf(doc, "tax-code")),
|
|
347
324
|
...(doc.names ?? []),
|
|
348
325
|
]);
|
|
349
|
-
const expandedAt = expansionAt(
|
|
326
|
+
const expandedAt = expansionAt(definitionWordsOf(doc));
|
|
350
327
|
const stated = statedAcronyms(doc.source, { statements: patternsOf(doc, "definition-statement"), markers: patternsOf(doc, "definition-marker") });
|
|
351
328
|
const entries = new Set([...termEntryAcronyms(doc.source), ...stated]);
|
|
352
329
|
const headings = doc.sections.map((section) => section.heading);
|
|
353
330
|
const explainedAlone = (word: string): boolean =>
|
|
354
331
|
common.has(word) || entries.has(word) || isExpanded(body, word, expandedAt) || headings.some((heading) => expandsInHeading(heading, word, expandedAt));
|
|
355
|
-
const
|
|
332
|
+
const counted = outsideSpans(acronymsOf(doc, notationOf(doc)), [
|
|
356
333
|
...referenceListSpans(doc.source, patternsOf(doc, "reference-list-heading")),
|
|
357
334
|
...outlineLabelSpans(doc.source, patternsOf(doc, "numbered-division")),
|
|
358
335
|
]);
|
|
336
|
+
// リンク先のページの題名の略語([NASA Fprime AI Policy](https://…))は、読み手が出会う説明の無い略語として数に入れるが、
|
|
337
|
+
// 書き手が直せないので指さない。
|
|
338
|
+
const hits = outsideSpans(counted, linkTitleSpans(doc.source, doc.links));
|
|
359
339
|
const acronyms = [...firstHits(hits).keys()];
|
|
360
340
|
const unexplained = new Set(acronyms.filter((acronym) => !isExplained(acronym, explainedAlone)));
|
|
341
|
+
const quoted = [...firstHits(counted).keys()].filter((acronym) => !acronyms.includes(acronym) && !isExplained(acronym, explainedAlone)).length;
|
|
361
342
|
const bracketed = (acronym: string): boolean => [body, ...headings].some((text) => isBracketed(text, acronym));
|
|
362
343
|
// 定義の一覧("SOW" means …)で定義する書き手も、略語を展開する書き手と数える。
|
|
363
344
|
const definedByWriter = (acronym: string): boolean => bracketed(acronym) || stated.has(acronym);
|
|
364
345
|
const writerSpellsOut = acronyms.filter((acronym) => !common.has(acronym) && explainedAlone(acronym) && definedByWriter(acronym)).length >= options.limit;
|
|
365
346
|
// 日付を読むには文書の木を作る。上限に届かない文書では作らない。
|
|
366
|
-
if (unexplained.size < options.limit && !writerSpellsOut) return [];
|
|
347
|
+
if (unexplained.size + quoted < options.limit && !writerSpellsOut) return [];
|
|
367
348
|
const bare = [...firstHits(outsideSpans(hits, dateSpans(doc)))].filter(([acronym]) => unexplained.has(acronym));
|
|
368
|
-
|
|
349
|
+
const met = bare.length + quoted;
|
|
350
|
+
if (met >= options.limit) return bare.map(([acronym, hit]) => acronymFinding(acronym, hit, met, options.limit));
|
|
369
351
|
if (!writerSpellsOut) return [];
|
|
370
352
|
const alone = bare.filter(([acronym, hit]) => !isNamePartAt(acronym, hit) && !isInHeading(headings, acronym));
|
|
371
353
|
return alone.map(([acronym, hit]) => acronymFinding(acronym, hit, alone.length, options.limit));
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Detector, Finding, ProseDocument, StructureNode } from "../plugin.ts";
|
|
2
2
|
import { danglingReferences, duplicateDefinitions, inDocumentOrder, type StructureIssue } from "../structure/issues.ts";
|
|
3
3
|
import { numberingBreaks } from "../structure/numbering.ts";
|
|
4
|
+
import { attachedPartStarts } from "../structure/attached-parts.ts";
|
|
5
|
+
import { sideStepReader } from "../structure/side-step.ts";
|
|
4
6
|
import { htmlTextBlocks } from "../structure/html-text-blocks.ts";
|
|
5
7
|
import { listsNumberBreaks } from "../structure/list-numbering.ts";
|
|
6
8
|
import { weekdayMismatches } from "../structure/weekday.ts";
|
|
@@ -9,6 +11,7 @@ import { dateOrderBreaks } from "../structure/date-order.ts";
|
|
|
9
11
|
import { totalMismatches, type Amount } from "../structure/total.ts";
|
|
10
12
|
import { isListedTotal, isPeriodTotalLine, isTotalLikeLine, isTotalLine } from "../structure/total-line.ts";
|
|
11
13
|
import { proseTotalMismatches } from "../structure/prose-total.ts";
|
|
14
|
+
import { proseTotalWordsOf } from "./prose-total-words.ts";
|
|
12
15
|
import { countedAmounts, type SummedCounter } from "../structure/counted-amounts.ts";
|
|
13
16
|
import { measuredAmounts, type MeasureMarks, type SummedMeasure } from "../structure/measured-amounts.ts";
|
|
14
17
|
import { withCompoundHours } from "../structure/compound-hours.ts";
|
|
@@ -41,7 +44,7 @@ const findingsOf =
|
|
|
41
44
|
doc.structure === undefined
|
|
42
45
|
? []
|
|
43
46
|
: issuesOf(doc.structure, doc.source).map((issue) => ({
|
|
44
|
-
rule,
|
|
47
|
+
...(issue.variant === undefined ? { rule } : { rule, variant: issue.variant }),
|
|
45
48
|
severity: "error",
|
|
46
49
|
line: 0,
|
|
47
50
|
column: 0,
|
|
@@ -52,8 +55,11 @@ const findingsOf =
|
|
|
52
55
|
export const danglingReference: Detector = (doc, options) =>
|
|
53
56
|
findingsOf("dangling-reference", (tree, source) => danglingReferences(tree, source, patternsOf(doc, "section-name-noun")))(doc, options);
|
|
54
57
|
/** Markdown の HTML ブロックの中の条は木に入らない。そこを挟んだ抜けは、見えなかった番号かもしれない。 */
|
|
55
|
-
const structureNumberingGap: Detector = (doc, options) =>
|
|
56
|
-
|
|
58
|
+
const structureNumberingGap: Detector = (doc, options) => {
|
|
59
|
+
const isSideStep = sideStepReader(patternsOf(doc, "side-step-label"));
|
|
60
|
+
const hiddenBlocks = (source: string) => (doc.markup?.markdown === true ? htmlTextBlocks(source) : []);
|
|
61
|
+
return findingsOf("numbering-gap", (tree, source) => numberingBreaks(tree, hiddenBlocks(source), isSideStep))(doc, options);
|
|
62
|
+
};
|
|
57
63
|
|
|
58
64
|
const lineStartAt = (source: string, offset: number): number => source.lastIndexOf("\n", offset - 1) + 1;
|
|
59
65
|
|
|
@@ -90,7 +96,10 @@ export const numberingGap: Detector = (doc, options): Finding[] => {
|
|
|
90
96
|
(left, right) => Number(left.values["offset"]) - Number(right.values["offset"]),
|
|
91
97
|
);
|
|
92
98
|
};
|
|
93
|
-
export const duplicateDefinition: Detector =
|
|
99
|
+
export const duplicateDefinition: Detector = (doc, options) => {
|
|
100
|
+
const labels = patternsOf(doc, "attached-instrument-label");
|
|
101
|
+
return findingsOf("duplicate-definition", (tree, source) => duplicateDefinitions(tree, attachedPartStarts(source, labels)))(doc, options);
|
|
102
|
+
};
|
|
94
103
|
|
|
95
104
|
/** 曜日の名前は言語パッケージの語彙表(weekday、日曜日から順)から取る。無ければ番号のまま。 */
|
|
96
105
|
const dayName = (doc: ProseDocument, day: unknown): string => {
|
|
@@ -262,20 +271,11 @@ const totalIssues = (doc: ProseDocument, tree: NonNullable<ProseDocument["struct
|
|
|
262
271
|
(text) => isPeriodTotalLine(text, words),
|
|
263
272
|
{ isListed: (text) => isListedTotal(text, words), isTotalLike: (text, header) => isTotalLikeLine(text, words, header) },
|
|
264
273
|
);
|
|
265
|
-
const phrases = {
|
|
266
|
-
totals: patternsOf(doc, "total-phrase"),
|
|
267
|
-
breakdowns: patternsOf(doc, "breakdown-phrase"),
|
|
268
|
-
discounts: patternsOf(doc, "discount-word"),
|
|
269
|
-
joiners: patternsOf(doc, "breakdown-gap-joiner"),
|
|
270
|
-
leads: patternsOf(doc, "total-breakdown-lead"),
|
|
271
|
-
partials: patternsOf(doc, "breakdown-partial-word"),
|
|
272
|
-
backReferences: patternsOf(doc, "total-back-reference"),
|
|
273
|
-
};
|
|
274
274
|
const prose = proseTotalMismatches(
|
|
275
275
|
doc.source,
|
|
276
276
|
doc.sentences.map((sentence) => sentence.span),
|
|
277
277
|
amounts,
|
|
278
|
-
|
|
278
|
+
proseTotalWordsOf(doc),
|
|
279
279
|
);
|
|
280
280
|
return [...lines, ...prose.filter((issue) => !lines.some((line) => line.offset === issue.offset))];
|
|
281
281
|
};
|
|
@@ -138,7 +138,8 @@ const withoutDateStamps = (doc: ProseDocument, paragraphs: readonly Paragraph[])
|
|
|
138
138
|
export const preambleLength: Detector = (doc, options): Finding[] => {
|
|
139
139
|
const body = bodySectionOf(doc.sections);
|
|
140
140
|
if (body === undefined) return [];
|
|
141
|
-
const
|
|
141
|
+
const noteMarks = (doc.lexicons["note-mark"] ?? []).map((entry) => entry.pattern);
|
|
142
|
+
const all = preambleParagraphs(doc.paragraphs, body.span.start, doc.source, noteMarks);
|
|
142
143
|
if (all.length <= options.limit) return [];
|
|
143
144
|
const before = withoutDateStamps(doc, all);
|
|
144
145
|
if (before.length <= options.limit) return [];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// A line under a heading that gives the name of what the heading is about, not a sentence restating it: the label of a
|
|
2
|
+
// link or an attachment the heading introduces (### 実施要綱について → 実施要綱), or a list named after the heading
|
|
3
|
+
// (## 皆さんの声 → 「皆さんの声」一覧). A converted page keeps such labels as plain lines. Pure.
|
|
4
|
+
import { isContent } from "./content-morphemes.ts";
|
|
5
|
+
import type { Token } from "../plugin.ts";
|
|
6
|
+
|
|
7
|
+
/** A title is made of these: names, the words that build a name (annual, の, of, and), no predicate. */
|
|
8
|
+
const TITLE_POS: ReadonlySet<string> = new Set(["NOUN", "PROPN", "NUM", "PUNCT", "SYM", "X", "ADJ", "ADP", "DET", "CCONJ"]);
|
|
9
|
+
/** A line that ends like a sentence says something, whatever its words. */
|
|
10
|
+
const SENTENCE_END = /[。..!?!?]$/u;
|
|
11
|
+
|
|
12
|
+
const isTitle = (tokens: readonly Token[]): boolean => tokens.some(isContent) && tokens.every((token) => TITLE_POS.has(token.pos));
|
|
13
|
+
|
|
14
|
+
const baseForm = (token: Token): string => (token.lemma ?? token.surface).toLowerCase();
|
|
15
|
+
|
|
16
|
+
/** Brackets a line quotes a title in. */
|
|
17
|
+
const QUOTES: readonly (readonly [string, string])[] = [
|
|
18
|
+
["「", "」"],
|
|
19
|
+
["『", "』"],
|
|
20
|
+
["“", "”"],
|
|
21
|
+
['"', '"'],
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
type Span = { readonly start: number; readonly end: number };
|
|
25
|
+
|
|
26
|
+
/** Where the line quotes the whole heading as a title, in the tokens' coordinates. */
|
|
27
|
+
const quotedHeading = (heading: string, line: string, lineStart: number): Span | undefined => {
|
|
28
|
+
const quoted = QUOTES.map(([open, close]) => `${open}${heading}${close}`).find((form) => line.includes(form));
|
|
29
|
+
if (quoted === undefined) return undefined;
|
|
30
|
+
const start = lineStart + line.indexOf(quoted);
|
|
31
|
+
return { start, end: start + quoted.length };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** 「見出し」一覧: the heading quoted as a title, and only a name after it that says what the line is (一覧, page). */
|
|
35
|
+
const namesListAfterHeading = (outside: readonly Token[]): boolean => isTitle(outside);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 実施要綱 under ### 実施要綱について: the line is a title, and what the heading has beyond it only frames the name (について,
|
|
39
|
+
* About, 紹介). A line that copies the heading whole (### 研究科 → 研究科) is a repeat, and one that drops a word of the
|
|
40
|
+
* heading's own (### 精算方法の概要 → 精算方法) does not name the heading's subject.
|
|
41
|
+
*/
|
|
42
|
+
const namesHeadingTopic = (heading: readonly Token[], line: readonly Token[], announcing: ReadonlySet<string>): boolean => {
|
|
43
|
+
if (!isTitle(line)) return false;
|
|
44
|
+
const named = new Set(line.map(baseForm));
|
|
45
|
+
const beyond = heading.filter((token) => token.pos !== "PUNCT" && !named.has(baseForm(token)));
|
|
46
|
+
return beyond.length > 0 && beyond.every((token) => !isContent(token) || announcing.has(baseForm(token)));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The first line under a heading names what the heading is about. `heading` is the heading's text without its number
|
|
51
|
+
* label, `headingTokens` its tokens; `lineTokens` are the line's, in the coordinates `lineStart` gives. `announcing`
|
|
52
|
+
* holds the words that only frame a subject (the heading-announcer lexicon's ungrouped entries).
|
|
53
|
+
*/
|
|
54
|
+
export const namesHeadingSubject = (
|
|
55
|
+
heading: string,
|
|
56
|
+
headingTokens: readonly Token[],
|
|
57
|
+
line: string,
|
|
58
|
+
lineStart: number,
|
|
59
|
+
lineTokens: readonly Token[],
|
|
60
|
+
announcing: ReadonlySet<string>,
|
|
61
|
+
): boolean => {
|
|
62
|
+
if (line.trim().includes("\n") || SENTENCE_END.test(line.trim()) || heading.trim() === "") return false;
|
|
63
|
+
const quoted = quotedHeading(heading.trim(), line, lineStart);
|
|
64
|
+
if (quoted !== undefined) return namesListAfterHeading(lineTokens.filter((token) => token.span.start < quoted.start || token.span.start >= quoted.end));
|
|
65
|
+
return namesHeadingTopic(headingTokens, lineTokens, announcing);
|
|
66
|
+
};
|
|
@@ -53,7 +53,21 @@ const rawCells = (line: Line): { readonly raw: string; readonly from: number }[]
|
|
|
53
53
|
return inner.at(-1)?.raw.trim() === "" ? inner.slice(0, -1) : inner;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
/**
|
|
57
|
+
* An inline HTML tag in a cell (`<div style="…">`, `</div>`, `<br/>`): the reader sees none of it. A tag name ends at a space,
|
|
58
|
+
* a slash or `>`, so an autolink (`<https://…>`) is not one; an attribute in double quotes may hold a `>`.
|
|
59
|
+
*/
|
|
60
|
+
const HTML_TAG = /<\/?[A-Za-z][\w-]*(?:\s(?:"[^"]*"|[^<>"])*)?\/?>/gu;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The cell with its HTML tags blanked out, same length, so the words keep their offsets and the spaces around them trim.
|
|
64
|
+
* A cell with a code span is left whole: a tag written in code is text the reader sees.
|
|
65
|
+
*/
|
|
66
|
+
const withoutTags = (raw: string): string => (raw.includes("`") ? raw : raw.replace(HTML_TAG, (tag) => " ".repeat(tag.length)));
|
|
67
|
+
|
|
68
|
+
const labelCell = (line: Line, cell: { readonly raw: string; readonly from: number }): HeaderCell[] => {
|
|
69
|
+
const { from } = cell;
|
|
70
|
+
const raw = withoutTags(cell.raw);
|
|
57
71
|
const trimmed = raw.trim();
|
|
58
72
|
const unwrapped = unwrap(trimmed);
|
|
59
73
|
const written = unwrapped.replace(INNER_MARKS, "").trim();
|
|
@@ -6,6 +6,7 @@ import { codeFences, codeSpans, type CodeFence } from "./code-fences.ts";
|
|
|
6
6
|
import { opensAsNounPhrase } from "./nominal-step.ts";
|
|
7
7
|
import { quoteAt } from "./structure-tree.ts";
|
|
8
8
|
import { escapeRegExp } from "../orthography.ts";
|
|
9
|
+
import { isFormatTemplate } from "../format-template.ts";
|
|
9
10
|
import type { Detector, Finding, ProseDocument, Span, Token } from "../plugin.ts";
|
|
10
11
|
|
|
11
12
|
const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
|
|
@@ -25,6 +26,9 @@ const finding = (doc: ProseDocument, rule: string, offset: number, values: Reado
|
|
|
25
26
|
values: { ...values, offset },
|
|
26
27
|
});
|
|
27
28
|
|
|
29
|
+
/** A fence that should name a language: an untagged format template (<MAJOR>.<MINOR>) is in none, so it is left out. */
|
|
30
|
+
const wantsLanguage = (fence: CodeFence): boolean => fence.language !== "" || !isFormatTemplate(fence.lines);
|
|
31
|
+
|
|
28
32
|
/** Fences without a language, when they are the fewer kind: a document that mostly leaves the language out is not reported. */
|
|
29
33
|
export const untaggedFewer = (fences: readonly CodeFence[], limit: number): readonly CodeFence[] => {
|
|
30
34
|
const untagged = fences.filter((fence) => fence.language === "");
|
|
@@ -33,7 +37,7 @@ export const untaggedFewer = (fences: readonly CodeFence[], limit: number): read
|
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
export const codeFenceLanguage: Detector = (doc, options): Finding[] => {
|
|
36
|
-
const fences = codeFences(doc.source);
|
|
40
|
+
const fences = codeFences(doc.source).filter(wantsLanguage);
|
|
37
41
|
const tagged = fences.filter((fence) => fence.language !== "").length;
|
|
38
42
|
return untaggedFewer(fences, options.limit).map((fence) =>
|
|
39
43
|
finding(doc, "code-fence-language-mix", fence.start, { tagged, untagged: fences.length - tagged }),
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
2
|
+
import type { Sentence } from "../plugin.ts";
|
|
3
|
+
|
|
4
|
+
// An entry of a definitions list opens with the term it defines, in quotes ("Capital Contributions" The capital
|
|
5
|
+
// contribution to the Venture …). The words after the quoted name are the definition's own body, not uses of the term.
|
|
6
|
+
// Pure.
|
|
7
|
+
|
|
8
|
+
/** The ending a quoted name may carry past the term: a plural or a possessive (Contributions, Contribution's). */
|
|
9
|
+
const ENDING = String.raw`(?:e?s|['’]s)?`;
|
|
10
|
+
/** The label of a list item before the entry (a., (b), 1., iv)). */
|
|
11
|
+
const ITEM_LABEL = String.raw`(?:\(?[\p{L}\p{N}]{1,4}[.)]\s+)?`;
|
|
12
|
+
/** The quotes a term is named in, each with its own closing mark. */
|
|
13
|
+
const QUOTE_PAIRS = [
|
|
14
|
+
['"', '"'],
|
|
15
|
+
["“", "”"],
|
|
16
|
+
["「", "」"],
|
|
17
|
+
["『", "』"],
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
const entryHead = (term: string): RegExp => {
|
|
21
|
+
const quoted = QUOTE_PAIRS.map(([open, close]) => `${open}${escapeRegExp(term)}${ENDING}${close}`).join("|");
|
|
22
|
+
return new RegExp(`^\\s*${ITEM_LABEL}(?:${quoted})`, "u");
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Whether the sentence holding offset is a definitions entry that opens with the term in quotes, and offset is after that name. */
|
|
26
|
+
export const inEntryOfTerm = (sentences: readonly Sentence[], term: string, offset: number): boolean => {
|
|
27
|
+
const sentence = sentences.find((candidate) => candidate.span.start <= offset && offset < candidate.span.end);
|
|
28
|
+
if (sentence === undefined) return false;
|
|
29
|
+
const head = entryHead(term).exec(sentence.text);
|
|
30
|
+
return head !== null && offset - sentence.span.start >= head[0].length;
|
|
31
|
+
};
|