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
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Span } from "../plugin.ts";
|
|
2
|
+
import type { StructureIssue } from "./issues.ts";
|
|
3
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 書いた定員より多い申込・招待・参加の人数(定員:90名 と 95名の方にお申し込み、Capacity: 90 seats と 95 members have registered)。
|
|
7
|
+
* 定員の語(定員、先着、capacity、limited to)と人数の語(申込、招待者、have registered)を付けた数だけを読み、語の無い数は読まない。
|
|
8
|
+
* 比べるのは、文書に定員が一つ(一つの値)だけ書いてあるときだけ。二つ以上あれば、どの人数がどの定員のものか決められない。
|
|
9
|
+
* 数える物の組が違う数(30組と45名)は比べない。キャンセル待ちや抽選の語が文書にあれば、定員を超える申込は書いたとおりのことなので
|
|
10
|
+
* 言わない。一回あたりの数(各回定員20名、20 per session)は、定員でも人数でも比べない。全体の人数と一回の定員は比べられない。
|
|
11
|
+
* 去年や前回の人数(昨年は120名が参加)は、この催しの人数ではないので読まない。語は言語パッケージの語彙表から受け取る。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** 語彙表の一語。position は数のどちら側に書くか。group は語の種類(数える物の組、place の付いた定員の語)。 */
|
|
15
|
+
export type CountMark = { readonly pattern: string; readonly position?: "before" | "after" | undefined; readonly group?: string | undefined };
|
|
16
|
+
|
|
17
|
+
export type CapacityWords = {
|
|
18
|
+
/** 定員の語。group が place のものは、席の数(seats、places)にだけ付く(there are 25 places)。 */
|
|
19
|
+
readonly capacities: readonly CountMark[];
|
|
20
|
+
/** 申込・招待・参加の人数の語。 */
|
|
21
|
+
readonly counts: readonly CountMark[];
|
|
22
|
+
/** 数える物の語(名、人、席、people、seats)。group は組(head は人、place は席で人と比べる、party は組や家族)。 */
|
|
23
|
+
readonly units: readonly CountMark[];
|
|
24
|
+
/** 文書にあれば定員を超える申込を言わない語(キャンセル待ち、抽選、waitlist)。 */
|
|
25
|
+
readonly overflows: readonly string[];
|
|
26
|
+
/** 同じ行にあれば一回・一日あたりの数だと言う語(各回、per session)。 */
|
|
27
|
+
readonly perSession: readonly string[];
|
|
28
|
+
/** 人数と同じ行にあれば別の時の人数だと言う語(昨年、前回、last year)。 */
|
|
29
|
+
readonly otherOccasions: readonly string[];
|
|
30
|
+
/** 人数の後ろの句にあれば、申し込んでいない人の数だと言う語(していません、not)。 */
|
|
31
|
+
readonly negations: readonly string[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** 句の切れ目。人数の後ろの打ち消しは、ここまでで探す。 */
|
|
35
|
+
const CLAUSE_BREAK = /[。..!?!?;;、,,\n]/u;
|
|
36
|
+
|
|
37
|
+
const clauseAfter = (source: string, end: number): string => {
|
|
38
|
+
const rest = source.slice(end);
|
|
39
|
+
const cut = CLAUSE_BREAK.exec(rest)?.index ?? rest.length;
|
|
40
|
+
return rest.slice(0, cut);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** 語の付いた数。unit は数える物の組で、単位を書かない数(capacity 30)は undefined。line はその数の行。 */
|
|
44
|
+
export type LabelledCount = {
|
|
45
|
+
readonly start: number;
|
|
46
|
+
readonly end: number;
|
|
47
|
+
readonly value: number;
|
|
48
|
+
readonly unit: string | undefined;
|
|
49
|
+
readonly line: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const DIGIT = "[0-90-9]";
|
|
53
|
+
/** 整数(1,200 は千二百)。小数と、桁区切りの続きの途中からは読まない。 */
|
|
54
|
+
const NUMBER = new RegExp(`(?<!${DIGIT}|[.,,.])${DIGIT}+(?:[,,]${DIGIT}{3})*(?!${DIGIT}|[.,,.]${DIGIT})`, "gu");
|
|
55
|
+
|
|
56
|
+
/** 記号と空白を除いて、語と数の間に挟んでよいもの(定員:90名、定員は25名、capacity of 30、registrations: 45)。 */
|
|
57
|
+
const BEFORE_GAP_WORDS: ReadonlySet<string> = new Set(["", "は", "が", "of", "is", "was", "at"]);
|
|
58
|
+
const isBeforeGap = (gap: string): boolean => BEFORE_GAP_WORDS.has(lower(gap.replaceAll(/[\s::=]/gu, "")));
|
|
59
|
+
/** 数(と単位)と後ろの和語の間に挟んでよいもの(95名の方にお申し込み、28名のお申し込み)。 */
|
|
60
|
+
const AFTER_GAP_CJK = /^(?:の方|の皆様|の皆さま)?(?:[にがの]|から)?[おご]?$/u;
|
|
61
|
+
/** 数(と単位)と後ろの英語の間の語は三つまで(95 members have registered、28 children had already booked)。 */
|
|
62
|
+
const AFTER_GAP_LATIN = /^(?:\s+[A-Za-z]+){0,3}\s+$/u;
|
|
63
|
+
/** 英語の単位は数との間に空白を一つ置ける(90 seats)。 */
|
|
64
|
+
const LATIN_UNIT_GAP = /^\s?/u;
|
|
65
|
+
const WORD_NEXT = /^\s?[A-Za-z]/u;
|
|
66
|
+
|
|
67
|
+
const LETTER = /[A-Za-z]/u;
|
|
68
|
+
|
|
69
|
+
const lower = (text: string): string => text.toLowerCase();
|
|
70
|
+
|
|
71
|
+
const isLatin = (word: string): boolean => LETTER.test(word.charAt(0));
|
|
72
|
+
|
|
73
|
+
const numberOf = (digits: string): number => Number(digits.normalize("NFKC").replaceAll(/[,,]/gu, ""));
|
|
74
|
+
|
|
75
|
+
const startsWithWord = (text: string, word: string): boolean =>
|
|
76
|
+
lower(text).startsWith(lower(word)) && !(LETTER.test(word.slice(-1)) && LETTER.test(text.charAt(word.length)));
|
|
77
|
+
|
|
78
|
+
const endsWithWord = (text: string, word: string): boolean =>
|
|
79
|
+
lower(text).endsWith(lower(word)) && !(LETTER.test(word.charAt(0)) && LETTER.test(text.charAt(text.length - word.length - 1)));
|
|
80
|
+
|
|
81
|
+
/** 英字の語は語の切れ目で照らす(past が pastry に当たらない)。 */
|
|
82
|
+
const contains = (text: string, words: readonly string[]): boolean =>
|
|
83
|
+
words.some((word) =>
|
|
84
|
+
[...lower(text).matchAll(new RegExp(escapeRegExp(lower(word)), "gu"))].some(
|
|
85
|
+
(match) => startsWithWord(text.slice(match.index), word) && endsWithWord(text.slice(0, match.index + word.length), word),
|
|
86
|
+
),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
type Unit = { readonly mark: CountMark; readonly end: number };
|
|
90
|
+
|
|
91
|
+
/** 数のすぐ後ろの単位と、単位の終わりの位置。長い語から照らす。 */
|
|
92
|
+
const unitAfter = (line: string, end: number, units: readonly CountMark[]): Unit | undefined =>
|
|
93
|
+
units
|
|
94
|
+
.toSorted((left, right) => right.pattern.length - left.pattern.length)
|
|
95
|
+
.flatMap((mark) => {
|
|
96
|
+
const gap = isLatin(mark.pattern) ? (LATIN_UNIT_GAP.exec(line.slice(end))?.[0].length ?? 0) : 0;
|
|
97
|
+
return startsWithWord(line.slice(end + gap), mark.pattern) ? [{ mark, end: end + gap + mark.pattern.length }] : [];
|
|
98
|
+
})[0];
|
|
99
|
+
|
|
100
|
+
const labelBefore = (head: string, marks: readonly CountMark[]): CountMark | undefined =>
|
|
101
|
+
marks
|
|
102
|
+
.filter((mark) => mark.position !== "after")
|
|
103
|
+
.find((mark) => {
|
|
104
|
+
const at = lower(head).lastIndexOf(lower(mark.pattern));
|
|
105
|
+
const end = at + mark.pattern.length;
|
|
106
|
+
return at !== -1 && endsWithWord(head.slice(0, end), mark.pattern) && isBeforeGap(head.slice(end));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const labelAfter = (tail: string, marks: readonly CountMark[]): CountMark | undefined =>
|
|
110
|
+
marks
|
|
111
|
+
.filter((mark) => mark.position === "after")
|
|
112
|
+
.find((mark) => {
|
|
113
|
+
const at = lower(tail).indexOf(lower(mark.pattern));
|
|
114
|
+
if (at === -1 || !startsWithWord(tail.slice(at), mark.pattern)) return false;
|
|
115
|
+
return (isLatin(mark.pattern) ? AFTER_GAP_LATIN : AFTER_GAP_CJK).test(tail.slice(0, at));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 語の付いた数か。和語の語には単位が要る(定員90 は読まない)。英語の数は単位を書かなくてよいが、後ろに単位でない語が続けば
|
|
120
|
+
* 別の物の数(capacity 30 cars)。place の付いた語は席の数にだけ付く。
|
|
121
|
+
*/
|
|
122
|
+
const isLabelled = (label: CountMark | undefined, unit: Unit | undefined, after: string, afterLabel: CountMark | undefined): label is CountMark => {
|
|
123
|
+
if (label === undefined || (label.group === "place" && unit?.mark.group !== "place")) return false;
|
|
124
|
+
if (unit !== undefined) return true;
|
|
125
|
+
return isLatin(label.pattern) && (afterLabel !== undefined || !WORD_NEXT.test(after));
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/** 一行の中の、語の付いた数。 */
|
|
129
|
+
const labelledIn = (line: string, lineStart: number, marks: readonly CountMark[], units: readonly CountMark[]): LabelledCount[] =>
|
|
130
|
+
[...line.matchAll(NUMBER)].flatMap((match) => {
|
|
131
|
+
const unit = unitAfter(line, match.index + match[0].length, units);
|
|
132
|
+
const end = unit?.end ?? match.index + match[0].length;
|
|
133
|
+
const after = line.slice(end);
|
|
134
|
+
const afterLabel = labelAfter(after, marks);
|
|
135
|
+
if (!isLabelled(labelBefore(line.slice(0, match.index), marks) ?? afterLabel, unit, after, afterLabel)) return [];
|
|
136
|
+
return [{ start: lineStart + match.index, end: lineStart + end, value: numberOf(match[0]), unit: unit?.mark.group, line }];
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const linesOf = (source: string): { readonly text: string; readonly start: number }[] => {
|
|
140
|
+
const starts = [0, ...[...source.matchAll(/\n/gu)].map((match) => match.index + 1)];
|
|
141
|
+
return starts.map((start, index) => ({ text: source.slice(start, (starts[index + 1] ?? source.length + 1) - 1), start }));
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const readAll = (source: string, marks: readonly CountMark[], units: readonly CountMark[]): LabelledCount[] =>
|
|
145
|
+
linesOf(source).flatMap((line) => labelledIn(line.text, line.start, marks, units));
|
|
146
|
+
|
|
147
|
+
/** 席(place)は人(head)と同じ組として比べる。単位を書かない数は人の数。 */
|
|
148
|
+
export const comparableGroup = (unit: string | undefined): string => (unit === undefined || unit === "place" ? "head" : unit);
|
|
149
|
+
|
|
150
|
+
/** 文書の中の、定員の語の付いた数。一回あたりの定員は除く。 */
|
|
151
|
+
export const capacityStatements = (source: string, words: CapacityWords): LabelledCount[] =>
|
|
152
|
+
readAll(source, words.capacities, words.units).filter((reading) => !contains(reading.line, words.perSession));
|
|
153
|
+
|
|
154
|
+
/** 文書の中の、人数の語の付いた数。一回あたりの人数と、別の時の人数は除く。 */
|
|
155
|
+
export const countStatements = (source: string, words: CapacityWords): LabelledCount[] =>
|
|
156
|
+
readAll(source, words.counts, words.units).filter(
|
|
157
|
+
(reading) =>
|
|
158
|
+
!contains(reading.line, words.perSession) &&
|
|
159
|
+
!contains(reading.line, words.otherOccasions) &&
|
|
160
|
+
!contains(clauseAfter(source, reading.end), words.negations),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
/** 定員を超える人数のうち一番多いもの。定員が一つの値でなければ、比べない。 */
|
|
164
|
+
export const overCapacity = (
|
|
165
|
+
capacities: readonly LabelledCount[],
|
|
166
|
+
counts: readonly LabelledCount[],
|
|
167
|
+
): { readonly capacity: LabelledCount; readonly over: LabelledCount } | undefined => {
|
|
168
|
+
const capacity = capacities[0];
|
|
169
|
+
if (capacity === undefined || capacities.some((other) => other.value !== capacity.value)) return undefined;
|
|
170
|
+
const over = counts
|
|
171
|
+
.filter((count) => comparableGroup(count.unit) === comparableGroup(capacity.unit) && count.value > capacity.value)
|
|
172
|
+
.toSorted((left, right) => right.value - left.value)[0];
|
|
173
|
+
return over === undefined ? undefined : { capacity, over };
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/** その位置を含む一番小さい節の原文。節が無ければ文書の全体。 */
|
|
177
|
+
export const sectionAround = (source: string, offset: number, sections: readonly Span[]): string => {
|
|
178
|
+
const around = sections
|
|
179
|
+
.filter((section) => section.start <= offset && offset < section.end)
|
|
180
|
+
.toSorted((left, right) => left.end - left.start - (right.end - right.start))[0];
|
|
181
|
+
return around === undefined ? source : source.slice(around.start, around.end);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 定員より多い人数。キャンセル待ちや抽選の語のある節の定員と人数は読まない(定員を超える申込が書いたとおりのこと)。
|
|
186
|
+
* 節に限るのは、別の節の「抽選会」(催しの一つ)で比べるのをやめないため。定員の位置を指す。sections は節の範囲。
|
|
187
|
+
*/
|
|
188
|
+
export const countsOverCapacity = (source: string, words: CapacityWords, sections: readonly Span[] = []): StructureIssue[] => {
|
|
189
|
+
const settled = (reading: LabelledCount): boolean => !contains(sectionAround(source, reading.start, sections), words.overflows);
|
|
190
|
+
const capacities = capacityStatements(source, words);
|
|
191
|
+
if (!capacities.every(settled)) return [];
|
|
192
|
+
const found = overCapacity(capacities, countStatements(source, words).filter(settled));
|
|
193
|
+
if (found === undefined) return [];
|
|
194
|
+
const { capacity, over } = found;
|
|
195
|
+
return [{ offset: capacity.start, values: { capacity: source.slice(capacity.start, capacity.end), count: source.slice(over.start, over.end) } }];
|
|
196
|
+
};
|
|
@@ -7,10 +7,10 @@ import type { Amount } from "./total.ts";
|
|
|
7
7
|
export type SummedCounter = { readonly pattern: string; readonly unit: string };
|
|
8
8
|
|
|
9
9
|
/** 前に英字や数や小数点が続く数(v2、A4、1.2.3 の 2)は読まない。日本語は数の前に空白を置かないので、仮名や漢字の後ろはよい。 */
|
|
10
|
-
const NUMBER = /(?<![\p{Script=Latin}\p{N}.,.,])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
|
|
10
|
+
export const NUMBER = /(?<![\p{Script=Latin}\p{N}.,.,])[0-90-9]+(?:[,,][0-90-9]{3})*(?:[..][0-90-9]+)?/gu;
|
|
11
11
|
|
|
12
12
|
/** 助数詞に文字や数、つなぎの - _ が詰めて続くもの(3単位目、4コマ漫画、3 unit-priced)は、別の語の一部。 */
|
|
13
|
-
const CONTINUES_WORD = /^[\p{L}\p{N}_-]/u;
|
|
13
|
+
export const CONTINUES_WORD = /^[\p{L}\p{N}_-]/u;
|
|
14
14
|
|
|
15
15
|
/** 序数の印(第3回)。 */
|
|
16
16
|
const ORDINAL_MARK = "第";
|
|
@@ -18,7 +18,7 @@ const ORDINAL_MARK = "第";
|
|
|
18
18
|
/** 助数詞を探す長さ。どの助数詞よりも長い。 */
|
|
19
19
|
const LOOKAHEAD = 32;
|
|
20
20
|
|
|
21
|
-
const valueOf = (written: string): number => Number(written.normalize("NFKC").replace(/,/gu, ""));
|
|
21
|
+
export const valueOf = (written: string): number => Number(written.normalize("NFKC").replace(/,/gu, ""));
|
|
22
22
|
|
|
23
23
|
/** 数のすぐ後ろ(空白一つまで)の助数詞。長い語から試す。大文字小文字は区別しない(4 Credits)。 */
|
|
24
24
|
const counterAfter = (source: string, end: number, counters: readonly SummedCounter[]): { unit: string; end: number } | undefined => {
|
|
@@ -28,7 +28,8 @@ const counterAfter = (source: string, end: number, counters: readonly SummedCoun
|
|
|
28
28
|
return counter === undefined ? undefined : { unit: counter.unit, end: end + gap + counter.pattern.length };
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
const overlapsAny = (start: number, end: number, amounts: readonly Amount[]): boolean =>
|
|
31
|
+
export const overlapsAny = (start: number, end: number, amounts: readonly Amount[]): boolean =>
|
|
32
|
+
amounts.some((amount) => start < amount.end && amount.offset < end);
|
|
32
33
|
|
|
33
34
|
/** 文書の中の、足してよい助数詞の付いた数。木がすでに数量として読んだもの(known)とは重ねない。 */
|
|
34
35
|
export const countedAmounts = (source: string, counters: readonly SummedCounter[], known: readonly Amount[]): Amount[] => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { escapeRegExp } from "../orthography.ts";
|
|
2
2
|
import type { StructureIssue } from "./issues.ts";
|
|
3
3
|
import { TABLE_ROW } from "./runs.ts";
|
|
4
|
+
import { deadlineVerdict } from "./term-deadline.ts";
|
|
4
5
|
import { statedPeriod, type DateMention, type Period, type PeriodWords } from "./stated-period.ts";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -9,7 +10,7 @@ import { statedPeriod, type DateMention, type Period, type PeriodWords } from ".
|
|
|
9
10
|
* 期間の前後に置く予定(前泊、follow-up)、締め切りや予約の日、過去の回を言う語(period-aside)が、その行、文、節の見出しにあれば比べない。
|
|
10
11
|
* 年の無い期間(12月28日〜1月4日)は年をまたいで読む。
|
|
11
12
|
* 文書の仕事の期間(開講期間:…)を文書の頭か概要の節で書いたものは文書全体の期間で、後ろのどの節でも、締め切りの語(period-deadline)のある項目や文の、
|
|
12
|
-
*
|
|
13
|
+
* 期間の終わりより後の日付を指す(課題の提出が学期の後)。年の無い日付は、期間が一つの年に収まるときだけその年と読む。成績発表や再試験の語(period-after-term)のある日付は比べない。期間の前の締め切り(申込締切)と、旅行期間のように後に締め切りが来てよい期間は比べない。
|
|
13
14
|
*/
|
|
14
15
|
export type HeadingSpan = { readonly start: number; readonly end: number; readonly depth: number };
|
|
15
16
|
type Span = { readonly start: number; readonly end: number };
|
|
@@ -20,6 +21,8 @@ export type OutsideWords = PeriodWords & {
|
|
|
20
21
|
readonly terms: readonly string[];
|
|
21
22
|
readonly deadlines: readonly string[];
|
|
22
23
|
readonly overviews: readonly string[];
|
|
24
|
+
/** 期間の後に来てよい仕事の語(成績発表、再試験)。この語のある締め切りは期間と比べない。 */
|
|
25
|
+
readonly afterTerm: readonly string[];
|
|
23
26
|
};
|
|
24
27
|
|
|
25
28
|
const LIST_ITEM = /^[ \t]{0,12}(?:[-*+]|\d{1,3}[.)])[ \t]/u;
|
|
@@ -143,15 +146,17 @@ const isDocumentTerm = (period: Stated, context: Context, overviews: readonly st
|
|
|
143
146
|
return enclosingHeadings(period.line.start, context.headings).some((heading) => mentions(context.source.slice(heading.start, heading.end), overviews));
|
|
144
147
|
};
|
|
145
148
|
|
|
146
|
-
const afterEnd = (value: string, period: Period): boolean => hasYear(value) && hasYear(period.end) && value > period.end;
|
|
147
|
-
|
|
148
149
|
const lateDeadline = (date: DateMention, period: Stated, context: Context, words: OutsideWords): boolean => {
|
|
149
|
-
if (!DAY_VALUE.test(date.value)
|
|
150
|
+
if (!DAY_VALUE.test(date.value)) return false;
|
|
150
151
|
const line = containing(context.lines, date.offset);
|
|
151
152
|
if (line === undefined) return false;
|
|
152
153
|
const texts = surroundings(date, line, isItem(context.source.slice(line.start, line.end), line, context.headings), context);
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
const marks = {
|
|
155
|
+
deadline: mentions(texts[0] ?? "", words.deadlines),
|
|
156
|
+
aside: texts.some((text) => mentions(withoutWords(text, words.deadlines), words.asides)),
|
|
157
|
+
afterTerm: mentions(texts[0] ?? "", words.afterTerm),
|
|
158
|
+
};
|
|
159
|
+
return deadlineVerdict(date.value, period, marks) === "late";
|
|
155
160
|
};
|
|
156
161
|
|
|
157
162
|
const issueOf = (source: string, date: DateMention, period: Stated): StructureIssue => ({
|
|
@@ -140,7 +140,7 @@ const bareFramed = (source: string, start: DatedSpan, end: DatedSpan, written: s
|
|
|
140
140
|
return (isLabelled(start.offset) || withWeekdays) && !isChange(source, start, end, words);
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
-
const isRange = (source: string, start: DatedSpan, end: DatedSpan, words: RangeWords, isLabelled: (offset: number) => boolean): boolean => {
|
|
143
|
+
export const isRange = (source: string, start: DatedSpan, end: DatedSpan, words: RangeWords, isLabelled: (offset: number) => boolean): boolean => {
|
|
144
144
|
const written = jointOf(source, start, end);
|
|
145
145
|
if (written === undefined) return false;
|
|
146
146
|
const joint = withoutTrailingWeekday(written, words.weekdays ?? []);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { mentions } from "./date-outside-period.ts";
|
|
2
|
+
import type { DatedPoint } from "./due-date.ts";
|
|
3
|
+
import type { StructureIssue } from "./issues.ts";
|
|
4
|
+
import { lineNumberAt, linesOf, type Line } from "./lines.ts";
|
|
5
|
+
import { isTotalLabel } from "./total.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 催しの後の申込締切。催しの日の語で始まり時刻のある一行(日時:2026年11月20日(金)14:00〜)が催しの日を書き、
|
|
9
|
+
* 申込の語(申込、RSVP)と締め切りの語(までに、by)のある文か行の、年のある日付がどの催しの日よりも後なら指す。
|
|
10
|
+
* 時刻を求めるのは、手紙の頭の「Date: …」を催しの日と読まないため。催しの後に来てよいもの(アンケート、支払)の語が同じ文にあれば比べない。
|
|
11
|
+
* 文か行に日付が二つ以上あれば、どれが締め切りか分からないので比べない。Pure.
|
|
12
|
+
*/
|
|
13
|
+
export type EventDeadlineWords = {
|
|
14
|
+
readonly events: readonly string[];
|
|
15
|
+
readonly registrations: readonly string[];
|
|
16
|
+
readonly deadlines: readonly string[];
|
|
17
|
+
readonly asides: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type Span = { readonly start: number; readonly end: number };
|
|
21
|
+
|
|
22
|
+
const FULL_DATE = /^\d{4}-\d{2}-\d{2}$/u;
|
|
23
|
+
const CLOCK_TIME = /(?<!\d)\d{1,2}[::]\d{2}(?!\d)/u;
|
|
24
|
+
|
|
25
|
+
/** 年月日(2026-11-20)の並びでいちばん後のもの。字の順が日付の順になる。 */
|
|
26
|
+
const latestOf = (values: readonly string[]): string | undefined =>
|
|
27
|
+
values.reduce<string | undefined>((latest, value) => (latest === undefined || value > latest ? value : latest), undefined);
|
|
28
|
+
|
|
29
|
+
const endOf = (line: Line): number => line.start + line.text.length;
|
|
30
|
+
|
|
31
|
+
const datesIn = (dates: readonly DatedPoint[], span: Span): DatedPoint[] => dates.filter((date) => date.offset >= span.start && date.offset < span.end);
|
|
32
|
+
|
|
33
|
+
/** 催しの日: 催しの日の語で始まり、時刻と年のある日付を書いた行の、いちばん後の日付。 */
|
|
34
|
+
const eventDayOf = (line: Line, dates: readonly DatedPoint[], words: EventDeadlineWords): string | undefined => {
|
|
35
|
+
if (!isTotalLabel(line.text, words.events) || !CLOCK_TIME.test(line.text)) return undefined;
|
|
36
|
+
const values = datesIn(dates, { start: line.start, end: endOf(line) }).map((date) => date.value);
|
|
37
|
+
return latestOf(values.filter((value) => FULL_DATE.test(value)));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** 日付を囲む文を、その行の中に切ったもの。文が見つからなければ行。 */
|
|
41
|
+
const unitOf = (offset: number, line: Line, sentences: readonly Span[]): Span => {
|
|
42
|
+
const sentence = sentences.find((span) => span.start <= offset && offset < span.end);
|
|
43
|
+
return { start: Math.max(sentence?.start ?? line.start, line.start), end: Math.min(sentence?.end ?? endOf(line), endOf(line)) };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** 申込の締め切りを書いた文か: 申込の語と締め切りの語があり、催しの後に来てよいものの語が無い。 */
|
|
47
|
+
export const isRegistrationDeadline = (text: string, words: EventDeadlineWords): boolean =>
|
|
48
|
+
mentions(text, words.registrations) && mentions(text, words.deadlines) && !mentions(text, words.asides);
|
|
49
|
+
|
|
50
|
+
type Reading = { readonly source: string; readonly lines: readonly Line[]; readonly dates: readonly DatedPoint[]; readonly sentences: readonly Span[] };
|
|
51
|
+
|
|
52
|
+
const lateDeadlines = (reading: Reading, words: EventDeadlineWords, event: string): StructureIssue[] =>
|
|
53
|
+
reading.dates.flatMap((date) => {
|
|
54
|
+
if (!FULL_DATE.test(date.value) || date.value <= event) return [];
|
|
55
|
+
const line = reading.lines[(lineNumberAt(reading.lines, date.offset) ?? 0) - 1];
|
|
56
|
+
if (line === undefined) return [];
|
|
57
|
+
const unit = unitOf(date.offset, line, reading.sentences);
|
|
58
|
+
if (datesIn(reading.dates, unit).length > 1 || !isRegistrationDeadline(reading.source.slice(unit.start, unit.end), words)) return [];
|
|
59
|
+
return [{ offset: date.offset, values: { deadline: date.value, event } }];
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const deadlinesAfterEvent = (source: string, dates: readonly DatedPoint[], sentences: readonly Span[], words: EventDeadlineWords): StructureIssue[] => {
|
|
63
|
+
if (words.events.length === 0 || words.registrations.length === 0 || words.deadlines.length === 0) return [];
|
|
64
|
+
const lines = linesOf(source);
|
|
65
|
+
const event = latestOf(lines.flatMap((line) => eventDayOf(line, dates, words) ?? []));
|
|
66
|
+
return event === undefined ? [] : lateDeadlines({ source, lines, dates, sentences }, words, event);
|
|
67
|
+
};
|
|
@@ -148,6 +148,58 @@ const continuesInHan = (texts: readonly BodyText[], term: string, offset: number
|
|
|
148
148
|
return body !== undefined && HAN.test(term.at(-1) ?? "") && HAN.test(body.text.charAt(offset - body.start + term.length));
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
+
/** 半角の長音・濁点・中黒(ー ゙ ゚ ・)は Katakana の字ではないが、片仮名の名前の一部。 */
|
|
152
|
+
const KATAKANA = /[\p{Script=Katakana}ーー゙゚]/u;
|
|
153
|
+
const NAKAGURO = /[・・]/u;
|
|
154
|
+
|
|
155
|
+
/** 語の外側の隣の字(next)とその向こうの字(beyond)が、片仮名か「・片仮名」か。 */
|
|
156
|
+
const katakanaJoins = (next: string, beyond: string): boolean => KATAKANA.test(next) || (NAKAGURO.test(next) && KATAKANA.test(beyond));
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 片仮名の端に片仮名が続く現れ、または「・」で片仮名とつないだ現れは、もっと長い名前の一部
|
|
160
|
+
* (クリエイティブ・コモンズ・パブリック・ライセンスのパブリック・ライセンス、サブライセンスのライセンス)。
|
|
161
|
+
*/
|
|
162
|
+
const insideKatakanaName = (texts: readonly BodyText[], term: string, offset: number): boolean => {
|
|
163
|
+
const body = sentenceAt(texts, offset);
|
|
164
|
+
if (body === undefined) return false;
|
|
165
|
+
const at = offset - body.start;
|
|
166
|
+
const end = at + term.length;
|
|
167
|
+
const joinedBefore = at > 0 && katakanaJoins(body.text.charAt(at - 1), at > 1 ? body.text.charAt(at - 2) : "");
|
|
168
|
+
const joinedAfter = katakanaJoins(body.text.charAt(end), body.text.charAt(end + 1));
|
|
169
|
+
return (KATAKANA.test(term.charAt(0)) && joinedBefore) || (KATAKANA.test(term.at(-1) ?? "") && joinedAfter);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/** 長い名前の写しと読むのに、語の前で定義の名前と重ならなければならない字の数(手引き の前の「の」と「成」)。 */
|
|
173
|
+
const MIN_ECHO = 2;
|
|
174
|
+
const OPENING_BRACKET = /[\s((]/u;
|
|
175
|
+
|
|
176
|
+
/** 定義の括弧を開けた字((、空白)を後ろから外した、括弧の前の名前。 */
|
|
177
|
+
const nameBefore = (text: string): string => {
|
|
178
|
+
let end = text.length;
|
|
179
|
+
while (end > 0 && OPENING_BRACKET.test(text.charAt(end - 1))) end -= 1;
|
|
180
|
+
return text.slice(0, end);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/** 二つの文字列が後ろから何字重なるか。 */
|
|
184
|
+
const sharedTail = (left: string, right: string): number => {
|
|
185
|
+
let shared = 0;
|
|
186
|
+
while (shared < left.length && shared < right.length && left.at(-1 - shared) === right.at(-1 - shared)) shared += 1;
|
|
187
|
+
return shared;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 定義の括弧の前に書いた長い名前(…ガイドライン作成の手引き(以下、「手引き」という。))を、定義より前でそのまま書いた所。
|
|
192
|
+
* 名前が語で終わり、語の前の字も名前と同じなら、それは長い名前で、定義した短い名前の使用ではない。
|
|
193
|
+
*/
|
|
194
|
+
const echoesLongName = (texts: readonly BodyText[], defined: DefinedTerm, offset: number): boolean => {
|
|
195
|
+
const defining = sentenceAt(texts, defined.span.start);
|
|
196
|
+
const using = sentenceAt(texts, offset);
|
|
197
|
+
if (defining === undefined || using === undefined) return false;
|
|
198
|
+
const name = nameBefore(defining.text.slice(0, defined.span.start - defining.start));
|
|
199
|
+
const written = using.text.slice(0, offset - using.start + defined.term.length);
|
|
200
|
+
return name.endsWith(defined.term) && sharedTail(name, written) >= defined.term.length + MIN_ECHO;
|
|
201
|
+
};
|
|
202
|
+
|
|
151
203
|
const CAPITAL_OR_NON_LATIN = /\p{Lu}|[^\p{Script=Latin}\p{N}\s\p{P}]/u;
|
|
152
204
|
|
|
153
205
|
/**
|
|
@@ -159,7 +211,7 @@ const isDistinctive = (term: string): boolean => CAPITAL_OR_NON_LATIN.test(term)
|
|
|
159
211
|
/**
|
|
160
212
|
* 文の途中で括弧に入れて定義した語((the "Seller")、以下「甲」という)を、その定義の文より前で使っている所。最初の一つだけ。
|
|
161
213
|
* 定義の文の中の現れ(株式会社GovTech東京(以下「GovTech東京」という。))は、定義する名前そのものなので数えない。札の文も、
|
|
162
|
-
* isTitle
|
|
214
|
+
* isTitle が言う題・見出しの行も、漢字で終わる語にさらに漢字が続く長い語の一部も、定義の括弧の前の長い名前を写した所も数えない。
|
|
163
215
|
* 定義の条("Seller" means、「甲」とは)は条の並びの頭にも終わりにも置く書き方があるので、前で使っても言わない。
|
|
164
216
|
* 定義の語の無い括弧の引用(("The key point is"))は例の引用と同じ形なので、その語を引用符で挙げただけの現れ
|
|
165
217
|
* (Its sentences open with "The key point is")は使用ではない。定義の語のある定義((the "Seller")、以下「買主」という)は、
|
|
@@ -177,7 +229,12 @@ export const usesBeforeDefinition = (
|
|
|
177
229
|
const defining = sentenceAt(texts, defined.span.start)?.start ?? defined.span.start;
|
|
178
230
|
const uses = usesOf(defined.term, texts, spans, "exact", defined.bare === true ? mentioned : NEVER_MENTIONED);
|
|
179
231
|
const first = uses.find(
|
|
180
|
-
(offset) =>
|
|
232
|
+
(offset) =>
|
|
233
|
+
!isLabel(sentenceAt(texts, offset), defined.term) &&
|
|
234
|
+
!isTitle(offset) &&
|
|
235
|
+
!continuesInHan(texts, defined.term, offset) &&
|
|
236
|
+
!insideKatakanaName(texts, defined.term, offset) &&
|
|
237
|
+
!echoesLongName(texts, defined, offset),
|
|
181
238
|
);
|
|
182
239
|
return first !== undefined && first < defining ? [{ term: defined, offset: first }] : [];
|
|
183
240
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { datesOutOfOrder } from "./labelled-date-order.ts";
|
|
1
2
|
import type { StructureIssue } from "./issues.ts";
|
|
2
|
-
import { linesOf } from "./lines.ts";
|
|
3
|
-
import { isTotalLabel } from "./total.ts";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* A due date before the issue date. A line (or a list item, or a table's first column) starting with an issue-date word
|
|
@@ -10,37 +9,14 @@ import { isTotalLabel } from "./total.ts";
|
|
|
10
9
|
*/
|
|
11
10
|
export type DueWords = { readonly issue: readonly string[]; readonly due: readonly string[]; readonly passed: readonly string[] };
|
|
12
11
|
|
|
13
|
-
/** How many lines from the issue date a due date may be and still be read as the same document's deadline. */
|
|
14
|
-
const MAX_LINE_GAP = 8;
|
|
15
|
-
|
|
16
12
|
/** A date of the structure tree: where it starts and its value (2026-11-25). */
|
|
17
13
|
export type DatedPoint = { readonly offset: number; readonly value: string };
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type Labelled = { readonly kind: "issue" | "due"; readonly date: DatedPoint; readonly line: number };
|
|
22
|
-
|
|
23
|
-
const kindOf = (text: string, words: DueWords): Labelled["kind"] | undefined => {
|
|
24
|
-
if (isTotalLabel(text, words.issue)) return "issue";
|
|
25
|
-
return isTotalLabel(text, words.due) ? "due" : undefined;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const labelledDates = (source: string, dates: readonly DatedPoint[], words: DueWords): Labelled[] =>
|
|
29
|
-
linesOf(source).flatMap((line) => {
|
|
30
|
-
const passed = words.passed.some((word) => line.text.toLowerCase().includes(word.toLowerCase()));
|
|
31
|
-
const kind = passed ? undefined : kindOf(line.text, words);
|
|
32
|
-
const end = line.start + line.text.length;
|
|
33
|
-
const onLine = dates.filter((date) => date.offset >= line.start && date.offset <= end && FULL_DATE.test(date.value));
|
|
34
|
-
const [date] = onLine;
|
|
35
|
-
return kind === undefined || date === undefined || onLine.length > 1 ? [] : [{ kind, date, line: line.number }];
|
|
36
|
-
});
|
|
15
|
+
/** How many lines from the issue date a due date may be and still be read as the same document's deadline. */
|
|
16
|
+
const MAX_LINE_GAP = 8;
|
|
37
17
|
|
|
38
|
-
export const dueBeforeIssue = (source: string, dates: readonly DatedPoint[], words: DueWords): StructureIssue[] =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return labelled
|
|
44
|
-
.filter((entry) => entry.kind === "due" && entry.date.value < issued.date.value && Math.abs(entry.line - issued.line) < MAX_LINE_GAP)
|
|
45
|
-
.map((entry) => ({ offset: entry.date.offset, values: { due: entry.date.value, issued: issued.date.value } }));
|
|
46
|
-
};
|
|
18
|
+
export const dueBeforeIssue = (source: string, dates: readonly DatedPoint[], words: DueWords): StructureIssue[] =>
|
|
19
|
+
datesOutOfOrder(source, dates, { earlier: words.issue, later: words.due, passed: words.passed, maxLineGap: MAX_LINE_GAP }).map(({ earlier, later }) => ({
|
|
20
|
+
offset: later.date.offset,
|
|
21
|
+
values: { due: later.date.value, issued: earlier.date.value },
|
|
22
|
+
}));
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { DatedPoint } from "./due-date.ts";
|
|
2
|
+
import type { StructureIssue } from "./issues.ts";
|
|
3
|
+
import { linesOf } from "./lines.ts";
|
|
4
|
+
import { isTotalLabel } from "./total.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Two labelled dates that must come in order: a line (or a list item, or a table's first column) starting with an
|
|
8
|
+
* earlier-date word and one starting with a later-date word, each with one full date on it. A later date before the
|
|
9
|
+
* first earlier date, and written near it, is out of order. A line with a passed word (期限切れ, overdue) reports on a
|
|
10
|
+
* date rather than setting one and is not read. Pure.
|
|
11
|
+
*/
|
|
12
|
+
export type DateOrderWords = {
|
|
13
|
+
readonly earlier: readonly string[];
|
|
14
|
+
readonly later: readonly string[];
|
|
15
|
+
readonly passed: readonly string[];
|
|
16
|
+
/** How many lines from the earlier date a later date may be and still be read as the same record's. */
|
|
17
|
+
readonly maxLineGap: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** A labelled date: the word that labels it, as the lexicon writes it. */
|
|
21
|
+
export type LabelledDate = { readonly label: string; readonly date: DatedPoint; readonly line: number };
|
|
22
|
+
|
|
23
|
+
export type OutOfOrder = { readonly earlier: LabelledDate; readonly later: LabelledDate };
|
|
24
|
+
|
|
25
|
+
const FULL_DATE = /^\d{4}-\d{2}-\d{2}$/u;
|
|
26
|
+
|
|
27
|
+
type Read = LabelledDate & { readonly kind: "earlier" | "later" };
|
|
28
|
+
|
|
29
|
+
const labelOf = (text: string, words: readonly string[]): string | undefined => words.find((word) => isTotalLabel(text, [word]));
|
|
30
|
+
|
|
31
|
+
const kindOf = (text: string, words: DateOrderWords): Pick<Read, "kind" | "label"> | undefined => {
|
|
32
|
+
const earlier = labelOf(text, words.earlier);
|
|
33
|
+
if (earlier !== undefined) return { kind: "earlier", label: earlier };
|
|
34
|
+
const later = labelOf(text, words.later);
|
|
35
|
+
return later === undefined ? undefined : { kind: "later", label: later };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const labelledDates = (source: string, dates: readonly DatedPoint[], words: DateOrderWords): Read[] =>
|
|
39
|
+
linesOf(source).flatMap((line) => {
|
|
40
|
+
const passed = words.passed.some((word) => line.text.toLowerCase().includes(word.toLowerCase()));
|
|
41
|
+
const kind = passed ? undefined : kindOf(line.text, words);
|
|
42
|
+
const end = line.start + line.text.length;
|
|
43
|
+
const onLine = dates.filter((date) => date.offset >= line.start && date.offset <= end && FULL_DATE.test(date.value));
|
|
44
|
+
const [date] = onLine;
|
|
45
|
+
return kind === undefined || date === undefined || onLine.length > 1 ? [] : [{ ...kind, date, line: line.number }];
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const datesOutOfOrder = (source: string, dates: readonly DatedPoint[], words: DateOrderWords): OutOfOrder[] => {
|
|
49
|
+
if (words.earlier.length === 0 || words.later.length === 0) return [];
|
|
50
|
+
const labelled = labelledDates(source, dates, words);
|
|
51
|
+
const earlier = labelled.find((entry) => entry.kind === "earlier");
|
|
52
|
+
if (earlier === undefined) return [];
|
|
53
|
+
return labelled
|
|
54
|
+
.filter((entry) => entry.kind === "later" && entry.date.value < earlier.date.value && Math.abs(entry.line - earlier.line) < words.maxLineGap)
|
|
55
|
+
.map((later) => ({ earlier, later }));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** A lexicon entry naming its pair (group) and its side: before for the earlier date, after for the later one. */
|
|
59
|
+
export type OrderLabel = { readonly pattern: string; readonly group?: string | undefined; readonly position?: "before" | "after" | undefined };
|
|
60
|
+
|
|
61
|
+
const groupsOf = (labels: readonly OrderLabel[]): string[] => [...new Set(labels.flatMap((label) => (label.group === undefined ? [] : [label.group])))];
|
|
62
|
+
|
|
63
|
+
const sideOf = (labels: readonly OrderLabel[], group: string, position: "before" | "after"): string[] =>
|
|
64
|
+
labels.filter((label) => label.group === group && label.position === position).map((label) => label.pattern);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Every pair of a dated-pair lexicon: the entries of one group with position before label the earlier date, those with
|
|
68
|
+
* position after the later one. The values name both labels, so the message can quote them.
|
|
69
|
+
*/
|
|
70
|
+
export const pairedDatesOutOfOrder = (
|
|
71
|
+
source: string,
|
|
72
|
+
dates: readonly DatedPoint[],
|
|
73
|
+
labels: readonly OrderLabel[],
|
|
74
|
+
passed: readonly string[],
|
|
75
|
+
maxLineGap: number,
|
|
76
|
+
): StructureIssue[] =>
|
|
77
|
+
groupsOf(labels).flatMap((group) =>
|
|
78
|
+
datesOutOfOrder(source, dates, { earlier: sideOf(labels, group, "before"), later: sideOf(labels, group, "after"), passed, maxLineGap }).map(
|
|
79
|
+
({ earlier, later }) => ({
|
|
80
|
+
offset: later.date.offset,
|
|
81
|
+
values: { later: later.date.value, earlier: earlier.date.value, later_label: later.label, earlier_label: earlier.label },
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
);
|