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,178 @@
|
|
|
1
|
+
import type { Span } from "../plugin.ts";
|
|
2
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
3
|
+
import type { Mark } from "../structure/time-marks.ts";
|
|
4
|
+
import { linesOf } from "../structure/lines.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Counts of uses in a period (1日3回, 3 times a day, twice in 24 hours) and the words that make a number a limit (まで,
|
|
8
|
+
* no more than, 最大量). The words come from the language packages; nothing here knows a language. Pure.
|
|
9
|
+
*/
|
|
10
|
+
export type PeriodWord = Mark & { readonly hours: number };
|
|
11
|
+
|
|
12
|
+
/** A number written as a word, with its value (three, twice). alone: it counts uses without a counter (twice a day). */
|
|
13
|
+
export type CountWord = { readonly pattern: string; readonly value: number; readonly alone: boolean };
|
|
14
|
+
|
|
15
|
+
export type PeriodCountWords = {
|
|
16
|
+
/** Periods: before the number (1日3回) or after the counter (3 times a day). */
|
|
17
|
+
readonly periods: readonly PeriodWord[];
|
|
18
|
+
/** What a count of uses is written in (回, times, doses). */
|
|
19
|
+
readonly counters: readonly string[];
|
|
20
|
+
readonly numberWords: readonly CountWord[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type PeriodCount = Span & { readonly amount: number; readonly hours: number };
|
|
24
|
+
|
|
25
|
+
const alternation = (words: readonly string[]): string =>
|
|
26
|
+
[...new Set(words.filter((word) => word !== ""))]
|
|
27
|
+
.toSorted((left, right) => right.length - left.length)
|
|
28
|
+
.map(escapeRegExp)
|
|
29
|
+
.join("|");
|
|
30
|
+
|
|
31
|
+
/** A word that does not run on from a Latin letter or a digit before it, or into a Latin letter after it. */
|
|
32
|
+
const bounded = (pattern: string): string => `(?<![A-Za-z0-9])(?:${pattern})(?![A-Za-z])`;
|
|
33
|
+
|
|
34
|
+
const DIGITS = "(?<![\\p{N}.,.])\\p{Nd}+(?:[..]\\p{Nd}+)?";
|
|
35
|
+
|
|
36
|
+
const numberAt = (written: string, words: readonly CountWord[]): number =>
|
|
37
|
+
words.find((word) => word.pattern.toLowerCase() === written.toLowerCase())?.value ?? Number(written.normalize("NFKC"));
|
|
38
|
+
|
|
39
|
+
const periodsOn = (words: PeriodCountWords, side: "before" | "after"): PeriodWord[] => words.periods.filter((period) => (period.position ?? "before") === side);
|
|
40
|
+
|
|
41
|
+
const hoursOf = (words: PeriodCountWords, written: string): number =>
|
|
42
|
+
words.periods.find((period) => period.pattern.toLowerCase() === written.toLowerCase())?.hours ?? 0;
|
|
43
|
+
|
|
44
|
+
/** The hours of the longest period word the match starts with. */
|
|
45
|
+
const periodHoursIn = (written: string, words: PeriodCountWords): number => {
|
|
46
|
+
const found = periodsOn(words, "before")
|
|
47
|
+
.toSorted((left, right) => right.pattern.length - left.pattern.length)
|
|
48
|
+
.find((period) => written.toLowerCase().startsWith(period.pattern.toLowerCase()));
|
|
49
|
+
return found?.hours ?? 0;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** At most this many letters (の, に, あたり) between a period written first and its count: 1日に3回. */
|
|
53
|
+
const JOINER = "[^\\p{N}\\s。、,,..!?!?]{0,4}";
|
|
54
|
+
|
|
55
|
+
/** 1日3回: the period first, then the number and the counter. */
|
|
56
|
+
const periodFirst = (text: string, words: PeriodCountWords): PeriodCount[] => {
|
|
57
|
+
const [periods, counters] = [alternation(periodsOn(words, "before").map((word) => word.pattern)), alternation(words.counters)];
|
|
58
|
+
if (periods === "" || counters === "") return [];
|
|
59
|
+
const pattern = new RegExp(`${bounded(periods)}${JOINER}\\s?(?<digits>${DIGITS})\\s?(?:${counters})`, "giu");
|
|
60
|
+
return [...text.matchAll(pattern)].map((match) => ({
|
|
61
|
+
start: match.index,
|
|
62
|
+
end: match.index + match[0].length,
|
|
63
|
+
amount: Number((match.groups?.["digits"] ?? "").normalize("NFKC")),
|
|
64
|
+
hours: periodHoursIn(match[0], words),
|
|
65
|
+
}));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const namesOf = (words: readonly CountWord[], alone: boolean): string => alternation(words.filter((word) => word.alone === alone).map((word) => word.pattern));
|
|
69
|
+
|
|
70
|
+
/** 3 times a day, twice in 24 hours: the number and the counter first, then the period. */
|
|
71
|
+
const periodLast = (text: string, words: PeriodCountWords): PeriodCount[] => {
|
|
72
|
+
const [periods, counters] = [alternation(periodsOn(words, "after").map((word) => word.pattern)), alternation(words.counters)];
|
|
73
|
+
if (periods === "" || counters === "") return [];
|
|
74
|
+
const [counted, alone] = [namesOf(words.numberWords, false), namesOf(words.numberWords, true)];
|
|
75
|
+
const number = counted === "" ? `(?<digits>${DIGITS})` : `(?:(?<digits>${DIGITS})|(?<word>${bounded(counted)}))`;
|
|
76
|
+
const once = alone === "" ? "" : `|(?<alone>${bounded(alone)})`;
|
|
77
|
+
const pattern = new RegExp(`(?:${number}\\s?${bounded(counters)}${once})\\s+(?<period>${bounded(periods)})`, "giu");
|
|
78
|
+
return [...text.matchAll(pattern)].map((match) => {
|
|
79
|
+
const groups = match.groups ?? {};
|
|
80
|
+
const written = groups["digits"] ?? groups["word"] ?? groups["alone"] ?? "";
|
|
81
|
+
return {
|
|
82
|
+
start: match.index,
|
|
83
|
+
end: match.index + match[0].length,
|
|
84
|
+
amount: numberAt(written, words.numberWords),
|
|
85
|
+
hours: hoursOf(words, groups["period"] ?? ""),
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const FULL_WIDTH_ZERO = 0xff10;
|
|
91
|
+
const ASCII_ZERO = 0x30;
|
|
92
|
+
|
|
93
|
+
/** Full-width digits as ASCII ones, one for one, so offsets stay (1日 reads as 1日). */
|
|
94
|
+
export const asciiDigits = (text: string): string =>
|
|
95
|
+
text.replace(/[0-9]/gu, (digit) => String.fromCharCode(digit.charCodeAt(0) - FULL_WIDTH_ZERO + ASCII_ZERO));
|
|
96
|
+
|
|
97
|
+
/** Counts of uses in a period, in the order written. */
|
|
98
|
+
export const periodCounts = (written: string, words: PeriodCountWords): PeriodCount[] => {
|
|
99
|
+
const text = asciiDigits(written);
|
|
100
|
+
return [...periodFirst(text, words), ...periodLast(text, words)]
|
|
101
|
+
.filter((count) => Number.isFinite(count.amount) && count.amount > 0 && count.hours > 0)
|
|
102
|
+
.toSorted((left, right) => left.start - right.start);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** The periods written in text, wherever they stand (the maximum daily dose, 1日の最大量). */
|
|
106
|
+
export const periodsIn = (written: string, words: PeriodCountWords): (Span & { readonly hours: number })[] => {
|
|
107
|
+
const text = asciiDigits(written);
|
|
108
|
+
const all = alternation(words.periods.map((word) => word.pattern));
|
|
109
|
+
if (all === "") return [];
|
|
110
|
+
return [...text.matchAll(new RegExp(bounded(all), "giu"))].map((match) => ({
|
|
111
|
+
start: match.index,
|
|
112
|
+
end: match.index + match[0].length,
|
|
113
|
+
hours: hoursOf(words, match[0]),
|
|
114
|
+
}));
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const SENTENCE_END = /[。.!?!?\n]|\.(?=\s|$)/gu;
|
|
118
|
+
|
|
119
|
+
/** How far back the window of a number reaches at most, in characters. */
|
|
120
|
+
const WINDOW_REACH = 120;
|
|
121
|
+
|
|
122
|
+
/** The index of the last of values (ascending) at or before at, or -1. */
|
|
123
|
+
export const lastIndexAtOrBefore = (values: readonly number[], at: number): number => {
|
|
124
|
+
let [low, high, found] = [0, values.length - 1, -1];
|
|
125
|
+
while (low <= high) {
|
|
126
|
+
const middle = (low + high) >> 1;
|
|
127
|
+
if ((values[middle] ?? Infinity) <= at) [found, low] = [middle, middle + 1];
|
|
128
|
+
else high = middle - 1;
|
|
129
|
+
}
|
|
130
|
+
return found;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/** Where the stretch a number is read in begins: after the sentence end, or the last of takenEnds (ascending), before at. */
|
|
134
|
+
export const windowStart = (text: string, at: number, takenEnds: readonly number[]): number => {
|
|
135
|
+
const reach = Math.max(0, at - WINDOW_REACH);
|
|
136
|
+
const ends = [...text.slice(reach, at).matchAll(SENTENCE_END)].map((match) => reach + match.index + match[0].length);
|
|
137
|
+
return Math.max(reach, takenEnds[lastIndexAtOrBefore(takenEnds, at)] ?? 0, ...ends);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export type LimitWords = {
|
|
141
|
+
/** Limit words; a word in group limit-negated ("more than") is one only with a negation before it ("do not take more than"). */
|
|
142
|
+
readonly limits: readonly Mark[];
|
|
143
|
+
readonly negations: readonly string[];
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const NEGATED = "limit-negated";
|
|
147
|
+
const LIMIT_GAP_AFTER = /^[\s、,]*/u;
|
|
148
|
+
const LIMIT_REACH_AFTER = 24;
|
|
149
|
+
|
|
150
|
+
const containsWord = (text: string, word: string): boolean => new RegExp(bounded(escapeRegExp(word.toLowerCase())), "u").test(text);
|
|
151
|
+
|
|
152
|
+
/** A limit word in the window before span (no more than, 最大量は), or right after it (まで, を超えて). */
|
|
153
|
+
export const isLimited = (text: string, span: Span, from: number, words: LimitWords): boolean => {
|
|
154
|
+
const before = text.slice(from, span.start).toLowerCase();
|
|
155
|
+
const after = text.slice(span.end, span.end + LIMIT_REACH_AFTER).toLowerCase();
|
|
156
|
+
const gap = LIMIT_GAP_AFTER.exec(after)?.[0].length ?? 0;
|
|
157
|
+
const negated = words.negations.some((word) => containsWord(before, word));
|
|
158
|
+
return words.limits.some((limit) =>
|
|
159
|
+
(limit.position ?? "before") === "before"
|
|
160
|
+
? containsWord(before, limit.pattern) && (limit.group !== NEGATED || negated)
|
|
161
|
+
: after.startsWith(limit.pattern.toLowerCase(), gap),
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const TABLE_ROW = /^\s*\|/u;
|
|
166
|
+
|
|
167
|
+
const isProse = (line: { readonly text: string } | undefined): boolean => line !== undefined && line.text.trim() !== "" && !TABLE_ROW.test(line.text);
|
|
168
|
+
|
|
169
|
+
/** Runs of non-blank lines that are not table rows: the paragraphs a statement of use is read in. */
|
|
170
|
+
export const paragraphsOf = (text: string): Span[] =>
|
|
171
|
+
linesOf(text).reduce<Span[]>((runs, line, index, lines) => {
|
|
172
|
+
if (!isProse(line)) return runs;
|
|
173
|
+
const end = line.start + line.text.length;
|
|
174
|
+
const last = runs.at(-1);
|
|
175
|
+
if (isProse(lines[index - 1]) && last !== undefined) runs[runs.length - 1] = { start: last.start, end };
|
|
176
|
+
else runs.push({ start: line.start, end });
|
|
177
|
+
return runs;
|
|
178
|
+
}, []);
|
|
@@ -44,8 +44,8 @@ const numberOf = (written: string, numberWords: readonly string[]): number => {
|
|
|
44
44
|
/** A digit number not inside a longer one, or a number word standing as a word of its own. */
|
|
45
45
|
const numberPattern = (numberWords: readonly string[]): string => {
|
|
46
46
|
const words = alternation(numberWords);
|
|
47
|
-
const digits = "(?<![\\p{N}.,./⁄])(
|
|
48
|
-
return words === "" ? digits : `(?:${digits}|(?<![\\p{L}\\p{N}\\p{Pd}])(
|
|
47
|
+
const digits = "(?<![\\p{N}.,./⁄])(?<digits>\\p{Nd}+(?:[..]\\p{Nd}+)?)";
|
|
48
|
+
return words === "" ? digits : `(?:${digits}|(?<![\\p{L}\\p{N}\\p{Pd}])(?<word>${words}))`;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
const SEPARATOR = "[\\s\\-‐]?";
|
|
@@ -71,17 +71,18 @@ const smallestUnit = (number: string | undefined, minutes: string | undefined, h
|
|
|
71
71
|
const hourLengths = (text: string, words: LengthWords): Read[] => {
|
|
72
72
|
const [hours, minutes, halves] = [alternation(words.hourUnits), alternation(words.minuteUnits), alternation(words.halves)];
|
|
73
73
|
if (hours === "") return [];
|
|
74
|
-
const minutePart = minutes === "" ? "" : `|\\s?(
|
|
75
|
-
const halfPart = halves === "" ? "" : `|\\s?(
|
|
74
|
+
const minutePart = minutes === "" ? "" : `|\\s?(?<extra>\\p{Nd}{1,2})\\s?(?:${minutes})`;
|
|
75
|
+
const halfPart = halves === "" ? "" : `|\\s?(?<half>${halves})`;
|
|
76
76
|
const tail = minutePart === "" && halfPart === "" ? "" : `(?:${minutePart.slice(1)}${halfPart})?`;
|
|
77
77
|
const pattern = new RegExp(`${numberPattern(words.numberWords)}${SEPARATOR}(?:${hours})${tail}`, "giu");
|
|
78
78
|
return [...text.matchAll(pattern)].flatMap((match): Read[] => {
|
|
79
79
|
const end = match.index + match[0].length;
|
|
80
80
|
if (runsOn(text, end)) return [];
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
81
|
+
const { digits, word, extra, half } = match.groups ?? {};
|
|
82
|
+
const amount = numberOf(digits ?? word ?? "", words.numberWords);
|
|
83
|
+
const extraMinutes = extra === undefined ? 0 : Number(extra.normalize("NFKC"));
|
|
84
|
+
const halfMinutes = half === undefined ? 0 : HALF_HOUR;
|
|
85
|
+
return [{ span: { start: match.index, end }, minutes: amount * MINUTES_PER_HOUR + extraMinutes + halfMinutes, unit: smallestUnit(digits, extra, half) }];
|
|
85
86
|
});
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -91,7 +92,9 @@ const minuteLengths = (text: string, words: LengthWords): Read[] => {
|
|
|
91
92
|
const pattern = new RegExp(`${numberPattern(words.numberWords)}${SEPARATOR}(?:${minutes})`, "giu");
|
|
92
93
|
return [...text.matchAll(pattern)].flatMap((match): Read[] => {
|
|
93
94
|
const end = match.index + match[0].length;
|
|
94
|
-
return runsOn(text, end)
|
|
95
|
+
return runsOn(text, end)
|
|
96
|
+
? []
|
|
97
|
+
: [{ span: { start: match.index, end }, minutes: numberOf(match.groups?.["digits"] ?? match.groups?.["word"] ?? "", words.numberWords), unit: 1 }];
|
|
95
98
|
});
|
|
96
99
|
};
|
|
97
100
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Span } from "../plugin.ts";
|
|
2
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
3
|
+
import type { Mark } from "../structure/time-marks.ts";
|
|
4
|
+
import { linesOf, type Line } from "../structure/lines.ts";
|
|
5
|
+
import { cellsOf, tablesOf } from "../facts/table-facts.ts";
|
|
6
|
+
import type { TimeLength } from "./time-lengths.ts";
|
|
7
|
+
import {
|
|
8
|
+
asciiDigits,
|
|
9
|
+
isLimited,
|
|
10
|
+
lastIndexAtOrBefore,
|
|
11
|
+
periodCounts,
|
|
12
|
+
windowStart,
|
|
13
|
+
type LimitWords,
|
|
14
|
+
type PeriodCount,
|
|
15
|
+
type PeriodCountWords,
|
|
16
|
+
type PeriodWord,
|
|
17
|
+
} from "./period-counts.ts";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A minimum interval between uses and a maximum count of uses in a period that cannot both hold, and a maximum count that
|
|
21
|
+
* differs from the times a day of the dosing table in the same section. Read in one paragraph holding exactly one
|
|
22
|
+
* minimum interval (4時間以上あけ, at least 4 hours between doses) and exactly one count with a limit (1日6回を超えて,
|
|
23
|
+
* no more than 6 doses a day). n uses at least h hours apart take (n - 1) × h hours from the first to the last; when
|
|
24
|
+
* that reaches the length of the period, the n-th use falls outside it. Pure.
|
|
25
|
+
*/
|
|
26
|
+
export type IntervalWords = PeriodCountWords &
|
|
27
|
+
LimitWords & {
|
|
28
|
+
/** What makes a length a minimum: before it (at least 4 hours) or right after it (4時間以上). */
|
|
29
|
+
readonly minimum: readonly Mark[];
|
|
30
|
+
/** What makes a minimum length an interval between uses, in the same sentence (間隔, between). */
|
|
31
|
+
readonly cues: readonly string[];
|
|
32
|
+
/** Table headings of a count of uses in a period (1日の服用回数, Times a day), with the period's hours. */
|
|
33
|
+
readonly columns: readonly PeriodWord[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type IntervalMismatch =
|
|
37
|
+
| { readonly kind: "interval"; readonly count: PeriodCount; readonly interval: TimeLength; readonly neededHours: number }
|
|
38
|
+
| { readonly kind: "table"; readonly count: PeriodCount; readonly column: string; readonly tableCount: number };
|
|
39
|
+
|
|
40
|
+
const MINUTES_PER_HOUR = 60;
|
|
41
|
+
|
|
42
|
+
const lower = (text: string): string => text.toLowerCase();
|
|
43
|
+
|
|
44
|
+
const SENTENCE_END = /[。.!?!?\n]|\.(?=\s|$)/u;
|
|
45
|
+
|
|
46
|
+
/** How far after a length its sentence is read, in characters. */
|
|
47
|
+
const SENTENCE_REACH = 120;
|
|
48
|
+
|
|
49
|
+
const sentenceAround = (text: string, span: Span): Span => {
|
|
50
|
+
const end = SENTENCE_END.exec(text.slice(span.end, span.end + SENTENCE_REACH));
|
|
51
|
+
return { start: windowStart(text, span.start, []), end: end === null ? Math.min(text.length, span.end + SENTENCE_REACH) : span.end + end.index };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const hasWord = (text: string, word: string): boolean => new RegExp(`(?<![a-z])${escapeRegExp(lower(word))}(?![a-z])`, "u").test(lower(text));
|
|
55
|
+
|
|
56
|
+
/** 4時間以上, at least 4 hours: a length with a minimum mark beside it and an interval word in its sentence. */
|
|
57
|
+
const isMinimumInterval = (text: string, length: TimeLength, words: IntervalWords): boolean => {
|
|
58
|
+
const sentence = sentenceAround(text, length);
|
|
59
|
+
const before = lower(text.slice(sentence.start, length.start)).trimEnd();
|
|
60
|
+
const after = lower(text.slice(length.end, sentence.end)).trimStart();
|
|
61
|
+
const marked = words.minimum.some((mark) =>
|
|
62
|
+
(mark.position ?? "after") === "after" ? after.startsWith(lower(mark.pattern)) : before.endsWith(lower(mark.pattern)),
|
|
63
|
+
);
|
|
64
|
+
return marked && words.cues.some((cue) => hasWord(text.slice(sentence.start, sentence.end), cue));
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const inside = (scope: Span) => (span: Span) => span.start >= scope.start && span.end <= scope.end;
|
|
68
|
+
|
|
69
|
+
type Statement = { readonly count: PeriodCount; readonly interval: TimeLength };
|
|
70
|
+
|
|
71
|
+
const statementIn = (scope: Span, counts: readonly PeriodCount[], intervals: readonly TimeLength[]): Statement | undefined => {
|
|
72
|
+
const [inCounts, inIntervals] = [counts.filter(inside(scope)), intervals.filter(inside(scope))];
|
|
73
|
+
const [count, interval] = [inCounts[0], inIntervals[0]];
|
|
74
|
+
return inCounts.length === 1 && inIntervals.length === 1 && count !== undefined && interval !== undefined ? { count, interval } : undefined;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const HEADING = /^ {0,3}#{1,6}\s/u;
|
|
78
|
+
|
|
79
|
+
const plain = (cell: string): string => lower(asciiDigits(cell).normalize("NFKC").replace(/[*_`]/gu, "").trim());
|
|
80
|
+
|
|
81
|
+
const COUNT_CELL = /^(\d+)(?:\s*[〜~\-–]\s*(\d+))?$/u;
|
|
82
|
+
|
|
83
|
+
/** A cell that holds only a count: 3, 3回, 2〜3回, three, twice. The larger end of a range. */
|
|
84
|
+
const cellCount = (cell: string, words: PeriodCountWords): number | undefined => {
|
|
85
|
+
const text = plain(cell);
|
|
86
|
+
const counter = words.counters.find((word) => text.endsWith(lower(word)));
|
|
87
|
+
const bare = counter === undefined ? text : text.slice(0, -counter.length).trim();
|
|
88
|
+
const digits = COUNT_CELL.exec(bare);
|
|
89
|
+
if (digits !== null) return Number(digits[2] ?? digits[1]);
|
|
90
|
+
return words.numberWords.find((word) => lower(word.pattern) === bare)?.value;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type TableCount = { readonly at: number; readonly column: string; readonly count: number; readonly hours: number };
|
|
94
|
+
|
|
95
|
+
/** The largest count of each counted column, in every table. */
|
|
96
|
+
const tableCountsOf = (lines: readonly Line[], words: IntervalWords): TableCount[] =>
|
|
97
|
+
tablesOf(lines).flatMap(({ header, rows }) =>
|
|
98
|
+
cellsOf(header).flatMap((cell, index): TableCount[] => {
|
|
99
|
+
const column = words.columns.find((word) => plain(word.pattern) === plain(cell.text));
|
|
100
|
+
const values = rows.flatMap((row) => {
|
|
101
|
+
const value = cellCount(cellsOf(row)[index]?.text ?? "", words);
|
|
102
|
+
return value === undefined ? [] : [value];
|
|
103
|
+
});
|
|
104
|
+
if (column === undefined || values.length === 0) return [];
|
|
105
|
+
return [{ at: header.start, column: cell.text.trim(), count: Math.max(...values), hours: column.hours }];
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
type Layout = { readonly headings: readonly number[]; readonly tables: readonly TableCount[]; readonly length: number };
|
|
110
|
+
|
|
111
|
+
const layoutOf = (text: string, words: IntervalWords): Layout => {
|
|
112
|
+
const lines = linesOf(text);
|
|
113
|
+
return { headings: lines.filter((line) => HEADING.test(line.text)).map((line) => line.start), tables: tableCountsOf(lines, words), length: text.length };
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/** The heading-delimited section that holds at. */
|
|
117
|
+
const sectionOf = (layout: Layout, at: number): Span => {
|
|
118
|
+
const index = lastIndexAtOrBefore(layout.headings, at);
|
|
119
|
+
return { start: layout.headings[index] ?? 0, end: layout.headings[index + 1] ?? layout.length };
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const tableMismatch = (layout: Layout, count: PeriodCount): IntervalMismatch | undefined => {
|
|
123
|
+
const section = sectionOf(layout, count.start);
|
|
124
|
+
const tables = layout.tables.filter((table) => table.at >= section.start && table.at < section.end && table.hours === count.hours);
|
|
125
|
+
const table = tables[0];
|
|
126
|
+
if (tables.length !== 1 || table === undefined || table.count === count.amount) return undefined;
|
|
127
|
+
return { kind: "table", count, column: table.column, tableCount: table.count };
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const mismatchOf = (layout: Layout, statement: Statement): IntervalMismatch | undefined => {
|
|
131
|
+
const { count, interval } = statement;
|
|
132
|
+
const neededMinutes = (count.amount - 1) * interval.minutes;
|
|
133
|
+
if (neededMinutes >= count.hours * MINUTES_PER_HOUR) return { kind: "interval", count, interval, neededHours: neededMinutes / MINUTES_PER_HOUR };
|
|
134
|
+
return tableMismatch(layout, count);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/** Limited counts that a minimum interval in the same paragraph, or the table of the section, contradicts. */
|
|
138
|
+
export const intervalCountMismatches = (written: string, scopes: readonly Span[], lengths: readonly TimeLength[], words: IntervalWords): IntervalMismatch[] => {
|
|
139
|
+
const text = asciiDigits(written);
|
|
140
|
+
const all = periodCounts(text, words);
|
|
141
|
+
const takenEnds = all.map((count) => count.end);
|
|
142
|
+
const counts = all.filter((count) => isLimited(text, count, windowStart(text, count.start, takenEnds), words));
|
|
143
|
+
const intervals = lengths.filter((length) => isMinimumInterval(text, length, words));
|
|
144
|
+
if (counts.length === 0 || intervals.length === 0) return [];
|
|
145
|
+
const layout = layoutOf(text, words);
|
|
146
|
+
return scopes.flatMap((scope) => {
|
|
147
|
+
const statement = statementIn(scope, counts, intervals);
|
|
148
|
+
const found = statement === undefined ? undefined : mismatchOf(layout, statement);
|
|
149
|
+
return found === undefined ? [] : [found];
|
|
150
|
+
});
|
|
151
|
+
};
|
|
@@ -10,6 +10,7 @@ const countWordsOf = (doc: ProseDocument): CountWords => ({
|
|
|
10
10
|
anchors: patternsOf(doc, "count-anchor"),
|
|
11
11
|
numbers: patternsOf(doc, "count-number"),
|
|
12
12
|
counters: patternsOf(doc, "count-counter"),
|
|
13
|
+
frames: patternsOf(doc, "count-frame"),
|
|
13
14
|
hedgesBefore: patternsOf(doc, "count-hedge", "before"),
|
|
14
15
|
hedgesAfter: patternsOf(doc, "count-hedge", "after"),
|
|
15
16
|
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// capacity-runtime-mismatch: a stated runtime longer than the battery capacity divided by the consumption (derived/battery-runtime.ts).
|
|
2
|
+
// Values are read from table rows (item name, value) and from "item name: value" lines. One key-value table and the labelled
|
|
3
|
+
// lines of one section are one device; a wider table is one device per column.
|
|
4
|
+
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
5
|
+
import { cellsOf, tablesOf, type Cell } from "../facts/table-facts.ts";
|
|
6
|
+
import { linesOf, type Line } from "../structure/lines.ts";
|
|
7
|
+
import {
|
|
8
|
+
capacityRuntimeMismatches,
|
|
9
|
+
isPeakHeading,
|
|
10
|
+
labelOf,
|
|
11
|
+
splitCondition,
|
|
12
|
+
valueOf,
|
|
13
|
+
type BatteryWords,
|
|
14
|
+
type ElectricUnit,
|
|
15
|
+
type Entry,
|
|
16
|
+
type Family,
|
|
17
|
+
type Marker,
|
|
18
|
+
} from "../derived/battery-runtime.ts";
|
|
19
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
20
|
+
|
|
21
|
+
const FAMILIES: readonly Family[] = ["charge", "current", "energy", "power"];
|
|
22
|
+
const isFamily = (group: string | undefined): group is Family => FAMILIES.some((family) => family === group);
|
|
23
|
+
|
|
24
|
+
type Lexicons = ProseDocument["lexicons"];
|
|
25
|
+
|
|
26
|
+
const markersOf = (lexicons: Lexicons, id: string, group?: string): Marker[] =>
|
|
27
|
+
(lexicons[id] ?? [])
|
|
28
|
+
.filter((entry) => group === undefined || entry.group === group)
|
|
29
|
+
.map((entry) => ({ pattern: entry.pattern, position: entry.position ?? "before" }));
|
|
30
|
+
|
|
31
|
+
export const batteryWordsOf = (lexicons: Lexicons): BatteryWords => {
|
|
32
|
+
const labels = (lexicons["battery-label"] ?? []).map((entry) => ({ pattern: entry.pattern, group: entry.group ?? "" }));
|
|
33
|
+
const bounds = markersOf(lexicons, "battery-label", "bound");
|
|
34
|
+
return {
|
|
35
|
+
electric: (lexicons["battery-unit"] ?? []).flatMap((entry): ElectricUnit[] =>
|
|
36
|
+
isFamily(entry.group) ? [{ pattern: entry.pattern, weight: entry.weight ?? 1, family: entry.group }] : [],
|
|
37
|
+
),
|
|
38
|
+
time: (lexicons["unit-time"] ?? []).map((entry) => ({ pattern: entry.pattern, weight: entry.weight ?? 1 })),
|
|
39
|
+
approximate: markersOf(lexicons, "approximate-marker").filter((marker) => !bounds.some((bound) => bound.pattern === marker.pattern)),
|
|
40
|
+
bounds,
|
|
41
|
+
connectors: (lexicons["range-connector"] ?? []).map((entry) => entry.pattern),
|
|
42
|
+
labels,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const EMPHASIS = /[*`]/gu;
|
|
47
|
+
const plain = (text: string): string => text.replace(EMPHASIS, "");
|
|
48
|
+
|
|
49
|
+
type Slot = { readonly key: string; readonly entry: Entry };
|
|
50
|
+
|
|
51
|
+
const entryOf = (label: string, value: Cell, words: BatteryWords, columnPeak: boolean): Entry | undefined => {
|
|
52
|
+
const named = labelOf(plain(label), words);
|
|
53
|
+
const text = plain(value.text).trim();
|
|
54
|
+
const read = named === undefined ? undefined : valueOf(text, named.role, words);
|
|
55
|
+
if (named === undefined || read === undefined) return undefined;
|
|
56
|
+
const lead = value.text.length - value.text.trimStart().length;
|
|
57
|
+
return {
|
|
58
|
+
...named,
|
|
59
|
+
peak: named.peak || read.peak || columnPeak,
|
|
60
|
+
condition: named.condition === "" ? splitCondition(text).condition : named.condition,
|
|
61
|
+
reading: read.reading,
|
|
62
|
+
start: value.start + lead,
|
|
63
|
+
text,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const sectionAt = (doc: ProseDocument, offset: number): number => doc.sections.findLastIndex((section) => section.span.start <= offset);
|
|
68
|
+
|
|
69
|
+
const TWO_COLUMNS = 2;
|
|
70
|
+
|
|
71
|
+
const tableSlots = (doc: ProseDocument, words: BatteryWords): Slot[] =>
|
|
72
|
+
tablesOf(linesOf(doc.source)).flatMap((table) => {
|
|
73
|
+
const headings = cellsOf(table.header);
|
|
74
|
+
const wide = headings.length > TWO_COLUMNS;
|
|
75
|
+
return table.rows.flatMap((row) => {
|
|
76
|
+
const [label, ...values] = cellsOf(row);
|
|
77
|
+
if (label === undefined) return [];
|
|
78
|
+
return values.flatMap((value, index): Slot[] => {
|
|
79
|
+
const column = index + 1;
|
|
80
|
+
const peak = wide && isPeakHeading(plain(headings[column]?.text ?? ""), words);
|
|
81
|
+
const entry = entryOf(label.text, value, words, peak);
|
|
82
|
+
const key = wide ? `table ${table.header.start} ${column}` : `section ${sectionAt(doc, row.start)}`;
|
|
83
|
+
return entry === undefined || (!wide && column > 1) ? [] : [{ key, entry }];
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const LIST_MARKER = /^\s*(?:[-*+]|\d+[.)])\s+/u;
|
|
89
|
+
const COLON = /[::]/u;
|
|
90
|
+
const MAX_LABEL = 80;
|
|
91
|
+
|
|
92
|
+
/** "Battery life: up to 10 hours", "- 消費電流:500 mA". */
|
|
93
|
+
const lineSlot = (doc: ProseDocument, line: Line, words: BatteryWords): Slot[] => {
|
|
94
|
+
const body = line.text.slice(LIST_MARKER.exec(line.text)?.[0].length ?? 0);
|
|
95
|
+
const colon = COLON.exec(body)?.index;
|
|
96
|
+
if (colon === undefined) return [];
|
|
97
|
+
const label = body.slice(0, colon).trim();
|
|
98
|
+
const value = body.slice(colon + 1).trim();
|
|
99
|
+
if (label === "" || label.length > MAX_LABEL || value === "") return [];
|
|
100
|
+
const start = line.start + line.text.lastIndexOf(value);
|
|
101
|
+
const entry = entryOf(label, { start, end: start + value.length, text: value }, words, false);
|
|
102
|
+
return entry === undefined ? [] : [{ key: `section ${sectionAt(doc, line.start)}`, entry }];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const HOUR_DECIMALS = 100;
|
|
106
|
+
|
|
107
|
+
export const capacityRuntime: Detector = (doc): Finding[] => {
|
|
108
|
+
const words = batteryWordsOf(doc.lexicons);
|
|
109
|
+
const lines = linesOf(doc.prose ?? doc.source).filter((line) => !line.text.includes("|"));
|
|
110
|
+
const slots = [...tableSlots(doc, words), ...lines.flatMap((line) => lineSlot(doc, line, words))];
|
|
111
|
+
const keys = [...new Set(slots.map((slot) => slot.key))];
|
|
112
|
+
return keys
|
|
113
|
+
.flatMap((key) => capacityRuntimeMismatches(slots.filter((slot) => slot.key === key).map((slot) => slot.entry)))
|
|
114
|
+
.map((mismatch) => ({
|
|
115
|
+
rule: "capacity-runtime-mismatch",
|
|
116
|
+
severity: "warning",
|
|
117
|
+
line: 0,
|
|
118
|
+
column: 0,
|
|
119
|
+
quote: quoteAt(doc.source, mismatch.runtime.start),
|
|
120
|
+
values: {
|
|
121
|
+
capacity: mismatch.capacity.text,
|
|
122
|
+
consumption: mismatch.consumption.text,
|
|
123
|
+
runtime: mismatch.runtime.text,
|
|
124
|
+
expected: Math.round(mismatch.idealHours * HOUR_DECIMALS) / HOUR_DECIMALS,
|
|
125
|
+
offset: mismatch.runtime.start,
|
|
126
|
+
},
|
|
127
|
+
}));
|
|
128
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// contact-variant: one email address or postal address written two ways in one document (contacts/emails.ts,
|
|
2
|
+
// contacts/addresses.ts). The address labels come from the language's address-label lexicon.
|
|
3
|
+
import { addressVariants } from "../contacts/addresses.ts";
|
|
4
|
+
import { emailVariants } from "../contacts/emails.ts";
|
|
5
|
+
import type { Variant, Writing } from "../contacts/variants.ts";
|
|
6
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
7
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
8
|
+
|
|
9
|
+
const findingOf = (source: string, { writing, other }: Variant<Writing>, variant?: string): Finding => ({
|
|
10
|
+
rule: "",
|
|
11
|
+
severity: "info",
|
|
12
|
+
line: 0,
|
|
13
|
+
column: 0,
|
|
14
|
+
quote: quoteAt(source, writing.offset),
|
|
15
|
+
values: { written: writing.written, other: other.written, offset: writing.offset },
|
|
16
|
+
...(variant === undefined ? {} : { variant }),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const contactVariant: Detector = (doc, options): Finding[] => {
|
|
20
|
+
const text = doc.prose ?? doc.source;
|
|
21
|
+
const emails = emailVariants(text).map((found) => findingOf(doc.source, found));
|
|
22
|
+
const addresses = addressVariants(text, options.lexicon ?? []).map(({ variant, found }) => findingOf(doc.source, found, variant));
|
|
23
|
+
return [...emails, ...addresses].toSorted((a, b) => Number(a.values?.["offset"]) - Number(b.values?.["offset"]));
|
|
24
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// A stated capacity smaller than a stated number registered, invited or attending (count-over-capacity). The words come
|
|
2
|
+
// from the language package: capacity-label, headcount-label, headcount-unit and capacity-exception.
|
|
3
|
+
import { countsOverCapacity, type CapacityWords, type CountMark } from "../structure/capacity-count.ts";
|
|
4
|
+
import { proseAndTablesOf } from "../table-text.ts";
|
|
5
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
6
|
+
import type { Detector, Finding, ProseDocument } from "../plugin.ts";
|
|
7
|
+
|
|
8
|
+
const marksOf = (doc: ProseDocument, lexicon: string): CountMark[] =>
|
|
9
|
+
(doc.lexicons[lexicon] ?? []).map((entry) => ({ pattern: entry.pattern, position: entry.position, group: entry.group }));
|
|
10
|
+
|
|
11
|
+
const exceptionsOf = (doc: ProseDocument, group: string): string[] =>
|
|
12
|
+
(doc.lexicons["capacity-exception"] ?? []).filter((entry) => entry.group === group).map((entry) => entry.pattern);
|
|
13
|
+
|
|
14
|
+
const capacityWords = (doc: ProseDocument): CapacityWords => ({
|
|
15
|
+
capacities: marksOf(doc, "capacity-label"),
|
|
16
|
+
counts: marksOf(doc, "headcount-label"),
|
|
17
|
+
units: marksOf(doc, "headcount-unit"),
|
|
18
|
+
overflows: exceptionsOf(doc, "overflow"),
|
|
19
|
+
perSession: exceptionsOf(doc, "per-session"),
|
|
20
|
+
otherOccasions: exceptionsOf(doc, "other-occasion"),
|
|
21
|
+
negations: exceptionsOf(doc, "negation"),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** The prose with its tables put back, so code is not read; offsets are the source's. */
|
|
25
|
+
export const countOverCapacity: Detector = (doc): Finding[] =>
|
|
26
|
+
countsOverCapacity(
|
|
27
|
+
proseAndTablesOf(doc),
|
|
28
|
+
capacityWords(doc),
|
|
29
|
+
doc.sections.map((section) => section.span),
|
|
30
|
+
).map((issue) => ({
|
|
31
|
+
rule: "count-over-capacity",
|
|
32
|
+
severity: "warning",
|
|
33
|
+
line: 0,
|
|
34
|
+
column: 0,
|
|
35
|
+
quote: quoteAt(doc.source, issue.offset),
|
|
36
|
+
values: { ...issue.values, offset: issue.offset },
|
|
37
|
+
}));
|
|
@@ -6,13 +6,14 @@ import { quoteAt } from "./structure-tree.ts";
|
|
|
6
6
|
|
|
7
7
|
const patternsOf = (doc: ProseDocument, lexicon: string): string[] => (doc.lexicons[lexicon] ?? []).map((entry) => entry.pattern);
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/** 期間の語、期間の外に置く語、文書の仕事の期間の語、締め切りの語、期間の後に来てよい仕事の語、概要の節の見出しの語、範囲の記号(range-connector、range-opener、range-frame の間の語)、月と曜日の名は語彙表から取る。 */
|
|
10
10
|
const wordsOf = (doc: ProseDocument): OutsideWords => ({
|
|
11
11
|
labels: patternsOf(doc, "period-label"),
|
|
12
12
|
terms: patternsOf(doc, "period-term-label"),
|
|
13
13
|
asides: patternsOf(doc, "period-aside"),
|
|
14
14
|
deadlines: patternsOf(doc, "period-deadline"),
|
|
15
15
|
overviews: patternsOf(doc, "period-overview-heading"),
|
|
16
|
+
afterTerm: patternsOf(doc, "period-after-term"),
|
|
16
17
|
connectors: [
|
|
17
18
|
...patternsOf(doc, "range-connector"),
|
|
18
19
|
...patternsOf(doc, "range-opener"),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// date-stamp-order: an established date later than the last update, on the document's stamp lines (structure/stamp-order.ts).
|
|
2
|
+
// The stamp words come from the language's stamp-order-label lexicon, grouped into established and updated.
|
|
3
|
+
import type { Detector, Finding } from "../plugin.ts";
|
|
4
|
+
import { inDocumentOrder } from "../structure/issues.ts";
|
|
5
|
+
import { stampOrderIssues } from "../structure/stamp-order.ts";
|
|
6
|
+
import { proseAndTablesOf } from "../table-text.ts";
|
|
7
|
+
import { quoteAt } from "./structure-tree.ts";
|
|
8
|
+
|
|
9
|
+
export const dateStampOrder: Detector = (doc, options): Finding[] => {
|
|
10
|
+
if (doc.structure === undefined) return [];
|
|
11
|
+
const labels = options.lexicon ?? [];
|
|
12
|
+
const wordsOf = (group: string): string[] => labels.filter((entry) => entry.group === group).map((entry) => entry.pattern);
|
|
13
|
+
const dates = inDocumentOrder(doc.structure).flatMap((node) =>
|
|
14
|
+
node.kind === "date" ? [{ offset: node.span.start, end: node.span.end, value: String(node.attrs["value"]) }] : [],
|
|
15
|
+
);
|
|
16
|
+
return stampOrderIssues(proseAndTablesOf(doc), dates, { established: wordsOf("established"), updated: wordsOf("updated") }).map(({ offset, values }) => {
|
|
17
|
+
const { side, ...dated } = values;
|
|
18
|
+
return {
|
|
19
|
+
rule: "",
|
|
20
|
+
severity: "info",
|
|
21
|
+
line: 0,
|
|
22
|
+
column: 0,
|
|
23
|
+
quote: quoteAt(doc.source, offset),
|
|
24
|
+
values: { ...dated, offset },
|
|
25
|
+
...(side === undefined ? {} : { variant: String(side) }),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
};
|