chaffjs 0.30.0 → 0.31.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/dist/announced-count.d.ts +2 -0
- package/dist/announced-count.d.ts.map +1 -1
- package/dist/announced-count.js +4 -3
- package/dist/announced-count.js.map +1 -1
- package/dist/contacts/addresses.d.ts +21 -0
- package/dist/contacts/addresses.d.ts.map +1 -0
- package/dist/contacts/addresses.js +144 -0
- package/dist/contacts/addresses.js.map +1 -0
- package/dist/contacts/emails.d.ts +11 -0
- package/dist/contacts/emails.d.ts.map +1 -0
- package/dist/contacts/emails.js +51 -0
- package/dist/contacts/emails.js.map +1 -0
- package/dist/contacts/variants.d.ts +14 -0
- package/dist/contacts/variants.d.ts.map +1 -0
- package/dist/contacts/variants.js +25 -0
- package/dist/contacts/variants.js.map +1 -0
- package/dist/derived/battery-runtime.d.ts +85 -0
- package/dist/derived/battery-runtime.d.ts.map +1 -0
- package/dist/derived/battery-runtime.js +217 -0
- package/dist/derived/battery-runtime.js.map +1 -0
- package/dist/derived/period-counts.d.ts +48 -0
- package/dist/derived/period-counts.d.ts.map +1 -0
- package/dist/derived/period-counts.js +128 -0
- package/dist/derived/period-counts.js.map +1 -0
- package/dist/derived/time-lengths.d.ts.map +1 -1
- package/dist/derived/time-lengths.js +12 -9
- package/dist/derived/time-lengths.js.map +1 -1
- package/dist/derived/use-interval.d.ts +33 -0
- package/dist/derived/use-interval.d.ts.map +1 -0
- package/dist/derived/use-interval.js +93 -0
- package/dist/derived/use-interval.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/capacity-runtime.d.ts +7 -0
- package/dist/detectors/capacity-runtime.d.ts.map +1 -0
- package/dist/detectors/capacity-runtime.js +98 -0
- package/dist/detectors/capacity-runtime.js.map +1 -0
- package/dist/detectors/contact-variant.d.ts +3 -0
- package/dist/detectors/contact-variant.d.ts.map +1 -0
- package/dist/detectors/contact-variant.js +21 -0
- package/dist/detectors/contact-variant.js.map +1 -0
- package/dist/detectors/count-over-capacity.d.ts +4 -0
- package/dist/detectors/count-over-capacity.d.ts.map +1 -0
- package/dist/detectors/count-over-capacity.js +26 -0
- package/dist/detectors/count-over-capacity.js.map +1 -0
- package/dist/detectors/date-outside-period.d.ts.map +1 -1
- package/dist/detectors/date-outside-period.js +2 -1
- package/dist/detectors/date-outside-period.js.map +1 -1
- package/dist/detectors/date-stamp-order.d.ts +3 -0
- package/dist/detectors/date-stamp-order.d.ts.map +1 -0
- package/dist/detectors/date-stamp-order.js +24 -0
- package/dist/detectors/date-stamp-order.js.map +1 -0
- package/dist/detectors/defined-term-form.d.ts.map +1 -1
- package/dist/detectors/defined-term-form.js +57 -7
- package/dist/detectors/defined-term-form.js.map +1 -1
- package/dist/detectors/definition-use.d.ts +1 -1
- package/dist/detectors/definition-use.d.ts.map +1 -1
- package/dist/detectors/definition-use.js +4 -2
- package/dist/detectors/definition-use.js.map +1 -1
- package/dist/detectors/derived-numbers.d.ts +9 -1
- package/dist/detectors/derived-numbers.d.ts.map +1 -1
- package/dist/detectors/derived-numbers.js +2 -2
- package/dist/detectors/derived-numbers.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/en-shape.d.ts.map +1 -1
- package/dist/detectors/en-shape.js +7 -4
- package/dist/detectors/en-shape.js.map +1 -1
- package/dist/detectors/event-deadline.d.ts +3 -0
- package/dist/detectors/event-deadline.d.ts.map +1 -0
- package/dist/detectors/event-deadline.js +24 -0
- package/dist/detectors/event-deadline.js.map +1 -0
- package/dist/detectors/fact-consistency.d.ts +1 -1
- package/dist/detectors/fact-consistency.d.ts.map +1 -1
- package/dist/detectors/fact-consistency.js +52 -3
- package/dist/detectors/fact-consistency.js.map +1 -1
- package/dist/detectors/heading-case.d.ts +5 -2
- package/dist/detectors/heading-case.d.ts.map +1 -1
- package/dist/detectors/heading-case.js +12 -4
- package/dist/detectors/heading-case.js.map +1 -1
- package/dist/detectors/heading-echo.d.ts +5 -0
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +14 -1
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/layout-code.d.ts +5 -0
- package/dist/detectors/layout-code.d.ts.map +1 -0
- package/dist/detectors/layout-code.js +124 -0
- package/dist/detectors/layout-code.js.map +1 -0
- package/dist/detectors/measured-facts.d.ts +8 -0
- package/dist/detectors/measured-facts.d.ts.map +1 -0
- package/dist/detectors/measured-facts.js +18 -0
- package/dist/detectors/measured-facts.js.map +1 -0
- package/dist/detectors/name-variant-model-codes.d.ts +11 -0
- package/dist/detectors/name-variant-model-codes.d.ts.map +1 -0
- package/dist/detectors/name-variant-model-codes.js +21 -0
- package/dist/detectors/name-variant-model-codes.js.map +1 -0
- package/dist/detectors/name-variant.d.ts.map +1 -1
- package/dist/detectors/name-variant.js +25 -4
- package/dist/detectors/name-variant.js.map +1 -1
- package/dist/detectors/orthographic-variant.d.ts.map +1 -1
- package/dist/detectors/orthographic-variant.js +62 -7
- package/dist/detectors/orthographic-variant.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +12 -6
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/quantity-range.d.ts +3 -0
- package/dist/detectors/quantity-range.d.ts.map +1 -0
- package/dist/detectors/quantity-range.js +35 -0
- package/dist/detectors/quantity-range.js.map +1 -0
- package/dist/detectors/range-band.d.ts +5 -0
- package/dist/detectors/range-band.d.ts.map +1 -0
- package/dist/detectors/range-band.js +80 -0
- package/dist/detectors/range-band.js.map +1 -0
- package/dist/detectors/registry/capacity-runtime-mismatch.d.ts +3 -0
- package/dist/detectors/registry/capacity-runtime-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/capacity-runtime-mismatch.js +3 -0
- package/dist/detectors/registry/capacity-runtime-mismatch.js.map +1 -0
- package/dist/detectors/registry/contact-variant.d.ts +3 -0
- package/dist/detectors/registry/contact-variant.d.ts.map +1 -0
- package/dist/detectors/registry/contact-variant.js +3 -0
- package/dist/detectors/registry/contact-variant.js.map +1 -0
- package/dist/detectors/registry/count-over-capacity.d.ts +3 -0
- package/dist/detectors/registry/count-over-capacity.d.ts.map +1 -0
- package/dist/detectors/registry/count-over-capacity.js +3 -0
- package/dist/detectors/registry/count-over-capacity.js.map +1 -0
- package/dist/detectors/registry/date-stamp-order.d.ts +3 -0
- package/dist/detectors/registry/date-stamp-order.d.ts.map +1 -0
- package/dist/detectors/registry/date-stamp-order.js +3 -0
- package/dist/detectors/registry/date-stamp-order.js.map +1 -0
- package/dist/detectors/registry/event-deadline.d.ts +3 -0
- package/dist/detectors/registry/event-deadline.d.ts.map +1 -0
- package/dist/detectors/registry/event-deadline.js +3 -0
- package/dist/detectors/registry/event-deadline.js.map +1 -0
- package/dist/detectors/registry/interval-count-mismatch.d.ts +3 -0
- package/dist/detectors/registry/interval-count-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/interval-count-mismatch.js +3 -0
- package/dist/detectors/registry/interval-count-mismatch.js.map +1 -0
- package/dist/detectors/registry/layout-code-mismatch.d.ts +3 -0
- package/dist/detectors/registry/layout-code-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/layout-code-mismatch.js +3 -0
- package/dist/detectors/registry/layout-code-mismatch.js.map +1 -0
- package/dist/detectors/registry/quantity-range.d.ts +3 -0
- package/dist/detectors/registry/quantity-range.d.ts.map +1 -0
- package/dist/detectors/registry/quantity-range.js +3 -0
- package/dist/detectors/registry/quantity-range.js.map +1 -0
- package/dist/detectors/registry/range-band-mismatch.d.ts +3 -0
- package/dist/detectors/registry/range-band-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/range-band-mismatch.js +3 -0
- package/dist/detectors/registry/range-band-mismatch.js.map +1 -0
- package/dist/detectors/registry/rent-multiple-mismatch.d.ts +3 -0
- package/dist/detectors/registry/rent-multiple-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/rent-multiple-mismatch.js +3 -0
- package/dist/detectors/registry/rent-multiple-mismatch.js.map +1 -0
- package/dist/detectors/registry/scaled-quantity-mismatch.d.ts +3 -0
- package/dist/detectors/registry/scaled-quantity-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/scaled-quantity-mismatch.js +3 -0
- package/dist/detectors/registry/scaled-quantity-mismatch.js.map +1 -0
- package/dist/detectors/registry/step-time-sum-mismatch.d.ts +3 -0
- package/dist/detectors/registry/step-time-sum-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/step-time-sum-mismatch.js +3 -0
- package/dist/detectors/registry/step-time-sum-mismatch.js.map +1 -0
- package/dist/detectors/registry/time-range-reversed.d.ts +3 -0
- package/dist/detectors/registry/time-range-reversed.d.ts.map +1 -0
- package/dist/detectors/registry/time-range-reversed.js +3 -0
- package/dist/detectors/registry/time-range-reversed.js.map +1 -0
- package/dist/detectors/registry/unlisted-item-used.d.ts +3 -0
- package/dist/detectors/registry/unlisted-item-used.d.ts.map +1 -0
- package/dist/detectors/registry/unlisted-item-used.js +3 -0
- package/dist/detectors/registry/unlisted-item-used.js.map +1 -0
- package/dist/detectors/registry/walk-time-distance-mismatch.d.ts +3 -0
- package/dist/detectors/registry/walk-time-distance-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/walk-time-distance-mismatch.js +3 -0
- package/dist/detectors/registry/walk-time-distance-mismatch.js.map +1 -0
- package/dist/detectors/rent-multiple-mismatch.d.ts +3 -0
- package/dist/detectors/rent-multiple-mismatch.d.ts.map +1 -0
- package/dist/detectors/rent-multiple-mismatch.js +39 -0
- package/dist/detectors/rent-multiple-mismatch.js.map +1 -0
- package/dist/detectors/scaled-quantity.d.ts +3 -0
- package/dist/detectors/scaled-quantity.d.ts.map +1 -0
- package/dist/detectors/scaled-quantity.js +37 -0
- package/dist/detectors/scaled-quantity.js.map +1 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +3 -1
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/step-time-sum.d.ts +3 -0
- package/dist/detectors/step-time-sum.d.ts.map +1 -0
- package/dist/detectors/step-time-sum.js +46 -0
- package/dist/detectors/step-time-sum.js.map +1 -0
- package/dist/detectors/structure-tree.d.ts +2 -0
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +22 -5
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/structure.js +1 -1
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/technical-docs.d.ts +5 -0
- package/dist/detectors/technical-docs.d.ts.map +1 -1
- package/dist/detectors/technical-docs.js +12 -0
- package/dist/detectors/technical-docs.js.map +1 -1
- package/dist/detectors/time-order.d.ts +1 -0
- package/dist/detectors/time-order.d.ts.map +1 -1
- package/dist/detectors/time-order.js +3 -1
- package/dist/detectors/time-order.js.map +1 -1
- package/dist/detectors/unit-consistency.d.ts +1 -1
- package/dist/detectors/unit-consistency.d.ts.map +1 -1
- package/dist/detectors/unit-consistency.js +46 -38
- package/dist/detectors/unit-consistency.js.map +1 -1
- package/dist/detectors/unlisted-items.d.ts +3 -0
- package/dist/detectors/unlisted-items.d.ts.map +1 -0
- package/dist/detectors/unlisted-items.js +57 -0
- package/dist/detectors/unlisted-items.js.map +1 -0
- package/dist/detectors/use-count-words.d.ts +8 -0
- package/dist/detectors/use-count-words.d.ts.map +1 -0
- package/dist/detectors/use-count-words.js +20 -0
- package/dist/detectors/use-count-words.js.map +1 -0
- package/dist/detectors/use-interval.d.ts +3 -0
- package/dist/detectors/use-interval.d.ts.map +1 -0
- package/dist/detectors/use-interval.js +39 -0
- package/dist/detectors/use-interval.js.map +1 -0
- package/dist/detectors/walk-time-distance-mismatch.d.ts +4 -0
- package/dist/detectors/walk-time-distance-mismatch.d.ts.map +1 -0
- package/dist/detectors/walk-time-distance-mismatch.js +38 -0
- package/dist/detectors/walk-time-distance-mismatch.js.map +1 -0
- package/dist/facts/approximate-tolerance.d.ts +7 -0
- package/dist/facts/approximate-tolerance.d.ts.map +1 -0
- package/dist/facts/approximate-tolerance.js +16 -0
- package/dist/facts/approximate-tolerance.js.map +1 -0
- package/dist/facts/item-amounts.d.ts +18 -0
- package/dist/facts/item-amounts.d.ts.map +1 -0
- package/dist/facts/item-amounts.js +67 -0
- package/dist/facts/item-amounts.js.map +1 -0
- package/dist/facts/labelled-facts.d.ts +4 -0
- package/dist/facts/labelled-facts.d.ts.map +1 -1
- package/dist/facts/labelled-facts.js +21 -6
- package/dist/facts/labelled-facts.js.map +1 -1
- package/dist/facts/measure-units.d.ts +5 -0
- package/dist/facts/measure-units.d.ts.map +1 -0
- package/dist/facts/measure-units.js +28 -0
- package/dist/facts/measure-units.js.map +1 -0
- package/dist/facts/measures.d.ts +23 -4
- package/dist/facts/measures.d.ts.map +1 -1
- package/dist/facts/measures.js +68 -19
- package/dist/facts/measures.js.map +1 -1
- package/dist/facts/retention-periods.d.ts +51 -0
- package/dist/facts/retention-periods.d.ts.map +1 -0
- package/dist/facts/retention-periods.js +148 -0
- package/dist/facts/retention-periods.js.map +1 -0
- package/dist/facts/unit-conflicts.d.ts +3 -2
- package/dist/facts/unit-conflicts.d.ts.map +1 -1
- package/dist/facts/unit-conflicts.js +15 -7
- package/dist/facts/unit-conflicts.js.map +1 -1
- package/dist/facts/unit-equivalents.d.ts +13 -0
- package/dist/facts/unit-equivalents.d.ts.map +1 -0
- package/dist/facts/unit-equivalents.js +56 -0
- package/dist/facts/unit-equivalents.js.map +1 -0
- package/dist/facts/unit-tolerance.d.ts +4 -0
- package/dist/facts/unit-tolerance.d.ts.map +1 -0
- package/dist/facts/unit-tolerance.js +13 -0
- package/dist/facts/unit-tolerance.js.map +1 -0
- package/dist/facts/unit-word.d.ts +8 -0
- package/dist/facts/unit-word.d.ts.map +1 -0
- package/dist/facts/unit-word.js +34 -0
- package/dist/facts/unit-word.js.map +1 -0
- package/dist/facts/written-precision.d.ts +10 -0
- package/dist/facts/written-precision.d.ts.map +1 -0
- package/dist/facts/written-precision.js +20 -0
- package/dist/facts/written-precision.js.map +1 -0
- package/dist/kana-spelling.d.ts +12 -0
- package/dist/kana-spelling.d.ts.map +1 -1
- package/dist/kana-spelling.js +23 -0
- package/dist/kana-spelling.js.map +1 -1
- package/dist/model-codes.d.ts +23 -0
- package/dist/model-codes.d.ts.map +1 -0
- package/dist/model-codes.js +81 -0
- package/dist/model-codes.js.map +1 -0
- package/dist/name-spelling-chars.d.ts +16 -0
- package/dist/name-spelling-chars.d.ts.map +1 -0
- package/dist/name-spelling-chars.js +14 -0
- package/dist/name-spelling-chars.js.map +1 -0
- package/dist/name-variants.d.ts +3 -2
- package/dist/name-variants.d.ts.map +1 -1
- package/dist/name-variants.js +4 -7
- package/dist/name-variants.js.map +1 -1
- package/dist/phone-numbers.d.ts.map +1 -1
- package/dist/phone-numbers.js +22 -5
- package/dist/phone-numbers.js.map +1 -1
- package/dist/place-names.d.ts +12 -5
- package/dist/place-names.d.ts.map +1 -1
- package/dist/place-names.js +34 -14
- package/dist/place-names.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 +2 -1
- package/dist/preamble-paragraphs.d.ts.map +1 -1
- package/dist/preamble-paragraphs.js +16 -1
- package/dist/preamble-paragraphs.js.map +1 -1
- package/dist/profile/parse.d.ts.map +1 -1
- package/dist/profile/parse.js +11 -0
- package/dist/profile/parse.js.map +1 -1
- package/dist/spacing-code.d.ts +6 -0
- package/dist/spacing-code.d.ts.map +1 -0
- package/dist/spacing-code.js +16 -0
- package/dist/spacing-code.js.map +1 -0
- package/dist/structure/amount-range.d.ts +2 -2
- package/dist/structure/amount-range.d.ts.map +1 -1
- package/dist/structure/amount-range.js +12 -5
- package/dist/structure/amount-range.js.map +1 -1
- package/dist/structure/capacity-count.d.ts +59 -0
- package/dist/structure/capacity-count.d.ts.map +1 -0
- package/dist/structure/capacity-count.js +118 -0
- package/dist/structure/capacity-count.js.map +1 -0
- package/dist/structure/counted-amounts.d.ts +6 -0
- package/dist/structure/counted-amounts.d.ts.map +1 -1
- package/dist/structure/counted-amounts.js +4 -4
- package/dist/structure/counted-amounts.js.map +1 -1
- package/dist/structure/date-outside-period.d.ts +3 -1
- package/dist/structure/date-outside-period.d.ts.map +1 -1
- package/dist/structure/date-outside-period.js +8 -5
- package/dist/structure/date-outside-period.js.map +1 -1
- package/dist/structure/date-range.d.ts +1 -0
- package/dist/structure/date-range.d.ts.map +1 -1
- package/dist/structure/date-range.js +1 -1
- package/dist/structure/date-range.js.map +1 -1
- package/dist/structure/deadline-after-event.d.ts +23 -0
- package/dist/structure/deadline-after-event.d.ts.map +1 -0
- package/dist/structure/deadline-after-event.js +42 -0
- package/dist/structure/deadline-after-event.js.map +1 -0
- package/dist/structure/definition-use.d.ts +1 -1
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +55 -2
- package/dist/structure/definition-use.js.map +1 -1
- package/dist/structure/due-date.d.ts.map +1 -1
- package/dist/structure/due-date.js +5 -27
- package/dist/structure/due-date.js.map +1 -1
- package/dist/structure/labelled-date-order.d.ts +38 -0
- package/dist/structure/labelled-date-order.d.ts.map +1 -0
- package/dist/structure/labelled-date-order.js +41 -0
- package/dist/structure/labelled-date-order.js.map +1 -0
- package/dist/structure/layout-codes.d.ts +68 -0
- package/dist/structure/layout-codes.d.ts.map +1 -0
- package/dist/structure/layout-codes.js +161 -0
- package/dist/structure/layout-codes.js.map +1 -0
- package/dist/structure/measured-amounts.d.ts +17 -0
- package/dist/structure/measured-amounts.d.ts.map +1 -0
- package/dist/structure/measured-amounts.js +110 -0
- package/dist/structure/measured-amounts.js.map +1 -0
- package/dist/structure/quantity-range.d.ts +8 -0
- package/dist/structure/quantity-range.d.ts.map +1 -0
- package/dist/structure/quantity-range.js +36 -0
- package/dist/structure/quantity-range.js.map +1 -0
- package/dist/structure/range-bands.d.ts +75 -0
- package/dist/structure/range-bands.d.ts.map +1 -0
- package/dist/structure/range-bands.js +244 -0
- package/dist/structure/range-bands.js.map +1 -0
- package/dist/structure/rent-multiple.d.ts +76 -0
- package/dist/structure/rent-multiple.d.ts.map +1 -0
- package/dist/structure/rent-multiple.js +186 -0
- package/dist/structure/rent-multiple.js.map +1 -0
- package/dist/structure/scaled-quantities.d.ts +50 -0
- package/dist/structure/scaled-quantities.d.ts.map +1 -0
- package/dist/structure/scaled-quantities.js +153 -0
- package/dist/structure/scaled-quantities.js.map +1 -0
- package/dist/structure/stamp-order.d.ts +16 -0
- package/dist/structure/stamp-order.d.ts.map +1 -0
- package/dist/structure/stamp-order.js +78 -0
- package/dist/structure/stamp-order.js.map +1 -0
- package/dist/structure/step-times.d.ts +49 -0
- package/dist/structure/step-times.d.ts.map +1 -0
- package/dist/structure/step-times.js +128 -0
- package/dist/structure/step-times.js.map +1 -0
- package/dist/structure/term-deadline.d.ts +19 -0
- package/dist/structure/term-deadline.d.ts.map +1 -0
- package/dist/structure/term-deadline.js +28 -0
- package/dist/structure/term-deadline.js.map +1 -0
- package/dist/structure/time-range.d.ts +16 -0
- package/dist/structure/time-range.d.ts.map +1 -0
- package/dist/structure/time-range.js +57 -0
- package/dist/structure/time-range.js.map +1 -0
- package/dist/structure/total-line.d.ts +16 -0
- package/dist/structure/total-line.d.ts.map +1 -0
- package/dist/structure/total-line.js +44 -0
- package/dist/structure/total-line.js.map +1 -0
- package/dist/structure/total.d.ts +7 -1
- package/dist/structure/total.d.ts.map +1 -1
- package/dist/structure/total.js +28 -5
- package/dist/structure/total.js.map +1 -1
- package/dist/structure/unlisted-items.d.ts +70 -0
- package/dist/structure/unlisted-items.d.ts.map +1 -0
- package/dist/structure/unlisted-items.js +152 -0
- package/dist/structure/unlisted-items.js.map +1 -0
- package/dist/structure/walk-time.d.ts +87 -0
- package/dist/structure/walk-time.d.ts.map +1 -0
- package/dist/structure/walk-time.js +195 -0
- package/dist/structure/walk-time.js.map +1 -0
- package/package.json +3 -3
- package/profiles/listing.yaml +20 -0
- package/rules/announced-count-mismatch.yaml +2 -2
- package/rules/capacity-runtime-mismatch.yaml +66 -0
- package/rules/contact-variant.yaml +76 -0
- package/rules/count-over-capacity.yaml +55 -0
- package/rules/date-outside-period.yaml +4 -4
- package/rules/date-stamp-order.yaml +82 -0
- package/rules/deadline-after-event.yaml +67 -0
- package/rules/defined-name-repeated.yaml +2 -2
- package/rules/due-before-issue.yaml +11 -7
- package/rules/fact-conflict.yaml +9 -4
- package/rules/heading-echo.yaml +2 -2
- package/rules/interval-count-mismatch.yaml +54 -0
- package/rules/latin-spacing.yaml +2 -2
- package/rules/layout-code-mismatch.yaml +68 -0
- package/rules/name-variant.yaml +8 -2
- package/rules/no-em-dash.yaml +2 -2
- package/rules/preamble-length.yaml +2 -2
- package/rules/quantity-range-reversed.yaml +53 -0
- package/rules/range-band-mismatch.yaml +70 -0
- package/rules/rent-multiple-mismatch.yaml +61 -0
- package/rules/scaled-quantity-mismatch.yaml +69 -0
- package/rules/step-time-sum-mismatch.yaml +65 -0
- package/rules/time-range-reversed.yaml +48 -0
- package/rules/title-case-consistency.yaml +2 -2
- package/rules/total-mismatch.yaml +2 -2
- package/rules/unit-mismatch.yaml +12 -4
- package/rules/unlisted-item-used.yaml +90 -0
- package/rules/unused-definition.yaml +2 -2
- package/rules/use-before-definition.yaml +2 -2
- package/rules/walk-time-distance-mismatch.yaml +55 -0
- package/src/announced-count.ts +6 -3
- package/src/contacts/addresses.ts +179 -0
- package/src/contacts/emails.ts +63 -0
- package/src/contacts/variants.ts +33 -0
- package/src/derived/battery-runtime.ts +284 -0
- package/src/derived/period-counts.ts +178 -0
- package/src/derived/time-lengths.ts +12 -9
- package/src/derived/use-interval.ts +151 -0
- package/src/detectors/announced-count.ts +1 -0
- package/src/detectors/capacity-runtime.ts +128 -0
- package/src/detectors/contact-variant.ts +24 -0
- package/src/detectors/count-over-capacity.ts +37 -0
- package/src/detectors/date-outside-period.ts +2 -1
- package/src/detectors/date-stamp-order.ts +28 -0
- package/src/detectors/defined-term-form.ts +63 -7
- package/src/detectors/definition-use.ts +6 -2
- package/src/detectors/derived-numbers.ts +3 -3
- package/src/detectors/due-date.ts +10 -2
- package/src/detectors/en-shape.ts +11 -4
- package/src/detectors/event-deadline.ts +29 -0
- package/src/detectors/fact-consistency.ts +64 -3
- package/src/detectors/heading-case.ts +13 -4
- package/src/detectors/heading-echo.ts +17 -1
- package/src/detectors/layout-code.ts +174 -0
- package/src/detectors/measured-facts.ts +20 -0
- package/src/detectors/name-variant-model-codes.ts +27 -0
- package/src/detectors/name-variant.ts +32 -6
- package/src/detectors/orthographic-variant.ts +78 -9
- package/src/detectors/orthography.ts +16 -6
- package/src/detectors/quantity-range.ts +47 -0
- package/src/detectors/range-band.ts +125 -0
- package/src/detectors/registry/capacity-runtime-mismatch.ts +4 -0
- package/src/detectors/registry/contact-variant.ts +4 -0
- package/src/detectors/registry/count-over-capacity.ts +4 -0
- package/src/detectors/registry/date-stamp-order.ts +4 -0
- package/src/detectors/registry/event-deadline.ts +4 -0
- package/src/detectors/registry/interval-count-mismatch.ts +4 -0
- package/src/detectors/registry/layout-code-mismatch.ts +4 -0
- package/src/detectors/registry/quantity-range.ts +4 -0
- package/src/detectors/registry/range-band-mismatch.ts +4 -0
- package/src/detectors/registry/rent-multiple-mismatch.ts +4 -0
- package/src/detectors/registry/scaled-quantity-mismatch.ts +4 -0
- package/src/detectors/registry/step-time-sum-mismatch.ts +4 -0
- package/src/detectors/registry/time-range-reversed.ts +4 -0
- package/src/detectors/registry/unlisted-item-used.ts +4 -0
- package/src/detectors/registry/walk-time-distance-mismatch.ts +4 -0
- package/src/detectors/rent-multiple-mismatch.ts +56 -0
- package/src/detectors/scaled-quantity.ts +49 -0
- package/src/detectors/signals.ts +3 -1
- package/src/detectors/step-time-sum.ts +55 -0
- package/src/detectors/structure-tree.ts +30 -5
- package/src/detectors/structure.ts +1 -1
- package/src/detectors/technical-docs.ts +12 -0
- package/src/detectors/time-order.ts +5 -1
- package/src/detectors/unit-consistency.ts +50 -38
- package/src/detectors/unlisted-items.ts +72 -0
- package/src/detectors/use-count-words.ts +32 -0
- package/src/detectors/use-interval.ts +51 -0
- package/src/detectors/walk-time-distance-mismatch.ts +45 -0
- package/src/facts/approximate-tolerance.ts +19 -0
- package/src/facts/item-amounts.ts +94 -0
- package/src/facts/labelled-facts.ts +29 -7
- package/src/facts/measure-units.ts +31 -0
- package/src/facts/measures.ts +113 -25
- package/src/facts/retention-periods.ts +216 -0
- package/src/facts/unit-conflicts.ts +22 -9
- package/src/facts/unit-equivalents.ts +70 -0
- package/src/facts/unit-tolerance.ts +17 -0
- package/src/facts/unit-word.ts +35 -0
- package/src/facts/written-precision.ts +23 -0
- package/src/kana-spelling.ts +25 -0
- package/src/model-codes.ts +104 -0
- package/src/name-spelling-chars.ts +34 -0
- package/src/name-variants.ts +8 -7
- package/src/phone-numbers.ts +26 -6
- package/src/place-names.ts +53 -14
- package/src/plugin.ts +2 -0
- package/src/preamble-paragraphs.ts +21 -2
- package/src/profile/parse.ts +10 -0
- package/src/spacing-code.ts +26 -0
- package/src/structure/amount-range.ts +16 -7
- package/src/structure/capacity-count.ts +196 -0
- package/src/structure/counted-amounts.ts +5 -4
- package/src/structure/date-outside-period.ts +11 -6
- package/src/structure/date-range.ts +1 -1
- package/src/structure/deadline-after-event.ts +67 -0
- package/src/structure/definition-use.ts +59 -2
- package/src/structure/due-date.ts +8 -32
- package/src/structure/labelled-date-order.ts +84 -0
- package/src/structure/layout-codes.ts +210 -0
- package/src/structure/measured-amounts.ts +138 -0
- package/src/structure/quantity-range.ts +54 -0
- package/src/structure/range-bands.ts +316 -0
- package/src/structure/rent-multiple.ts +277 -0
- package/src/structure/scaled-quantities.ts +225 -0
- package/src/structure/stamp-order.ts +100 -0
- package/src/structure/step-times.ts +169 -0
- package/src/structure/term-deadline.ts +35 -0
- package/src/structure/time-range.ts +64 -0
- package/src/structure/total-line.ts +63 -0
- package/src/structure/total.ts +41 -6
- package/src/structure/unlisted-items.ts +207 -0
- package/src/structure/walk-time.ts +285 -0
|
@@ -23,8 +23,8 @@ const finding = (doc: ProseDocument, rule: string, offset: number, variant: stri
|
|
|
23
23
|
|
|
24
24
|
const OPENING_QUOTES = new Set(["「", "『", '"', "“"]);
|
|
25
25
|
const CLOSING_QUOTES = new Set(["」", "』", '"', "”"]);
|
|
26
|
-
/** A quoted term right before these is defined again (「X」とは, "X" means), which duplicate-definition reads. */
|
|
27
|
-
const DEFINING_AFTER = /^(
|
|
26
|
+
/** A quoted term right before these is defined again (「X」とは, 「X」といいます, "X" means), which duplicate-definition reads. */
|
|
27
|
+
const DEFINING_AFTER = /^(?:とは|という|といい(?:ます)?(?=[。、,))\s]|$)|\s+(?:means|shall mean|refers to|has the meaning))/u;
|
|
28
28
|
/** The ending a use may carry past the term: a plural or a possessive (Services, Service's). */
|
|
29
29
|
const WORD_ENDING = /^(?:e?s|['’]s?)/u;
|
|
30
30
|
|
|
@@ -238,14 +238,69 @@ const bracketBefore = (source: string, definition: Span): number => {
|
|
|
238
238
|
|
|
239
239
|
export type RepeatedName = { readonly offset: number; readonly name: string; readonly term: string; readonly line: number };
|
|
240
240
|
|
|
241
|
-
/**
|
|
242
|
-
const
|
|
241
|
+
/** How many characters a line may add to the long name and still be a line that only names the party. */
|
|
242
|
+
const SLACK = 12;
|
|
243
|
+
|
|
244
|
+
/** A field label on its own line, after a list marker (Attention:, 宛先:): short, and not a sentence. */
|
|
245
|
+
const FIELD_LABEL = /^(?:[-*+]\s+)?[^::。.]{1,20}[::]\s*/u;
|
|
246
|
+
/**
|
|
247
|
+
* What may follow the name in an address field: nothing, a comma and the next part (, Member Support), or a space and a part
|
|
248
|
+
* that does not go on in lower case (株式会社みなと 総務部). A particle or a verb (は支払う, shall pay) makes the line a sentence.
|
|
249
|
+
*/
|
|
250
|
+
const NEXT_PART = /^\.?(?:$|\s*[,、,]|\s+(?!\p{Ll}))/u;
|
|
251
|
+
const CLOSES_SENTENCE = /[.。!?!?]$/u;
|
|
252
|
+
|
|
253
|
+
/** A field whose value is the name and a little more, not a sentence (Attention: Hibari Lab Inc., Member Support). */
|
|
254
|
+
const isNameField = (line: string, name: string): boolean => {
|
|
255
|
+
const label = FIELD_LABEL.exec(line);
|
|
256
|
+
const value = label === null ? "" : line.slice(label[0].length);
|
|
257
|
+
const rest = value.slice(name.length);
|
|
258
|
+
return value.startsWith(name) && NEXT_PART.test(rest) && [...rest].length <= SLACK * 2 && !CLOSES_SENTENCE.test(rest.slice(1));
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/** A contact field's label: after a bullet or a number (1. 連絡先:), and as long as a label in English runs (Privacy Contact:). */
|
|
262
|
+
const CONTACT_LABEL = /^(?:(?:[-*+]|\d+[.)])\s+)?([^::。.]{1,40})[::]\s*/u;
|
|
263
|
+
const LABEL_MARKS = /[*_\s]+/gu;
|
|
264
|
+
/** After the name in a contact field, the next part after a space or a comma (, Tokyo), or the bracket that holds it (お問い合わせ窓口(株式会社みなと)). */
|
|
265
|
+
const NEXT_CONTACT_PART = /^\.?(?:$|[))]|\s*,?\s+(?!\p{Ll}))/u;
|
|
266
|
+
/** A comma that goes on in lower case or 、 may also start a clause (, which may; 株式会社みなと、平日に受け付ける): the address field's bound. */
|
|
267
|
+
const COMMA_PART = /^\.?\s*[,、,]/u;
|
|
268
|
+
|
|
269
|
+
const endsWithContactLabel = (label: string, contactLabels: readonly string[]): boolean => {
|
|
270
|
+
const bare = label.replaceAll(LABEL_MARKS, "").toLowerCase();
|
|
271
|
+
return contactLabels.some((contact) => contact !== "" && bare.endsWith(contact.toLowerCase()));
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* A field whose label ends with a contact label (窓口:, Attention:): the value names the party in full however long it is and
|
|
276
|
+
* wherever the name sits in it, unless the name goes on as a sentence (連絡先:株式会社みなとは、…).
|
|
277
|
+
*/
|
|
278
|
+
const isContactField = (line: string, name: string, contactLabels: readonly string[]): boolean => {
|
|
279
|
+
const label = CONTACT_LABEL.exec(line);
|
|
280
|
+
if (label === null || !endsWithContactLabel(label[1] ?? "", contactLabels)) return false;
|
|
281
|
+
const value = line.slice(label[0].length);
|
|
282
|
+
const at = value.indexOf(name);
|
|
283
|
+
if (at === -1) return false;
|
|
284
|
+
const rest = value.slice(at + name.length);
|
|
285
|
+
const continues = NEXT_CONTACT_PART.test(rest) || (COMMA_PART.test(rest) && [...rest].length <= SLACK * 2);
|
|
286
|
+
return continues && !CLOSES_SENTENCE.test(rest.slice(1));
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* A line that holds the short name too (甲 株式会社みなと), little else than the long name (a signature block names both),
|
|
291
|
+
* or a field whose value is the name (Attention: …, 宛先:…): an address gives the name in full.
|
|
292
|
+
*/
|
|
293
|
+
const isNameLine = (source: string, offset: number, name: string, term: string, contactLabels: readonly string[]): boolean => {
|
|
243
294
|
const start = source.lastIndexOf("\n", offset - 1) + 1;
|
|
244
295
|
const end = source.indexOf("\n", offset);
|
|
245
296
|
const line = source.slice(start, end === -1 ? source.length : end).trim();
|
|
246
|
-
const SLACK = 12;
|
|
247
297
|
// The short name inside the long one ("Pinecone" in "Pinecone Software Ltd") is not the short name written beside it.
|
|
248
|
-
return
|
|
298
|
+
return (
|
|
299
|
+
line.replaceAll(name, "").includes(term) ||
|
|
300
|
+
[...line].length <= [...name].length + SLACK ||
|
|
301
|
+
isNameField(line, name) ||
|
|
302
|
+
isContactField(line, name, contactLabels)
|
|
303
|
+
);
|
|
249
304
|
};
|
|
250
305
|
|
|
251
306
|
/** A name inside a longer word (東京大学 in 東京大学大学院, Acme in Acmeware) is part of another name. */
|
|
@@ -267,6 +322,7 @@ export const standsAlone = (source: string, offset: number, name: string, joiner
|
|
|
267
322
|
export const repeatedNames = (doc: ProseDocument, terms: readonly DefinedTerm[]): RepeatedName[] => {
|
|
268
323
|
const defined = new Set(terms.map((term) => term.term));
|
|
269
324
|
const joiners = (doc.lexicons["enumeration-joiner"] ?? []).map((entry) => entry.pattern);
|
|
325
|
+
const contactLabels = (doc.lexicons["contact-label"] ?? []).map((entry) => entry.pattern);
|
|
270
326
|
return terms
|
|
271
327
|
.filter((term) => term.inline)
|
|
272
328
|
.flatMap((term) => {
|
|
@@ -278,7 +334,7 @@ export const repeatedNames = (doc: ProseDocument, terms: readonly DefinedTerm[])
|
|
|
278
334
|
return doc.sentences
|
|
279
335
|
.filter((later) => later.span.start > term.span.end)
|
|
280
336
|
.flatMap((later) => [...later.text.matchAll(pattern)].map((match) => later.span.start + match.index))
|
|
281
|
-
.filter((offset) => standsAlone(doc.source, offset, name, joiners) && !isNameLine(doc.source, offset, name, term.term))
|
|
337
|
+
.filter((offset) => standsAlone(doc.source, offset, name, joiners) && !isNameLine(doc.source, offset, name, term.term, contactLabels))
|
|
282
338
|
.map((offset) => ({ offset, name, term: term.term, line: term.line }));
|
|
283
339
|
});
|
|
284
340
|
};
|
|
@@ -22,11 +22,15 @@ const findingAt = (doc: ProseDocument, offset: number, values: Readonly<Record<s
|
|
|
22
22
|
values: { ...values, offset },
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
/**
|
|
25
|
+
/** Markdown の見出し。文には入らないが、見出しで語を使っても、その語は文書で使われている。 */
|
|
26
|
+
const headingsOf = (doc: ProseDocument): BodyText[] =>
|
|
27
|
+
(doc.markup?.headings ?? []).map((heading) => ({ start: heading.start, text: doc.source.slice(heading.start, heading.end) }));
|
|
28
|
+
|
|
29
|
+
/** 定義したのに、定義の外(文と見出し)で一度も使っていない語。 */
|
|
26
30
|
export const unusedDefinition: Detector = (doc): Finding[] =>
|
|
27
31
|
doc.structure === undefined
|
|
28
32
|
? []
|
|
29
|
-
: unusedDefinitions(definedTerms(doc.structure), bodyOf(doc), mentionedIn(doc)).map((defined) =>
|
|
33
|
+
: unusedDefinitions(definedTerms(doc.structure), [...bodyOf(doc), ...headingsOf(doc)], mentionedIn(doc)).map((defined) =>
|
|
30
34
|
findingAt(doc, defined.span.start, { term: defined.term }),
|
|
31
35
|
);
|
|
32
36
|
|
|
@@ -25,14 +25,14 @@ import { proseAndTablesOf } from "../table-text.ts";
|
|
|
25
25
|
import { quoteAt } from "./structure-tree.ts";
|
|
26
26
|
|
|
27
27
|
/** 期間の単位の語彙表。木の数量の単位がどれかに入れば、その単位の期間。 */
|
|
28
|
-
const DURATION_LEXICONS: readonly (readonly [string, DurationUnit])[] = [
|
|
28
|
+
export const DURATION_LEXICONS: readonly (readonly [string, DurationUnit])[] = [
|
|
29
29
|
["duration-day", "day"],
|
|
30
30
|
["duration-week", "week"],
|
|
31
31
|
["duration-month", "month"],
|
|
32
32
|
["duration-year", "year"],
|
|
33
33
|
];
|
|
34
34
|
|
|
35
|
-
type Quantity = Span & { readonly amount: number; readonly unit: string };
|
|
35
|
+
export type Quantity = Span & { readonly amount: number; readonly unit: string };
|
|
36
36
|
|
|
37
37
|
const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
|
|
38
38
|
|
|
@@ -62,7 +62,7 @@ const withWordsAround = (source: string, start: number, end: number, unit: strin
|
|
|
62
62
|
return wordStart === undefined ? { start, end: endWithUnit(source, end, unit) } : { start: wordStart, end: endWithUnit(source, end + 1, unit) };
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
const quantitiesOf = (tree: StructureNode, source: string): Quantity[] =>
|
|
65
|
+
export const quantitiesOf = (tree: StructureNode, source: string): Quantity[] =>
|
|
66
66
|
inDocumentOrder(tree).flatMap((node): Quantity[] => {
|
|
67
67
|
if (node.kind !== "quantity") return [];
|
|
68
68
|
const unit = String(node.attrs["unit"] ?? "");
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
// due-before-issue: the reading half. The issue-date and due-date words come from the language's lexicons
|
|
2
2
|
// (issue-date-label, due-date-label, deadline-passed-word), and so do the words of minutes (minutes-title-word, meeting-date-label,
|
|
3
|
-
// action-section-heading, earlier-section-word, action-due-label, item-done-word)
|
|
4
|
-
// lines are read with code masked.
|
|
3
|
+
// action-section-heading, earlier-section-word, action-due-label, item-done-word) and the other pairs of dates that must come in
|
|
4
|
+
// order (dated-pair-label, date-now-word); the dates are the structure tree's, and the lines are read with code masked.
|
|
5
5
|
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
6
6
|
import { actionDueBeforeMeeting, type ActionWords } from "../structure/action-due.ts";
|
|
7
|
+
import { pairedDatesOutOfOrder } from "../structure/labelled-date-order.ts";
|
|
7
8
|
import { dueBeforeIssue, type DueWords } from "../structure/due-date.ts";
|
|
8
9
|
import type { StructureIssue } from "../structure/issues.ts";
|
|
9
10
|
import { proseAndTablesOf } from "../table-text.ts";
|
|
10
11
|
import { datedPoints, quoteAt } from "./structure-tree.ts";
|
|
11
12
|
|
|
13
|
+
/** A record's facts table can sit well below its header date (a listing date above the table holding the move-in date). */
|
|
14
|
+
const MAX_RECORD_LINE_GAP = 40;
|
|
15
|
+
|
|
12
16
|
const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexicons[lexicon] ?? []).map((entry) => entry.pattern);
|
|
13
17
|
|
|
14
18
|
const wordsOf = (doc: ProseDocument): DueWords => ({
|
|
@@ -26,6 +30,8 @@ const actionWordsOf = (doc: ProseDocument): ActionWords => ({
|
|
|
26
30
|
minutes: patternsOf(doc, "minutes-title-word"),
|
|
27
31
|
});
|
|
28
32
|
|
|
33
|
+
const orderAsidesOf = (doc: ProseDocument): string[] => [...patternsOf(doc, "deadline-passed-word"), ...patternsOf(doc, "date-now-word")];
|
|
34
|
+
|
|
29
35
|
const findingOf = (doc: ProseDocument, issue: StructureIssue, variant?: string): Finding => ({
|
|
30
36
|
rule: "due-before-issue",
|
|
31
37
|
severity: "error",
|
|
@@ -40,8 +46,10 @@ export const dueDate: Detector = (doc): Finding[] => {
|
|
|
40
46
|
if (doc.structure === undefined) return [];
|
|
41
47
|
const text = proseAndTablesOf(doc);
|
|
42
48
|
const dates = datedPoints(doc.structure);
|
|
49
|
+
const pairs = doc.lexicons["dated-pair-label"] ?? [];
|
|
43
50
|
return [
|
|
44
51
|
...dueBeforeIssue(text, dates, wordsOf(doc)).map((issue) => findingOf(doc, issue)),
|
|
52
|
+
...pairedDatesOutOfOrder(text, dates, pairs, orderAsidesOf(doc), MAX_RECORD_LINE_GAP).map((issue) => findingOf(doc, issue, "order")),
|
|
45
53
|
...actionDueBeforeMeeting(text, dates, doc.markup?.headings ?? [], actionWordsOf(doc)).map((issue) => findingOf(doc, issue, "meeting")),
|
|
46
54
|
];
|
|
47
55
|
};
|
|
@@ -123,9 +123,12 @@ export const conjunctionRun: Detector = (doc, options): Finding[] => {
|
|
|
123
123
|
});
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
/** Weekday and month names, capitalised in either style (the list leaves out May, March and August, also ordinary words). */
|
|
127
|
+
const FIXED_CASE_LISTS = ["calendar-name"] as const;
|
|
128
|
+
|
|
129
|
+
const headingsOf = (sections: readonly Section[], fixedCase: ReadonlySet<string>): { readonly section: Section; readonly title: boolean }[] =>
|
|
127
130
|
sections.flatMap((section) => {
|
|
128
|
-
const title = isTitleCase(section.heading);
|
|
131
|
+
const title = isTitleCase(section.heading, fixedCase);
|
|
129
132
|
return title === undefined ? [] : [{ section, title }];
|
|
130
133
|
});
|
|
131
134
|
|
|
@@ -134,10 +137,14 @@ const headingsOf = (sections: readonly Section[]): { readonly section: Section;
|
|
|
134
137
|
* 見るのは文書の中で揃っているかだけで、少数派のほうを指摘する。題名は指摘しない(minorityCase)。
|
|
135
138
|
*/
|
|
136
139
|
export const titleCaseMix: Detector = (doc, options): Finding[] => {
|
|
140
|
+
const fixedCase = new Set(FIXED_CASE_LISTS.flatMap((id) => (doc.lexicons[id] ?? []).map((entry) => entry.pattern)));
|
|
137
141
|
const pageTitle = pageTitleOf(doc.sections);
|
|
138
|
-
const judged = headingsOf(
|
|
142
|
+
const judged = headingsOf(
|
|
143
|
+
doc.sections.filter((section) => section !== pageTitle),
|
|
144
|
+
fixedCase,
|
|
145
|
+
);
|
|
139
146
|
const titleCase = judged.filter((entry) => entry.title).length;
|
|
140
|
-
const pageTitleCase = pageTitle === undefined ? undefined : isTitleCase(pageTitle.heading);
|
|
147
|
+
const pageTitleCase = pageTitle === undefined ? undefined : isTitleCase(pageTitle.heading, fixedCase);
|
|
141
148
|
const minorityIsTitle = minorityCase({ titleCase, sentenceCase: judged.length - titleCase }, pageTitleCase);
|
|
142
149
|
const few = minorityIsTitle === undefined ? [] : judged.filter((entry) => entry.title === minorityIsTitle);
|
|
143
150
|
if (few.length > options.limit) return [];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// deadline-after-event: the reading half. The event-date, registration, deadline and follow-up words come from the language's
|
|
2
|
+
// lexicons (event-date-label, event-registration-word, event-deadline-word, event-aside); the dates are the structure tree's,
|
|
3
|
+
// and the lines are read with code masked.
|
|
4
|
+
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
5
|
+
import { deadlinesAfterEvent, type EventDeadlineWords } from "../structure/deadline-after-event.ts";
|
|
6
|
+
import { proseAndTablesOf } from "../table-text.ts";
|
|
7
|
+
import { datedPoints, quoteAt } from "./structure-tree.ts";
|
|
8
|
+
|
|
9
|
+
const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexicons[lexicon] ?? []).map((entry) => entry.pattern);
|
|
10
|
+
|
|
11
|
+
const wordsOf = (doc: ProseDocument): EventDeadlineWords => ({
|
|
12
|
+
events: patternsOf(doc, "event-date-label"),
|
|
13
|
+
registrations: patternsOf(doc, "event-registration-word"),
|
|
14
|
+
deadlines: patternsOf(doc, "event-deadline-word"),
|
|
15
|
+
asides: patternsOf(doc, "event-aside"),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const eventDeadline: Detector = (doc): Finding[] => {
|
|
19
|
+
if (doc.structure === undefined) return [];
|
|
20
|
+
const sentences = doc.sentences.map((sentence) => sentence.span);
|
|
21
|
+
return deadlinesAfterEvent(proseAndTablesOf(doc), datedPoints(doc.structure), sentences, wordsOf(doc)).map((issue) => ({
|
|
22
|
+
rule: "deadline-after-event",
|
|
23
|
+
severity: "error",
|
|
24
|
+
line: 0,
|
|
25
|
+
column: 0,
|
|
26
|
+
quote: quoteAt(doc.source, issue.offset),
|
|
27
|
+
values: { ...issue.values, offset: issue.offset },
|
|
28
|
+
}));
|
|
29
|
+
};
|
|
@@ -8,7 +8,11 @@ import { partsAt, scopedFacts, type ScopedFact } from "../facts/fact-scope.ts";
|
|
|
8
8
|
import { conditionPairConflicts, type ChangeSentence, type ChangeWords, type ConditionWord, type PairConflict, type WordAt } from "../facts/condition-pairs.ts";
|
|
9
9
|
import { scopeConflicts, summaryConflicts, type FactConflict } from "../facts/fact-conflicts.ts";
|
|
10
10
|
import { eventDateConflicts, type EventDateConflict, type EventWord } from "../facts/event-dates.ts";
|
|
11
|
+
import { retentionConflicts, type LengthMark, type RetentionLength, type RetentionVerb, type RetentionWords } from "../facts/retention-periods.ts";
|
|
12
|
+
import type { DurationUnit } from "../derived/date-arithmetic.ts";
|
|
13
|
+
import { DURATION_LEXICONS, quantitiesOf, type Quantity } from "./derived-numbers.ts";
|
|
11
14
|
import { quoteAt } from "./structure-tree.ts";
|
|
15
|
+
import { measuredOf, valuesWith } from "./measured-facts.ts";
|
|
12
16
|
|
|
13
17
|
const patternsOf = (doc: ProseDocument, id: string): string[] => (doc.lexicons[id] ?? []).map((entry) => entry.pattern);
|
|
14
18
|
|
|
@@ -23,8 +27,9 @@ export const factWordsOf = (doc: ProseDocument): FactWords => ({
|
|
|
23
27
|
|
|
24
28
|
const factsByDocument = new WeakMap<ProseDocument, readonly ScopedFact[]>();
|
|
25
29
|
|
|
30
|
+
/** 単位の語彙表の量(410 g、1.2 kg)も値として読む。木が単位を読まない量は、数だけでは升や文の値にならない。 */
|
|
26
31
|
const readFacts = (doc: ProseDocument, tree: StructureNode): ScopedFact[] => {
|
|
27
|
-
const values =
|
|
32
|
+
const values = valuesWith(tree, doc, measuredOf(doc));
|
|
28
33
|
const facts = [...labelledFacts(doc.source, values, factWordsOf(doc)), ...tableFacts(doc.source, values)];
|
|
29
34
|
return scopedFacts(facts, tree, doc.source, patternsOf(doc, "summary-heading"));
|
|
30
35
|
};
|
|
@@ -51,8 +56,64 @@ const findingOf =
|
|
|
51
56
|
values: { label: conflict.fact.label, value: shown(doc, conflict.fact.value), other: shown(doc, conflict.other), offset: conflict.fact.value.start },
|
|
52
57
|
});
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
const UNITS: readonly DurationUnit[] = ["day", "week", "month", "year"];
|
|
60
|
+
|
|
61
|
+
const isDurationUnit = (group: string | undefined): group is DurationUnit => UNITS.some((unit) => unit === group);
|
|
62
|
+
|
|
63
|
+
const retentionUnitOf = (doc: ProseDocument, unit: string): DurationUnit | undefined => {
|
|
64
|
+
const listed = DURATION_LEXICONS.find(([id]) => patternsOf(doc, id).some((pattern) => pattern.normalize("NFKC") === unit))?.[1];
|
|
65
|
+
const extra = (doc.lexicons["retention-unit"] ?? []).find((entry) => entry.pattern.normalize("NFKC") === unit)?.group;
|
|
66
|
+
return listed ?? (isDurationUnit(extra) ? extra : undefined);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** 単位の語彙表に、書いた単位より長い形(か月 に対する か月間)があれば、そこまで。木の数量は か月 で終わる。 */
|
|
70
|
+
const endWithLongerUnit = (doc: ProseDocument, quantity: Quantity): number => {
|
|
71
|
+
const unitStart = quantity.end - quantity.unit.length;
|
|
72
|
+
const longer = DURATION_LEXICONS.flatMap(([id]) => patternsOf(doc, id))
|
|
73
|
+
.filter((pattern) => pattern.length > quantity.unit.length && pattern.startsWith(quantity.unit) && doc.source.startsWith(pattern, unitStart))
|
|
74
|
+
.reduce((longest, pattern) => Math.max(longest, pattern.length), quantity.unit.length);
|
|
75
|
+
return unitStart + longer;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const retentionLengthsOf = (doc: ProseDocument, tree: StructureNode): RetentionLength[] =>
|
|
79
|
+
quantitiesOf(tree, doc.source).flatMap((quantity) => {
|
|
80
|
+
const unit = retentionUnitOf(doc, quantity.unit);
|
|
81
|
+
return unit === undefined ? [] : [{ start: quantity.start, end: endWithLongerUnit(doc, quantity), amount: quantity.amount, unit }];
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const retentionVerbsOf = (doc: ProseDocument): RetentionVerb[] =>
|
|
85
|
+
(doc.lexicons["retention-verb"] ?? []).map((entry) => ({ pattern: entry.pattern, group: entry.group ?? "", position: entry.position ?? "before" }));
|
|
86
|
+
|
|
87
|
+
const lengthMarksOf = (doc: ProseDocument): LengthMark[] =>
|
|
88
|
+
(doc.lexicons["retention-length-mark"] ?? []).map((entry) => ({ pattern: entry.pattern, group: entry.group ?? "", position: entry.position ?? "before" }));
|
|
89
|
+
|
|
90
|
+
const retentionWordsOf = (doc: ProseDocument): RetentionWords => ({
|
|
91
|
+
verbs: retentionVerbsOf(doc),
|
|
92
|
+
marks: lengthMarksOf(doc),
|
|
93
|
+
modifiers: patternsOf(doc, "retention-length-modifier"),
|
|
94
|
+
bounds: [...wordsAt(doc, "approximate-marker"), ...wordsAt(doc, "retention-bound")],
|
|
95
|
+
joiners: patternsOf(doc, "fact-name-joiner"),
|
|
96
|
+
objectMarks: patternsOf(doc, "retention-object-mark"),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/** 文書のどこかで、同じものの保存期間が二通り(1年間保存 と 3年間を経過したら削除)。 */
|
|
100
|
+
const retentionFindings = (doc: ProseDocument): Finding[] => {
|
|
101
|
+
const tree = doc.structure;
|
|
102
|
+
if (tree === undefined) return [];
|
|
103
|
+
const sentences = doc.sentences.map((sentence) => ({ ...sentence.span, tokens: sentence.tokens ?? [] }));
|
|
104
|
+
return retentionConflicts(doc.source, sentences, retentionLengthsOf(doc, tree), retentionWordsOf(doc)).map(({ object, value, other }): Finding => ({
|
|
105
|
+
rule: "fact-conflict",
|
|
106
|
+
severity: "warning",
|
|
107
|
+
line: 0,
|
|
108
|
+
column: 0,
|
|
109
|
+
quote: quoteAt(doc.source, value.start),
|
|
110
|
+
variant: "retention",
|
|
111
|
+
values: { label: object, value: doc.source.slice(value.start, value.end), other: doc.source.slice(other.start, other.end), offset: value.start },
|
|
112
|
+
}));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/** 同じ節で、同じ名前に二通りの値(締切:10月5日 と 締切:10月7日)。文書のどこでも、同じものに二通りの保存期間。 */
|
|
116
|
+
export const factConflict: Detector = (doc): Finding[] => [...scopeConflicts(factsOf(doc)).map(findingOf("fact-conflict", doc)), ...retentionFindings(doc)];
|
|
56
117
|
|
|
57
118
|
const countedPhrasesOf = (doc: ProseDocument): CountedPhrase[] =>
|
|
58
119
|
doc.sentences.flatMap((sentence) => {
|
|
@@ -34,11 +34,20 @@ const ACRONYM = /^[A-Z]{2,}s?$/u;
|
|
|
34
34
|
|
|
35
35
|
const TITLE_DEPTH = 1;
|
|
36
36
|
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
/**
|
|
38
|
+
* 見出しの頭の番号の札(Section 3. / Day 1: / Part II:)。札の語は流儀によらず大文字で始まり、続く題の語数にも数えない。
|
|
39
|
+
* 番号は 3 桁までで、後ろに「.」「:」「)」か ダッシュがあるものだけ(Windows 11 Setup も Budget 2026: も札ではない)。
|
|
40
|
+
*/
|
|
41
|
+
const LEADING_LABEL = /^\s*\p{Lu}\p{Ll}+\s+(?:\d{1,3}(?:\.\d{1,3})*|[IVXLC]+)\s*[.:)\-\u2013\u2014]\s+/u;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 見出しが Title Case か。判定できなければ undefined。fixedCase は流儀によらず大文字で書く語(曜日・月の名)で、
|
|
45
|
+
* どちらの流儀の証拠にもならないので数えない。
|
|
46
|
+
*/
|
|
47
|
+
export const isTitleCase = (heading: string, fixedCase: ReadonlySet<string> = new Set()): boolean | undefined => {
|
|
48
|
+
const words = [...withoutCodeWords(straightApostrophes(heading.replace(LEADING_LABEL, ""))).matchAll(WORD)]
|
|
40
49
|
.map((match) => match[0])
|
|
41
|
-
.filter((word) => !MINOR_WORDS.has(word.toLowerCase()) && !ACRONYM.test(word));
|
|
50
|
+
.filter((word) => !MINOR_WORDS.has(word.toLowerCase()) && !ACRONYM.test(word) && !fixedCase.has(word));
|
|
42
51
|
// 1 語の見出しは、どちらの流儀でも先頭が大文字になる。判定できない。
|
|
43
52
|
if (words.length < 2) return undefined;
|
|
44
53
|
const capitalized = words.filter((word) => word[0] === word[0]?.toUpperCase()).length;
|
|
@@ -65,6 +65,22 @@ const pointsElsewhere = (doc: ProseDocument, section: Section): boolean => {
|
|
|
65
65
|
return first !== undefined && (holdsLink(doc.source, first.span, doc.links) || namesLocation(doc.source.slice(first.span.start, first.span.end)));
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
+
/** A figure, with its thousands separators (1,320,000), compared without them. */
|
|
69
|
+
const FIGURE = /\p{Nd}+(?:[,,]\p{Nd}{3})*/gu;
|
|
70
|
+
/** Note marks are not figures: [^1], ※1, <sup>1</sup>. */
|
|
71
|
+
const NOTE_MARK = /\[\^[^\]]*\]|※\p{Nd}+|<sup>[^<]*<\/sup>/gu;
|
|
72
|
+
|
|
73
|
+
const figuresOf = (text: string): string[] => (text.replace(NOTE_MARK, "").match(FIGURE) ?? []).map((figure) => figure.replace(/[,,]/gu, ""));
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 最初の文が、見出しに無い数(金額・番号・日付)を述べている。見出しが約束した中身そのもので(## 見積金額 → 見積金額は1,320,000円です。
|
|
77
|
+
* Invoice → Invoice number: INV-2026-0318)、語が重なっても読者は何かを受け取る。
|
|
78
|
+
*/
|
|
79
|
+
export const statesFigure = (heading: string, sentence: string): boolean => {
|
|
80
|
+
const inHeading = new Set(figuresOf(heading));
|
|
81
|
+
return figuresOf(sentence).some((figure) => !inHeading.has(figure));
|
|
82
|
+
};
|
|
83
|
+
|
|
68
84
|
/** 見出しとの重なりを測る文。用語集や表記の手引きは見出しの語の別の書き方を引用する(Not “datacentre”)ので、それは数えない。 */
|
|
69
85
|
const echoedText = (section: Section): string => withoutQuotedVariants(section.firstSentence?.text ?? "", measuredHeading(section));
|
|
70
86
|
|
|
@@ -72,7 +88,7 @@ export const headingEcho: Detector = (doc, options): Finding[] => {
|
|
|
72
88
|
const leadIns = (doc.lexicons["lead-in"] ?? []).map((entry) => entry.pattern);
|
|
73
89
|
return doc.sections
|
|
74
90
|
.filter((section) => section.heading.length > 0 && section.firstSentence !== undefined && addsLittle(section, doc.lengthUnit))
|
|
75
|
-
.filter((section) => !leadsIn(doc, section, leadIns) && !pointsElsewhere(doc, section))
|
|
91
|
+
.filter((section) => !leadsIn(doc, section, leadIns) && !pointsElsewhere(doc, section) && !statesFigure(section.heading, section.firstSentence?.text ?? ""))
|
|
76
92
|
.map((section) => ({ section, overlap: Math.round(containment(trigrams(measuredHeading(section)), trigrams(echoedText(section))) * 100) }))
|
|
77
93
|
.filter(({ overlap }) => overlap >= options.limit)
|
|
78
94
|
.map(({ section, overlap }) => ({
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// layout-code-mismatch: a listing's layout code (2LDK, "3 bedrooms") against the rooms the same listing names
|
|
2
|
+
// (structure/layout-codes.ts). The code letters and counted words are layout-code's, the room names layout-room's, and the
|
|
3
|
+
// field names layout-label's.
|
|
4
|
+
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
5
|
+
import { cellsOf, tablesOf, type Cell } from "../facts/table-facts.ts";
|
|
6
|
+
import { withoutEdgeMarks } from "../facts/trim-marks.ts";
|
|
7
|
+
import { linesOf, type Line } from "../structure/lines.ts";
|
|
8
|
+
import {
|
|
9
|
+
foldWidth,
|
|
10
|
+
layoutSlip,
|
|
11
|
+
pairByScope,
|
|
12
|
+
parseBreakdown,
|
|
13
|
+
parseLayoutCode,
|
|
14
|
+
type Breakdown,
|
|
15
|
+
type LayoutCode,
|
|
16
|
+
type LayoutSlip,
|
|
17
|
+
type LayoutWords,
|
|
18
|
+
type LetterGroup,
|
|
19
|
+
type RoomGroup,
|
|
20
|
+
} from "../structure/layout-codes.ts";
|
|
21
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
22
|
+
|
|
23
|
+
type LabelGroup = "code" | "breakdown" | "room-column";
|
|
24
|
+
type Labels = ReadonlyMap<string, LabelGroup>;
|
|
25
|
+
|
|
26
|
+
const LETTER_GROUPS: readonly LetterGroup[] = ["living", "dining", "kitchen", "storage", "one-room"];
|
|
27
|
+
const ROOM_GROUPS: readonly RoomGroup[] = ["living", "dining", "kitchen", "room", "storage", "unclear"];
|
|
28
|
+
const LABEL_GROUPS: readonly LabelGroup[] = ["code", "breakdown", "room-column"];
|
|
29
|
+
|
|
30
|
+
const letterGroupOf = (group: string | undefined): LetterGroup | undefined => LETTER_GROUPS.find((known) => known === group);
|
|
31
|
+
|
|
32
|
+
export const layoutWordsOf = (lexicons: ProseDocument["lexicons"]): LayoutWords => {
|
|
33
|
+
const code = lexicons["layout-code"] ?? [];
|
|
34
|
+
return {
|
|
35
|
+
letters: new Map(
|
|
36
|
+
code.flatMap((entry): [string, LetterGroup][] => {
|
|
37
|
+
const group = letterGroupOf(entry.group);
|
|
38
|
+
return group === undefined ? [] : [[entry.pattern, group]];
|
|
39
|
+
}),
|
|
40
|
+
),
|
|
41
|
+
joiners: code.filter((entry) => entry.group === "joiner").map((entry) => entry.pattern),
|
|
42
|
+
counted: code.filter((entry) => entry.group === "counted").map((entry) => entry.pattern),
|
|
43
|
+
counters: code.filter((entry) => entry.group === "counter").map((entry) => entry.pattern),
|
|
44
|
+
rooms: (lexicons["layout-room"] ?? []).flatMap((entry) => {
|
|
45
|
+
const group = ROOM_GROUPS.find((known) => known === entry.group);
|
|
46
|
+
return group === undefined ? [] : [{ pattern: entry.pattern, group }];
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const labelKey = (label: string): string => foldWidth(withoutEdgeMarks(label)).toLowerCase().replace(/\s+/gu, " ");
|
|
52
|
+
|
|
53
|
+
const labelsOf = (lexicons: ProseDocument["lexicons"]): Labels =>
|
|
54
|
+
new Map(
|
|
55
|
+
(lexicons["layout-label"] ?? []).flatMap((entry): [string, LabelGroup][] => {
|
|
56
|
+
const group = LABEL_GROUPS.find((known) => known === entry.group);
|
|
57
|
+
return group === undefined ? [] : [[labelKey(entry.pattern), group]];
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/** A code found in the page, with the breakdown written right with it when there is one (a row, or 2LDK(洋室6帖・…)). */
|
|
62
|
+
type PlacedCode = { readonly code: LayoutCode; readonly scope: number; readonly breakdown?: Breakdown | undefined };
|
|
63
|
+
type PlacedBreakdown = { readonly breakdown: Breakdown; readonly scope: number };
|
|
64
|
+
type Found = { readonly codes: PlacedCode[]; readonly breakdowns: PlacedBreakdown[] };
|
|
65
|
+
const NOTHING: Found = { codes: [], breakdowns: [] };
|
|
66
|
+
|
|
67
|
+
type Context = { readonly words: LayoutWords; readonly labels: Labels; readonly scopeOf: (offset: number) => number };
|
|
68
|
+
|
|
69
|
+
const INLINE_BREAKDOWN = /^[^((]*[((]([^))]+)[))]/u;
|
|
70
|
+
|
|
71
|
+
/** The breakdown written in brackets after the code, when it names a room. */
|
|
72
|
+
const inlineBreakdown = (rest: string, words: LayoutWords): Breakdown | undefined => {
|
|
73
|
+
const inside = INLINE_BREAKDOWN.exec(rest)?.[1];
|
|
74
|
+
if (inside === undefined) return undefined;
|
|
75
|
+
const breakdown = parseBreakdown([inside], words);
|
|
76
|
+
return breakdown.rooms > 0 || breakdown.unclear ? breakdown : undefined;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const codeIn = (text: string, start: number, context: Context, breakdown?: Breakdown): PlacedCode[] => {
|
|
80
|
+
const found = parseLayoutCode(text, context.words);
|
|
81
|
+
if (found === undefined) return [];
|
|
82
|
+
const code = { ...found, start: start + found.start, end: start + found.end };
|
|
83
|
+
const written = breakdown ?? inlineBreakdown(text.slice(found.end), context.words);
|
|
84
|
+
return [{ code, scope: context.scopeOf(code.start), breakdown: written }];
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const field = (group: LabelGroup | undefined, value: string, start: number, context: Context): Found => {
|
|
88
|
+
if (group === "code") return { codes: codeIn(value, start, context), breakdowns: [] };
|
|
89
|
+
if (group === "breakdown") return { codes: [], breakdowns: [{ breakdown: parseBreakdown([value], context.words), scope: context.scopeOf(start) }] };
|
|
90
|
+
return NOTHING;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const merged = (found: readonly Found[]): Found => ({
|
|
94
|
+
codes: found.flatMap((each) => each.codes),
|
|
95
|
+
breakdowns: found.flatMap((each) => each.breakdowns),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const groupOfCell = (cell: Cell | undefined, labels: Labels): LabelGroup | undefined => (cell === undefined ? undefined : labels.get(labelKey(cell.text)));
|
|
99
|
+
|
|
100
|
+
/** A table with a layout column: one listing a row, with its breakdown column when the table has one. */
|
|
101
|
+
const wideRows = (rows: readonly Cell[][], codeColumn: number, breakdownColumn: number, context: Context): Found => ({
|
|
102
|
+
codes: rows.flatMap((cells) => {
|
|
103
|
+
const code = cells[codeColumn];
|
|
104
|
+
const listed = cells[breakdownColumn];
|
|
105
|
+
const breakdown = listed === undefined ? undefined : parseBreakdown([listed.text], context.words);
|
|
106
|
+
return code === undefined ? [] : codeIn(code.text, code.start, context, breakdown);
|
|
107
|
+
}),
|
|
108
|
+
breakdowns: [],
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const tableFound = (header: Line, rows: readonly Cell[][], context: Context): Found => {
|
|
112
|
+
const groups = cellsOf(header).map((cell) => groupOfCell(cell, context.labels));
|
|
113
|
+
const codeColumn = groups.indexOf("code");
|
|
114
|
+
if (codeColumn !== -1) return wideRows(rows, codeColumn, groups.indexOf("breakdown"), context);
|
|
115
|
+
if (groups[0] === "room-column") {
|
|
116
|
+
const breakdown = parseBreakdown(
|
|
117
|
+
rows.map((cells) => cells[0]?.text ?? ""),
|
|
118
|
+
context.words,
|
|
119
|
+
);
|
|
120
|
+
return { codes: [], breakdowns: [{ breakdown, scope: context.scopeOf(header.start) }] };
|
|
121
|
+
}
|
|
122
|
+
return merged(rows.map(([label, value]) => (value === undefined ? NOTHING : field(groupOfCell(label, context.labels), value.text, value.start, context))));
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const tablesFound = (source: string, context: Context): Found =>
|
|
126
|
+
merged(tablesOf(linesOf(source)).map((table) => tableFound(table.header, table.rows.map(cellsOf), context)));
|
|
127
|
+
|
|
128
|
+
const LIST_LEAD = /^\s*(?:(?:[-*+]|\d+[.)])\s+)?/u;
|
|
129
|
+
const MAX_LABEL_LENGTH = 24;
|
|
130
|
+
|
|
131
|
+
/** "間取り:2LDK", "- Rooms: Bedroom 1, Bedroom 2" outside tables: the name before the first colon, and the value after it. */
|
|
132
|
+
const labelledLine = (line: Line, context: Context): Found => {
|
|
133
|
+
const colon = line.text.search(/[::]/u);
|
|
134
|
+
if (colon === -1 || line.text.includes("|")) return NOTHING;
|
|
135
|
+
const label = line.text.slice(0, colon).replace(LIST_LEAD, "");
|
|
136
|
+
const rest = line.text.slice(colon + 1);
|
|
137
|
+
const value = rest.trimStart();
|
|
138
|
+
if (label.length > MAX_LABEL_LENGTH || value === "") return NOTHING;
|
|
139
|
+
return field(context.labels.get(labelKey(label)), value, line.start + colon + 1 + rest.length - value.length, context);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/** Code and markup are masked in prose, so a colon in code is not read. */
|
|
143
|
+
const linesFound = (prose: string, context: Context): Found => merged(linesOf(prose).map((line) => labelledLine(line, context)));
|
|
144
|
+
|
|
145
|
+
const scopeFinder =
|
|
146
|
+
(doc: ProseDocument) =>
|
|
147
|
+
(offset: number): number =>
|
|
148
|
+
doc.sections.findLastIndex((section) => section.span.start <= offset);
|
|
149
|
+
|
|
150
|
+
const slipsOf = (found: Found): LayoutSlip[] => {
|
|
151
|
+
const direct = found.codes.flatMap((placed): [LayoutCode, Breakdown][] => (placed.breakdown === undefined ? [] : [[placed.code, placed.breakdown]]));
|
|
152
|
+
const pooled = found.codes.filter((placed) => placed.breakdown === undefined);
|
|
153
|
+
const paired = pairByScope(pooled, found.breakdowns).map(([placed, listed]): [LayoutCode, Breakdown] => [placed.code, listed.breakdown]);
|
|
154
|
+
return [...direct, ...paired].flatMap(([code, breakdown]) => layoutSlip(code, breakdown) ?? []);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const layoutCode: Detector = (doc): Finding[] => {
|
|
158
|
+
const context: Context = { words: layoutWordsOf(doc.lexicons), labels: labelsOf(doc.lexicons), scopeOf: scopeFinder(doc) };
|
|
159
|
+
const found = merged([tablesFound(doc.source, context), linesFound(doc.prose ?? doc.source, context)]);
|
|
160
|
+
return slipsOf(found).map((slip) => ({
|
|
161
|
+
rule: "layout-code-mismatch",
|
|
162
|
+
severity: "warning",
|
|
163
|
+
line: 0,
|
|
164
|
+
column: 0,
|
|
165
|
+
quote: quoteAt(doc.source, slip.code.start),
|
|
166
|
+
...(slip.kind === "part" ? { variant: "part" } : {}),
|
|
167
|
+
values: {
|
|
168
|
+
code: slip.code.text,
|
|
169
|
+
stated: slip.code.rooms,
|
|
170
|
+
...(slip.kind === "count" ? { listed: slip.listed } : { part: slip.entry }),
|
|
171
|
+
offset: slip.code.start,
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ProseDocument, StructureNode } from "../plugin.ts";
|
|
2
|
+
import { nameSpans } from "../compare/proper-nouns.ts";
|
|
3
|
+
import { overlapsAny, spanIndex } from "../compare/spans.ts";
|
|
4
|
+
import { factValues, type FactValue } from "../facts/fact-values.ts";
|
|
5
|
+
import { codeFences } from "./code-fences.ts";
|
|
6
|
+
import { measuredValues, type Measured } from "../facts/measures.ts";
|
|
7
|
+
import { measureUnitsOf } from "../facts/measure-units.ts";
|
|
8
|
+
|
|
9
|
+
/** 文書の中の、単位の語彙表の単位が付いた量。コードの塊の中の量は、項目の値ではない。 */
|
|
10
|
+
export const measuredOf = (doc: ProseDocument): Measured[] => {
|
|
11
|
+
const fences = codeFences(doc.source);
|
|
12
|
+
return measuredValues(doc.source, measureUnitsOf(doc)).filter((value) => !fences.some((fence) => fence.start <= value.start && value.end <= fence.end));
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/** fact-conflict の値に、単位の付いた量を足す。量と重なる値(量の数だけを読んだもの)は量に置き換える。 */
|
|
16
|
+
export const valuesWith = (tree: StructureNode, doc: ProseDocument, measured: readonly Measured[]): FactValue[] => {
|
|
17
|
+
const taken = spanIndex(measured);
|
|
18
|
+
const others = factValues(tree, doc.source, nameSpans(doc)).filter((value) => !overlapsAny(taken, value));
|
|
19
|
+
return [...others, ...measured].toSorted((left, right) => left.start - right.start);
|
|
20
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { MarkupHeading, ProseDocument } from "../plugin.ts";
|
|
2
|
+
import { codesAfterLabels, codesInTitle, modelCodeVariants } from "../model-codes.ts";
|
|
3
|
+
import { proseAndTablesOf } from "../table-text.ts";
|
|
4
|
+
import { tableBodyCells } from "../facts/table-facts.ts";
|
|
5
|
+
import { proseWithCells } from "../table-cells.ts";
|
|
6
|
+
|
|
7
|
+
// 型番の欄の語(型番、Model No.)は語彙表 model-code-label が言う。
|
|
8
|
+
|
|
9
|
+
type ModelCodeFinding = { readonly offset: number; readonly name: string; readonly usual: string; readonly kind: string };
|
|
10
|
+
|
|
11
|
+
/** 文書の題: 一番浅い見出しのうち最初のもの。 */
|
|
12
|
+
const titleOf = (doc: ProseDocument): MarkupHeading | undefined => {
|
|
13
|
+
const headings = doc.markup?.headings ?? [];
|
|
14
|
+
const top = Math.min(...headings.map((heading) => heading.depth));
|
|
15
|
+
return headings.find((heading) => heading.depth === top);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** 題か型番の欄に書いた型番を、ほかの所(題・表の升も)で別の形に書いた所。prose は見出しと表を覆うので、題と升の字を書き戻して読む。 */
|
|
19
|
+
export const modelCodeFindings = (doc: ProseDocument, prose: string): ModelCodeFinding[] => {
|
|
20
|
+
const title = titleOf(doc);
|
|
21
|
+
const titleSpans = title === undefined ? [] : [{ start: title.start, end: title.end, text: doc.source.slice(title.start, title.end) }];
|
|
22
|
+
const text = proseWithCells(prose, [...titleSpans, ...(doc.tableCells?.() ?? tableBodyCells(proseAndTablesOf(doc)))]);
|
|
23
|
+
const labels = (doc.lexicons["model-code-label"] ?? []).map((entry) => entry.pattern);
|
|
24
|
+
const titleCodes = title === undefined ? [] : codesInTitle(text, title.start, title.end);
|
|
25
|
+
const anchors = [...titleCodes, ...codesAfterLabels(text, labels)].toSorted((left, right) => left.offset - right.offset);
|
|
26
|
+
return modelCodeVariants(text, anchors).map(({ code, usual }) => ({ offset: code.offset, name: code.surface, usual, kind: "model-code" }));
|
|
27
|
+
};
|