chaffjs 0.29.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/session-hours.d.ts +26 -0
- package/dist/derived/session-hours.d.ts.map +1 -0
- package/dist/derived/session-hours.js +29 -0
- package/dist/derived/session-hours.js.map +1 -0
- package/dist/derived/time-lengths.d.ts +37 -0
- package/dist/derived/time-lengths.d.ts.map +1 -0
- package/dist/derived/time-lengths.js +171 -0
- package/dist/derived/time-lengths.js.map +1 -0
- package/dist/derived/unit-counts.d.ts +7 -0
- package/dist/derived/unit-counts.d.ts.map +1 -0
- package/dist/derived/unit-counts.js +13 -0
- package/dist/derived/unit-counts.js.map +1 -0
- 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/derived/working-hours.d.ts +36 -0
- package/dist/derived/working-hours.d.ts.map +1 -0
- package/dist/derived/working-hours.js +55 -0
- package/dist/derived/working-hours.js.map +1 -0
- package/dist/detectors/acronym-expansion.d.ts +1 -1
- package/dist/detectors/acronym-expansion.d.ts.map +1 -1
- package/dist/detectors/acronym-expansion.js +46 -2
- package/dist/detectors/acronym-expansion.js.map +1 -1
- 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/capitalised-term.d.ts +44 -0
- package/dist/detectors/capitalised-term.d.ts.map +1 -0
- package/dist/detectors/capitalised-term.js +101 -0
- package/dist/detectors/capitalised-term.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 +5 -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 +11 -1
- package/dist/detectors/derived-numbers.d.ts.map +1 -1
- package/dist/detectors/derived-numbers.js +74 -20
- 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 +78 -10
- 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/party-order.d.ts +3 -0
- package/dist/detectors/party-order.d.ts.map +1 -0
- package/dist/detectors/party-order.js +46 -0
- package/dist/detectors/party-order.js.map +1 -0
- 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/connection-time-short.d.ts +3 -0
- package/dist/detectors/registry/connection-time-short.d.ts.map +1 -0
- package/dist/detectors/registry/connection-time-short.js +3 -0
- package/dist/detectors/registry/connection-time-short.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/duration-product-mismatch.d.ts +3 -0
- package/dist/detectors/registry/duration-product-mismatch.d.ts.map +1 -0
- package/dist/detectors/registry/duration-product-mismatch.js +3 -0
- package/dist/detectors/registry/duration-product-mismatch.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/party-order.d.ts +3 -0
- package/dist/detectors/registry/party-order.d.ts.map +1 -0
- package/dist/detectors/registry/party-order.js +3 -0
- package/dist/detectors/registry/party-order.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/requirement-lists.d.ts +3 -0
- package/dist/detectors/registry/requirement-lists.d.ts.map +1 -0
- package/dist/detectors/registry/requirement-lists.js +3 -0
- package/dist/detectors/registry/requirement-lists.js.map +1 -0
- package/dist/detectors/registry/return-type.d.ts +3 -0
- package/dist/detectors/registry/return-type.d.ts.map +1 -0
- package/dist/detectors/registry/return-type.js +3 -0
- package/dist/detectors/registry/return-type.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/requirement-lists.d.ts +3 -0
- package/dist/detectors/requirement-lists.d.ts.map +1 -0
- package/dist/detectors/requirement-lists.js +46 -0
- package/dist/detectors/requirement-lists.js.map +1 -0
- package/dist/detectors/return-type.d.ts +3 -0
- package/dist/detectors/return-type.d.ts.map +1 -0
- package/dist/detectors/return-type.js +24 -0
- package/dist/detectors/return-type.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 +31 -6
- 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 +2 -0
- package/dist/detectors/time-order.d.ts.map +1 -1
- package/dist/detectors/time-order.js +33 -5
- package/dist/detectors/time-order.js.map +1 -1
- package/dist/detectors/undefined-term.d.ts.map +1 -1
- package/dist/detectors/undefined-term.js +19 -3
- package/dist/detectors/undefined-term.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/document.d.ts.map +1 -1
- package/dist/document.js +4 -1
- package/dist/document.js.map +1 -1
- 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/table-facts.d.ts +2 -0
- package/dist/facts/table-facts.d.ts.map +1 -1
- package/dist/facts/table-facts.js +2 -0
- package/dist/facts/table-facts.js.map +1 -1
- 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 +8 -2
- package/dist/name-variants.d.ts.map +1 -1
- package/dist/name-variants.js +72 -7
- package/dist/name-variants.js.map +1 -1
- package/dist/name-word-order.d.ts +49 -0
- package/dist/name-word-order.d.ts.map +1 -0
- package/dist/name-word-order.js +114 -0
- package/dist/name-word-order.js.map +1 -0
- 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 +12 -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/return-type.d.ts +33 -0
- package/dist/return-type.d.ts.map +1 -0
- package/dist/return-type.js +302 -0
- package/dist/return-type.js.map +1 -0
- 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/connection-times.d.ts +56 -0
- package/dist/structure/connection-times.d.ts.map +1 -0
- package/dist/structure/connection-times.js +165 -0
- package/dist/structure/connection-times.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-order-tie.d.ts +13 -0
- package/dist/structure/date-order-tie.d.ts.map +1 -0
- package/dist/structure/date-order-tie.js +61 -0
- package/dist/structure/date-order-tie.js.map +1 -0
- package/dist/structure/date-order.d.ts +2 -2
- package/dist/structure/date-order.d.ts.map +1 -1
- package/dist/structure/date-order.js +26 -9
- package/dist/structure/date-order.js.map +1 -1
- package/dist/structure/date-outside-period.d.ts +8 -0
- package/dist/structure/date-outside-period.d.ts.map +1 -1
- package/dist/structure/date-outside-period.js +52 -3
- package/dist/structure/date-outside-period.js.map +1 -1
- package/dist/structure/date-range.d.ts +6 -2
- package/dist/structure/date-range.d.ts.map +1 -1
- package/dist/structure/date-range.js +37 -9
- 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/leg-times.d.ts +2 -0
- package/dist/structure/leg-times.d.ts.map +1 -1
- package/dist/structure/leg-times.js +13 -0
- package/dist/structure/leg-times.js.map +1 -1
- 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/party-order.d.ts +33 -0
- package/dist/structure/party-order.d.ts.map +1 -0
- package/dist/structure/party-order.js +79 -0
- package/dist/structure/party-order.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/requirement-lists.d.ts +37 -0
- package/dist/structure/requirement-lists.d.ts.map +1 -0
- package/dist/structure/requirement-lists.js +89 -0
- package/dist/structure/requirement-lists.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-order.d.ts +21 -0
- package/dist/structure/time-order.d.ts.map +1 -1
- package/dist/structure/time-order.js +5 -6
- package/dist/structure/time-order.js.map +1 -1
- 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/version-order.d.ts +2 -0
- package/dist/structure/version-order.d.ts.map +1 -1
- package/dist/structure/version-order.js +10 -0
- package/dist/structure/version-order.js.map +1 -1
- 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/dist/surname-near.d.ts +6 -0
- package/dist/surname-near.d.ts.map +1 -0
- package/dist/surname-near.js +31 -0
- package/dist/surname-near.js.map +1 -0
- package/dist/table-cells.d.ts +13 -0
- package/dist/table-cells.d.ts.map +1 -0
- package/dist/table-cells.js +36 -0
- package/dist/table-cells.js.map +1 -0
- package/dist/table-names.d.ts +42 -0
- package/dist/table-names.d.ts.map +1 -0
- package/dist/table-names.js +94 -0
- package/dist/table-names.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/connection-time-short.yaml +52 -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/duration-mismatch.yaml +7 -4
- package/rules/duration-product-mismatch.yaml +73 -0
- 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 +14 -2
- package/rules/no-em-dash.yaml +2 -2
- package/rules/party-order.yaml +84 -0
- 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/required-listed-as-preferred.yaml +102 -0
- package/rules/return-type-mismatch.yaml +79 -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/undefined-term.yaml +21 -7
- 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/session-hours.ts +62 -0
- package/src/derived/time-lengths.ts +229 -0
- package/src/derived/unit-counts.ts +18 -0
- package/src/derived/use-interval.ts +151 -0
- package/src/derived/working-hours.ts +97 -0
- package/src/detectors/acronym-expansion.ts +57 -2
- package/src/detectors/announced-count.ts +1 -0
- package/src/detectors/capacity-runtime.ts +128 -0
- package/src/detectors/capitalised-term.ts +147 -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 +5 -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 +97 -24
- 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 +99 -15
- package/src/detectors/orthographic-variant.ts +78 -9
- package/src/detectors/orthography.ts +16 -6
- package/src/detectors/party-order.ts +50 -0
- 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/connection-time-short.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/duration-product-mismatch.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/party-order.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/requirement-lists.ts +4 -0
- package/src/detectors/registry/return-type.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/requirement-lists.ts +65 -0
- package/src/detectors/return-type.ts +30 -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 +42 -6
- package/src/detectors/structure.ts +1 -1
- package/src/detectors/technical-docs.ts +12 -0
- package/src/detectors/time-order.ts +45 -6
- package/src/detectors/undefined-term.ts +20 -3
- 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/document.ts +4 -1
- 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/table-facts.ts +3 -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 +83 -7
- package/src/name-word-order.ts +149 -0
- package/src/phone-numbers.ts +26 -6
- package/src/place-names.ts +53 -14
- package/src/plugin.ts +7 -0
- package/src/preamble-paragraphs.ts +21 -2
- package/src/profile/parse.ts +10 -0
- package/src/return-type.ts +361 -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/connection-times.ts +226 -0
- package/src/structure/counted-amounts.ts +5 -4
- package/src/structure/date-order-tie.ts +86 -0
- package/src/structure/date-order.ts +41 -14
- package/src/structure/date-outside-period.ts +77 -7
- package/src/structure/date-range.ts +45 -9
- 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/leg-times.ts +15 -0
- package/src/structure/measured-amounts.ts +138 -0
- package/src/structure/party-order.ts +115 -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/requirement-lists.ts +145 -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-order.ts +8 -7
- 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/version-order.ts +10 -0
- package/src/structure/walk-time.ts +285 -0
- package/src/surname-near.ts +31 -0
- package/src/table-cells.ts +41 -0
- package/src/table-names.ts +113 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { Amount } from "./total.ts";
|
|
2
|
+
import type { MeasureUnit } from "../facts/measures.ts";
|
|
3
|
+
import { CONTINUES_WORD, NUMBER, overlapsAny, valueOf } from "./counted-amounts.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 足してよい、単位の付いた量(300 mg、0.5 g、2 L、3 cm)。単位は量の種類(dimension)と、基準の単位への倍率(factors)を持つ。
|
|
7
|
+
* 同じ種類の量は、その種類で一番小さい単位に直して足す(500 mg と 0.5 g は 1,000 mg)。倍率が二つある単位(cup)は換算が決まらない。
|
|
8
|
+
*/
|
|
9
|
+
export type SummedMeasure = Pick<MeasureUnit, "pattern" | "dimension" | "factors" | "before" | "context">;
|
|
10
|
+
|
|
11
|
+
/** 足せない量の印。目安の印(約、about、程度)、範囲の印(〜)、何あたりかの印(数の前の $3 / 200 g、単位の後ろの 300 mg/錠、per tablet)。 */
|
|
12
|
+
export type MeasureMarks = {
|
|
13
|
+
readonly roughBefore: readonly string[];
|
|
14
|
+
readonly roughAfter: readonly string[];
|
|
15
|
+
readonly connectors: readonly string[];
|
|
16
|
+
readonly perMarks: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 足せない量の単位に付ける印。量は読むが、単位に位置も入れて、ほかのどの量とも同じ単位にならないようにする。その量がある列の和は取らない。
|
|
21
|
+
* 読まずに捨てると、その行が空の升に見えて、残りの行の和を合計と比べてしまう。
|
|
22
|
+
*/
|
|
23
|
+
const UNSUMMABLE = "?";
|
|
24
|
+
|
|
25
|
+
const LOOKAHEAD = 32;
|
|
26
|
+
const LATIN = /\p{Script=Latin}/u;
|
|
27
|
+
const DIGIT_AT_END = /\p{N}$/u;
|
|
28
|
+
|
|
29
|
+
const lineStartOf = (source: string, offset: number): number => source.lastIndexOf("\n", offset - 1) + 1;
|
|
30
|
+
|
|
31
|
+
/** text が word で終わり、英字の語なら語の途中(awesome の some)でない。 */
|
|
32
|
+
const endsWithWord = (text: string, word: string): boolean => {
|
|
33
|
+
if (!text.toLowerCase().endsWith(word.toLowerCase())) return false;
|
|
34
|
+
return !LATIN.test(word.charAt(0)) || !LATIN.test(text.charAt(text.length - word.length - 1));
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** text が word で始まり、英字の語なら語の途中(personal の per)でない。 */
|
|
38
|
+
const startsWithWord = (text: string, word: string): boolean => {
|
|
39
|
+
if (!text.toLowerCase().startsWith(word.toLowerCase())) return false;
|
|
40
|
+
return !LATIN.test(word.at(-1) ?? "") || !LATIN.test(text.charAt(word.length));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 数の前の目安の印(約300mg、about 300 mg)、何あたりかの印($3 / 200 g、$3 per 200 g)、
|
|
45
|
+
* 範囲の後ろの端(300〜400mg、300 - 400 mg)。
|
|
46
|
+
*/
|
|
47
|
+
const markedBefore = (source: string, start: number, marks: MeasureMarks): boolean => {
|
|
48
|
+
const before = source.slice(lineStartOf(source, start), start);
|
|
49
|
+
const trimmed = before.trimEnd();
|
|
50
|
+
if ([...marks.roughBefore, ...marks.perMarks].some((word) => endsWithWord(trimmed, word))) return true;
|
|
51
|
+
return marks.connectors.some(
|
|
52
|
+
(connector) => before.endsWith(connector) || (trimmed.endsWith(connector) && DIGIT_AT_END.test(trimmed.slice(0, -connector.length).trimEnd())),
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** 印の前に置かれうる、開き括弧と空白(5 mg (per tablet))。 */
|
|
57
|
+
const OPENING = /^[\s(([[]+/u;
|
|
58
|
+
|
|
59
|
+
/** 単位の後ろの、目安の印(300mg程度)か何あたりかの印(300 mg/tablet、300 mg per tablet、5 mg (per tablet))。 */
|
|
60
|
+
const markedAfter = (source: string, end: number, marks: MeasureMarks): boolean => {
|
|
61
|
+
const after = source.slice(end, end + LOOKAHEAD).replace(OPENING, "");
|
|
62
|
+
return [...marks.roughAfter, ...marks.perMarks].some((word) => startsWithWord(after, word));
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type Found = { readonly measure: SummedMeasure; readonly end: number };
|
|
66
|
+
|
|
67
|
+
const lineAt = (source: string, offset: number): string => {
|
|
68
|
+
const end = source.indexOf("\n", offset);
|
|
69
|
+
return source.slice(lineStartOf(source, offset), end === -1 ? source.length : end);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** 文脈の語が要る単位(unit-context)は、同じ行にその語があるときだけ単位。 */
|
|
73
|
+
const inContext = (measure: SummedMeasure, source: string, offset: number): boolean => {
|
|
74
|
+
if (measure.context.length === 0) return true;
|
|
75
|
+
const line = lineAt(source, offset).toLowerCase();
|
|
76
|
+
return measure.context.some((word) => line.includes(word.toLowerCase()));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** 数のすぐ後ろ(空白一つまで)の単位。長い単位から試す(mg を m で切らない)。大文字と小文字は区別する(mL と ML は別)。 */
|
|
80
|
+
const measureAfter = (source: string, end: number, measures: readonly SummedMeasure[], marks: MeasureMarks): Found | undefined => {
|
|
81
|
+
const gap = source.charAt(end) === " " ? 1 : 0;
|
|
82
|
+
const rest = source.slice(end + gap, end + gap + LOOKAHEAD);
|
|
83
|
+
const measure = measures.find((candidate) => {
|
|
84
|
+
if (candidate.before || !rest.startsWith(candidate.pattern) || !inContext(candidate, source, end)) return false;
|
|
85
|
+
const unitEnd = end + gap + candidate.pattern.length;
|
|
86
|
+
return markedAfter(source, unitEnd, marks) || !CONTINUES_WORD.test(rest.slice(candidate.pattern.length));
|
|
87
|
+
});
|
|
88
|
+
return measure === undefined ? undefined : { measure, end: end + gap + measure.pattern.length };
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/** 量の種類ごとの、一番小さい倍率。倍率が一つの単位だけから取る。 */
|
|
92
|
+
const baseFactors = (measures: readonly SummedMeasure[]): Map<string, number> =>
|
|
93
|
+
measures.reduce((bases, measure) => {
|
|
94
|
+
const [factor] = measure.factors;
|
|
95
|
+
if (measure.factors.length !== 1 || factor === undefined || factor <= 0) return bases;
|
|
96
|
+
return bases.set(measure.dimension, Math.min(bases.get(measure.dimension) ?? factor, factor));
|
|
97
|
+
}, new Map<string, number>());
|
|
98
|
+
|
|
99
|
+
const unsummable = (offset: number, end: number, value: number, measure: SummedMeasure): Amount => ({
|
|
100
|
+
offset,
|
|
101
|
+
end,
|
|
102
|
+
value,
|
|
103
|
+
unit: `${measure.dimension}${UNSUMMABLE}${String(offset)}`,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const amountOf = (source: string, start: number, written: string, found: Found, bases: Map<string, number>, marks: MeasureMarks): Amount => {
|
|
107
|
+
const value = valueOf(written);
|
|
108
|
+
const { measure } = found;
|
|
109
|
+
const [factor] = measure.factors;
|
|
110
|
+
const base = bases.get(measure.dimension);
|
|
111
|
+
const sure = measure.factors.length === 1 && factor !== undefined && base !== undefined;
|
|
112
|
+
if (!sure || markedBefore(source, start, marks) || markedAfter(source, found.end, marks)) return unsummable(start, found.end, value, measure);
|
|
113
|
+
const scale = factor / base;
|
|
114
|
+
return { offset: start, end: found.end, value: value * scale, unit: measure.dimension, scale };
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 数のすぐ前(空白一つまで)の単位(大さじ1)は、足さない量として読む。読まずに捨てると、その行が空の升に見えてしまう。
|
|
119
|
+
*/
|
|
120
|
+
const measureBefore = (source: string, start: number, end: number, measures: readonly SummedMeasure[]): Amount | undefined => {
|
|
121
|
+
const gap = source.charAt(start - 1) === " " ? 1 : 0;
|
|
122
|
+
const head = source.slice(Math.max(0, start - gap - LOOKAHEAD), start - gap);
|
|
123
|
+
const measure = measures.find((candidate) => candidate.before && head.endsWith(candidate.pattern) && inContext(candidate, source, start));
|
|
124
|
+
return measure === undefined ? undefined : unsummable(start - gap - measure.pattern.length, end, valueOf(source.slice(start, end)), measure);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/** 文書の中の、単位の付いた量。値は量の種類で一番小さい単位に直す。木がすでに数量として読んだもの(known)とは重ねない。 */
|
|
128
|
+
export const measuredAmounts = (source: string, measures: readonly SummedMeasure[], marks: MeasureMarks, known: readonly Amount[]): Amount[] => {
|
|
129
|
+
const longestFirst = measures.toSorted((left, right) => right.pattern.length - left.pattern.length);
|
|
130
|
+
const bases = baseFactors(measures);
|
|
131
|
+
return [...source.matchAll(NUMBER)].flatMap((match): Amount[] => {
|
|
132
|
+
const end = match.index + match[0].length;
|
|
133
|
+
const found = measureAfter(source, end, longestFirst, marks);
|
|
134
|
+
if (found !== undefined) return overlapsAny(match.index, found.end, known) ? [] : [amountOf(source, match.index, match[0], found, bases, marks)];
|
|
135
|
+
const before = measureBefore(source, match.index, end, longestFirst);
|
|
136
|
+
return before === undefined || overlapsAny(before.offset, before.end, known) ? [] : [before];
|
|
137
|
+
});
|
|
138
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { BodyText } from "./definition-use.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 当事者の呼び名を並べた所(甲及び乙、甲又は乙、甲乙、甲、乙及び丙)と、文書がふだん書く順と逆に並べた所。
|
|
5
|
+
* 並べる語は言語パッケージの語彙表から取る。向きのある言い方(乙から甲へ、甲が乙に)は並べる語でつながないので読まない。
|
|
6
|
+
*/
|
|
7
|
+
export type ListingWords = {
|
|
8
|
+
/** 当事者の呼び名(甲、乙、文書が定めた委託者)。 */
|
|
9
|
+
readonly labels: readonly string[];
|
|
10
|
+
/** 間に語を置かずに並べてよい呼び名(甲乙)。 */
|
|
11
|
+
readonly bareLabels: readonly string[];
|
|
12
|
+
/** 並べる語(及び、又は、・)。 */
|
|
13
|
+
readonly joiners: readonly string[];
|
|
14
|
+
/** 同じ並びのあとに並べる語があるときだけつなぐ印(甲、乙及び丙の「、」)。 */
|
|
15
|
+
readonly seriesMarks: readonly string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type PartyListing = { readonly start: number; readonly end: number; readonly labels: readonly string[] };
|
|
19
|
+
|
|
20
|
+
export type OrderSlip = { readonly listing: PartyListing; readonly usual: PartyListing; readonly usualCount: number; readonly reverseCount: number };
|
|
21
|
+
|
|
22
|
+
type Link = "joiner" | "series" | "bare";
|
|
23
|
+
type Step = { readonly link: Link; readonly label: string; readonly end: number };
|
|
24
|
+
|
|
25
|
+
/** 呼び名の前の一字がこれなら、呼び名は長い語の一部(乙種の前の語、1丁目)。 */
|
|
26
|
+
const WORD_CHAR = /[\p{Script=Han}\p{Script=Katakana}\p{Script=Latin}\p{N}ー]/u;
|
|
27
|
+
|
|
28
|
+
const longestAt = (text: string, at: number, words: readonly string[]): string | undefined =>
|
|
29
|
+
words
|
|
30
|
+
.filter((word) => word !== "" && text.startsWith(word, at))
|
|
31
|
+
.reduce<string | undefined>((best, word) => (best === undefined || word.length > best.length ? word : best), undefined);
|
|
32
|
+
|
|
33
|
+
const stepAfter = (text: string, at: number, previous: string, words: ListingWords): Step | undefined => {
|
|
34
|
+
const linked = (link: Link, mark: string | undefined): Step | undefined => {
|
|
35
|
+
if (mark === undefined) return undefined;
|
|
36
|
+
const label = longestAt(text, at + mark.length, words.labels);
|
|
37
|
+
return label === undefined ? undefined : { link, label, end: at + mark.length + label.length };
|
|
38
|
+
};
|
|
39
|
+
const bare = words.bareLabels.includes(previous) ? longestAt(text, at, words.bareLabels) : undefined;
|
|
40
|
+
const side: Step | undefined = bare === undefined ? undefined : { link: "bare", label: bare, end: at + bare.length };
|
|
41
|
+
return linked("joiner", longestAt(text, at, words.joiners)) ?? linked("series", longestAt(text, at, words.seriesMarks)) ?? side;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** 並べた語の数。「、」は、そのあとに並べる語が無ければ並びの終わり(「甲、乙は」は並べたと読まない)。 */
|
|
45
|
+
const linksKept = (links: readonly Link[]): number => {
|
|
46
|
+
const lastJoiner = links.lastIndexOf("joiner");
|
|
47
|
+
const series = links.findIndex((link, index) => link === "series" && index > lastJoiner);
|
|
48
|
+
return series === -1 ? links.length : series;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** 最後の呼び名が長い語の頭なら並びに入れない(乙及び甲種株式の甲)。間を置かずに並べた甲乙は、あとに語が続いてよい(甲乙間、甲乙双方)。 */
|
|
52
|
+
const endsInWord = (text: string, steps: readonly Step[]): boolean => {
|
|
53
|
+
const last = steps.at(-1);
|
|
54
|
+
return last !== undefined && last.link !== "bare" && WORD_CHAR.test(text.charAt(last.end));
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const listingAt = (text: BodyText, at: number, first: string, words: ListingWords): PartyListing => {
|
|
58
|
+
const steps: Step[] = [];
|
|
59
|
+
let end = at + first.length;
|
|
60
|
+
for (let step = stepAfter(text.text, end, first, words); step !== undefined; step = stepAfter(text.text, end, step.label, words)) {
|
|
61
|
+
steps.push(step);
|
|
62
|
+
end = step.end;
|
|
63
|
+
}
|
|
64
|
+
const whole = endsInWord(text.text, steps) ? steps.slice(0, -1) : steps;
|
|
65
|
+
const kept = whole.slice(0, linksKept(whole.map((step) => step.link)));
|
|
66
|
+
const last = kept.at(-1);
|
|
67
|
+
return { start: text.start + at, end: text.start + (last === undefined ? at + first.length : last.end), labels: [first, ...kept.map((step) => step.label)] };
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** 一つの文の中の並び。呼び名が二つ以上で、違う呼び名を並べたものだけ。 */
|
|
71
|
+
const listingsIn = (text: BodyText, words: ListingWords): PartyListing[] => {
|
|
72
|
+
const found: PartyListing[] = [];
|
|
73
|
+
let at = 0;
|
|
74
|
+
while (at < text.text.length) {
|
|
75
|
+
const first = WORD_CHAR.test(text.text.charAt(at - 1)) ? undefined : longestAt(text.text, at, words.labels);
|
|
76
|
+
const listing = first === undefined ? undefined : listingAt(text, at, first, words);
|
|
77
|
+
if (listing !== undefined && new Set(listing.labels).size > 1) found.push(listing);
|
|
78
|
+
at = listing !== undefined && listing.labels.length > 1 ? listing.end - text.start : at + 1;
|
|
79
|
+
}
|
|
80
|
+
return found;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const partyListings = (texts: readonly BodyText[], words: ListingWords): PartyListing[] => texts.flatMap((text) => listingsIn(text, words));
|
|
84
|
+
|
|
85
|
+
const pairsOf = (labels: readonly string[]): [string, string][] =>
|
|
86
|
+
labels.flatMap((first, index) => labels.slice(index + 1).flatMap((second): [string, string][] => (second === first ? [] : [[first, second]])));
|
|
87
|
+
|
|
88
|
+
const keyOf = (left: string, right: string): string => `${left}\u0000${right}`;
|
|
89
|
+
|
|
90
|
+
const byPair = (listings: readonly PartyListing[]): Map<string, PartyListing[]> => {
|
|
91
|
+
const pairs = new Map<string, PartyListing[]>();
|
|
92
|
+
listings.forEach((listing) =>
|
|
93
|
+
new Set(pairsOf(listing.labels).map(([first, second]) => keyOf(first, second))).forEach((key) => pairs.set(key, [...(pairs.get(key) ?? []), listing])),
|
|
94
|
+
);
|
|
95
|
+
return pairs;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 文書がふだん書く順と逆に並べた所。ふだんの順は、同じ二つの呼び名を並べた所の多い方で、逆の順の minRatio 倍以上あるときだけ
|
|
100
|
+
* 決まる(同じ数なら、どちらとも言えないので指さない)。
|
|
101
|
+
*/
|
|
102
|
+
export const reversedListings = (listings: readonly PartyListing[], minRatio: number): OrderSlip[] => {
|
|
103
|
+
const pairs = byPair(listings);
|
|
104
|
+
return listings.flatMap((listing) => {
|
|
105
|
+
const slips = pairsOf(listing.labels).flatMap(([first, second]): OrderSlip[] => {
|
|
106
|
+
const reverse = pairs.get(keyOf(first, second)) ?? [];
|
|
107
|
+
const usual = pairs.get(keyOf(second, first)) ?? [];
|
|
108
|
+
const example = usual[0];
|
|
109
|
+
return example === undefined || usual.length < minRatio * reverse.length
|
|
110
|
+
? []
|
|
111
|
+
: [{ listing, usual: example, usualCount: usual.length, reverseCount: reverse.length }];
|
|
112
|
+
});
|
|
113
|
+
return slips.slice(0, 1);
|
|
114
|
+
});
|
|
115
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// quantity-range-reversed: which measured quantities may be one end of a range, read as the ends structure/amount-range.ts
|
|
2
|
+
// compares. Pure.
|
|
3
|
+
import type { Measured } from "../facts/measures.ts";
|
|
4
|
+
import { escapeRegExp } from "../orthography.ts";
|
|
5
|
+
import type { StructureIssue } from "./issues.ts";
|
|
6
|
+
import type { RangeAmount } from "./amount-range.ts";
|
|
7
|
+
|
|
8
|
+
const LATIN_EDGE = /[A-Za-z]$/u;
|
|
9
|
+
const LATIN_START = /^[A-Za-z]/u;
|
|
10
|
+
|
|
11
|
+
/** A Latin unit running into a word is part of that word: the t of "40 to" is not a tonne. */
|
|
12
|
+
const standsAlone = (text: string, measured: Measured): boolean =>
|
|
13
|
+
!(LATIN_EDGE.test(measured.unit) && LATIN_START.test(text.slice(measured.end, measured.end + 1)));
|
|
14
|
+
|
|
15
|
+
/** 10 and a minus sign right before the number is a power of ten written flat ("10-8 cm" for 10⁻⁸ cm), not a range. */
|
|
16
|
+
const POWER_OF_TEN = /(?<![0-90-9.,,.])[11][00][-−-]$/u;
|
|
17
|
+
|
|
18
|
+
/** "10-" and the character before it, which must not be a digit (110-8 cm is a range). */
|
|
19
|
+
const POWER_OF_TEN_LOOKBACK = 4;
|
|
20
|
+
|
|
21
|
+
const isExponent = (text: string, measured: Measured): boolean =>
|
|
22
|
+
POWER_OF_TEN.test(text.slice(Math.max(0, measured.start - POWER_OF_TEN_LOOKBACK), measured.start));
|
|
23
|
+
|
|
24
|
+
/** A quantity as one end of a range: two ends compare only in one unit, however it is spelled (℃ with °C, m with meters). */
|
|
25
|
+
const rangeEndOf = (text: string, measured: Measured): RangeAmount => ({
|
|
26
|
+
offset: measured.start,
|
|
27
|
+
end: measured.end,
|
|
28
|
+
currency: `${measured.dimension}:${measured.factors.join(",")}`,
|
|
29
|
+
value: measured.amount,
|
|
30
|
+
scale: undefined,
|
|
31
|
+
position: text.startsWith(measured.unit, measured.start) ? "before" : "after",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/** The measured quantities that can end a range, as range ends. */
|
|
35
|
+
export const quantityRangeEnds = (text: string, measured: readonly Measured[]): RangeAmount[] =>
|
|
36
|
+
measured.filter((value) => standsAlone(text, value) && !isExponent(text, value)).map((value) => rangeEndOf(text, value));
|
|
37
|
+
|
|
38
|
+
const LATIN_WORD = /^[A-Za-z]/u;
|
|
39
|
+
|
|
40
|
+
/** Whether a lead word stands right before the range on its line ("went from 9 minutes to 2 minutes" tells of a change). */
|
|
41
|
+
const ledBy = (text: string, offset: number, leads: readonly string[]): boolean => {
|
|
42
|
+
const before = text
|
|
43
|
+
.slice(text.lastIndexOf("\n", offset - 1) + 1, offset)
|
|
44
|
+
.trimEnd()
|
|
45
|
+
.toLowerCase();
|
|
46
|
+
return leads.some((lead) => {
|
|
47
|
+
const edge = LATIN_WORD.test(lead) ? "(?<![a-z])" : "";
|
|
48
|
+
return new RegExp(`${edge}${escapeRegExp(lead.toLowerCase())}$`, "u").test(before);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** The reversed ranges that no lead word frames as a change. */
|
|
53
|
+
export const unledRanges = (text: string, issues: readonly StructureIssue[], leads: readonly string[]): StructureIssue[] =>
|
|
54
|
+
issues.filter((issue) => !ledBy(text, issue.offset, leads));
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// range-band-mismatch: the bands of one table column or one list (7〜11歳, 12〜14歳, 15歳以上; under 7, 7 to 11, 12 and over)
|
|
2
|
+
// that overlap or leave a gap between neighbours. The words that bound a band and the units it is counted in come from the
|
|
3
|
+
// lexicons (range-band-word, range-band-unit, range-band-heading). Pure.
|
|
4
|
+
|
|
5
|
+
/** How an end of a band is written: 以上/以下 (inclusive), 未満/超 (exclusive), or only a range mark (7〜11, 7 to 11). */
|
|
6
|
+
export type BoundKind = "inclusive" | "exclusive" | "loose";
|
|
7
|
+
|
|
8
|
+
export type Bound = { readonly value: number; readonly kind: BoundKind; readonly decimals: number };
|
|
9
|
+
|
|
10
|
+
/** Integer units (ages, people, points) have no value between 11 and 12; continuous ones (kg, yen, hours) do. */
|
|
11
|
+
export type UnitKind = "integer" | "continuous";
|
|
12
|
+
|
|
13
|
+
export type Band = { readonly low: Bound | undefined; readonly high: Bound | undefined; readonly unit: string };
|
|
14
|
+
|
|
15
|
+
export type BandMarker = {
|
|
16
|
+
readonly pattern: string;
|
|
17
|
+
readonly side: "low" | "high";
|
|
18
|
+
readonly kind: "inclusive" | "exclusive";
|
|
19
|
+
readonly position: "before" | "after";
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type BandUnit = { readonly pattern: string; readonly kind: UnitKind; readonly position: "before" | "after" };
|
|
23
|
+
|
|
24
|
+
export type BandWords = {
|
|
25
|
+
/** Marks between the two ends (〜, –, to). Written after a number alone (12歳〜) it leaves the band open above. */
|
|
26
|
+
readonly connectors: readonly string[];
|
|
27
|
+
/** The marks that, before a number alone (〜6歳), close a band above. A hyphen is not one: "- 5" is a bullet or a minus. */
|
|
28
|
+
readonly openers: readonly string[];
|
|
29
|
+
readonly markers: readonly BandMarker[];
|
|
30
|
+
/** Words a band may open with that say nothing about its ends ("ages", "aged"). */
|
|
31
|
+
readonly leads: readonly string[];
|
|
32
|
+
readonly units: readonly BandUnit[];
|
|
33
|
+
/** Column headings that name what bare numbers count (年齢, Age), with the kind of that quantity. */
|
|
34
|
+
readonly headings: readonly { readonly pattern: string; readonly kind: UnitKind }[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** One band as written, with where it is. */
|
|
38
|
+
export type PlacedBand = { readonly band: Band; readonly start: number; readonly end: number; readonly text: string };
|
|
39
|
+
|
|
40
|
+
export type BandSlip = { readonly kind: "overlap" | "gap"; readonly earlier: PlacedBand; readonly later: PlacedBand };
|
|
41
|
+
|
|
42
|
+
const NUMBER = /^(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?/u;
|
|
43
|
+
const LATIN_END = /[a-z]$/u;
|
|
44
|
+
const LETTER = /^[a-z]/u;
|
|
45
|
+
const SPACE = /^\s*/u;
|
|
46
|
+
const EMPHASIS = /[*_`]/gu;
|
|
47
|
+
|
|
48
|
+
/** The text without a note in brackets at its end (15歳以上(成人)), and the note. */
|
|
49
|
+
const splitNote = (text: string): { readonly bare: string; readonly note: string | undefined } => {
|
|
50
|
+
const open = text.lastIndexOf("(");
|
|
51
|
+
if (!text.endsWith(")") || open === -1) return { bare: text, note: undefined };
|
|
52
|
+
return { bare: text.slice(0, open).trim(), note: text.slice(open + 1, -1).trim() };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const plainOf = (text: string): string => text.normalize("NFKC").toLowerCase().replace(EMPHASIS, "").trim();
|
|
56
|
+
|
|
57
|
+
export const normalizeBandText = (text: string): string => splitNote(plainOf(text)).bare;
|
|
58
|
+
|
|
59
|
+
const normalizeWord = (word: string): string => word.normalize("NFKC").toLowerCase();
|
|
60
|
+
|
|
61
|
+
/** A unit compared across bands: years and year, kg and kgs are the same unit. */
|
|
62
|
+
const unitKey = (unit: string): string => (unit.length > 2 && unit.endsWith("s") ? unit.slice(0, -1) : unit);
|
|
63
|
+
|
|
64
|
+
type Cursor = { readonly text: string; readonly at: number };
|
|
65
|
+
|
|
66
|
+
const skipSpace = (cursor: Cursor): Cursor => ({ text: cursor.text, at: cursor.at + (SPACE.exec(cursor.text.slice(cursor.at))?.[0].length ?? 0) });
|
|
67
|
+
|
|
68
|
+
/** The longest word at the cursor; a Latin word must end at a word edge (to is not the start of total). */
|
|
69
|
+
const wordAt = (cursor: Cursor, words: readonly string[]): string | undefined =>
|
|
70
|
+
words
|
|
71
|
+
.map(normalizeWord)
|
|
72
|
+
.filter((word) => word !== "" && cursor.text.startsWith(word, cursor.at))
|
|
73
|
+
.filter((word) => !LATIN_END.test(word) || !LETTER.test(cursor.text.slice(cursor.at + word.length)))
|
|
74
|
+
.reduce<string | undefined>((best, word) => (best === undefined || word.length > best.length ? word : best), undefined);
|
|
75
|
+
|
|
76
|
+
const advance = (cursor: Cursor, word: string | undefined): Cursor =>
|
|
77
|
+
word === undefined ? cursor : skipSpace({ text: cursor.text, at: cursor.at + word.length });
|
|
78
|
+
|
|
79
|
+
type Read<T> = { readonly value: T; readonly cursor: Cursor } | undefined;
|
|
80
|
+
|
|
81
|
+
const numberAt = (cursor: Cursor): Read<{ value: number; decimals: number }> => {
|
|
82
|
+
const written = NUMBER.exec(cursor.text.slice(cursor.at))?.[0];
|
|
83
|
+
if (written === undefined) return undefined;
|
|
84
|
+
const digits = written.replaceAll(",", "");
|
|
85
|
+
return { value: { value: Number(digits), decimals: digits.split(".")[1]?.length ?? 0 }, cursor: advance(cursor, written) };
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const unitsAt = (cursor: Cursor, words: BandWords, position: "before" | "after"): Read<string | undefined> => {
|
|
89
|
+
const unit = wordAt(
|
|
90
|
+
cursor,
|
|
91
|
+
words.units.filter((entry) => entry.position === position).map((entry) => entry.pattern),
|
|
92
|
+
);
|
|
93
|
+
return { value: unit, cursor: advance(cursor, unit) };
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const markerAt = (cursor: Cursor, words: BandWords, position: "before" | "after"): Read<BandMarker | undefined> => {
|
|
97
|
+
const markers = words.markers.filter((marker) => marker.position === position);
|
|
98
|
+
const word = wordAt(
|
|
99
|
+
cursor,
|
|
100
|
+
markers.map((marker) => marker.pattern),
|
|
101
|
+
);
|
|
102
|
+
return { value: markers.find((marker) => normalizeWord(marker.pattern) === word), cursor: advance(cursor, word) };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** One number with the units written around it ($5, 7歳, 8 years). */
|
|
106
|
+
type Figure = { readonly value: number; readonly decimals: number; readonly units: readonly string[] };
|
|
107
|
+
|
|
108
|
+
const figureAt = (cursor: Cursor, words: BandWords): Read<Figure> => {
|
|
109
|
+
const prefix = unitsAt(cursor, words, "before");
|
|
110
|
+
const number = prefix === undefined ? undefined : numberAt(prefix.cursor);
|
|
111
|
+
const suffix = number === undefined ? undefined : unitsAt(number.cursor, words, "after");
|
|
112
|
+
if (prefix === undefined || number === undefined || suffix === undefined) return undefined;
|
|
113
|
+
const units = [prefix.value, suffix.value].filter((unit) => unit !== undefined);
|
|
114
|
+
return { value: { ...number.value, units }, cursor: suffix.cursor };
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const boundOf = (figure: Figure, kind: BoundKind): Bound => ({ value: figure.value, kind, decimals: figure.decimals });
|
|
118
|
+
|
|
119
|
+
/** A band with the units it was written in. undefined when the text is not one band of one unit. */
|
|
120
|
+
type Parsed = { readonly low: Bound | undefined; readonly high: Bound | undefined; readonly units: readonly string[] };
|
|
121
|
+
|
|
122
|
+
const withMarker = (figure: Figure, marker: BandMarker): Parsed => ({
|
|
123
|
+
low: marker.side === "low" ? boundOf(figure, marker.kind) : undefined,
|
|
124
|
+
high: marker.side === "high" ? boundOf(figure, marker.kind) : undefined,
|
|
125
|
+
units: figure.units,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/** One end with its word: 15歳以上, 7 and over, under 7. */
|
|
129
|
+
const markedEnd = (cursor: Cursor, words: BandWords): Read<{ readonly parsed: Parsed; readonly side: "low" | "high" }> => {
|
|
130
|
+
const before = markerAt(cursor, words, "before");
|
|
131
|
+
const figure = before === undefined ? undefined : figureAt(before.cursor, words);
|
|
132
|
+
const after = figure === undefined ? undefined : markerAt(figure.cursor, words, "after");
|
|
133
|
+
if (before === undefined || figure === undefined || after === undefined) return undefined;
|
|
134
|
+
const marker = before.value ?? after.value;
|
|
135
|
+
if (marker === undefined || (before.value !== undefined && after.value !== undefined)) return undefined;
|
|
136
|
+
const unit = unitsAt(after.cursor, words, "after");
|
|
137
|
+
if (unit === undefined) return undefined;
|
|
138
|
+
const parsed = withMarker(figure.value, marker);
|
|
139
|
+
return {
|
|
140
|
+
value: { parsed: { ...parsed, units: [...parsed.units, ...(unit.value === undefined ? [] : [unit.value])] }, side: marker.side },
|
|
141
|
+
cursor: unit.cursor,
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/** 15歳以上, under 7, and both ends with their words: 7歳以上12歳未満. */
|
|
146
|
+
const markedBand = (cursor: Cursor, words: BandWords): Read<Parsed> => {
|
|
147
|
+
const first = markedEnd(cursor, words);
|
|
148
|
+
if (first === undefined) return undefined;
|
|
149
|
+
const rest = first.value.side === "low" ? markedEnd(first.cursor, words) : undefined;
|
|
150
|
+
if (rest === undefined || rest.value.side !== "high") return { value: first.value.parsed, cursor: first.cursor };
|
|
151
|
+
const units = [...first.value.parsed.units, ...rest.value.parsed.units];
|
|
152
|
+
return { value: { low: first.value.parsed.low, high: rest.value.parsed.high, units }, cursor: rest.cursor };
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/** 7〜11歳, 7 to 11, 12歳〜, 〜6歳. */
|
|
156
|
+
const spannedBand = (cursor: Cursor, words: BandWords): Read<Parsed> => {
|
|
157
|
+
const leading = wordAt(cursor, words.openers);
|
|
158
|
+
const first = figureAt(advance(cursor, leading), words);
|
|
159
|
+
if (first === undefined) return undefined;
|
|
160
|
+
if (leading !== undefined) return { value: { low: undefined, high: boundOf(first.value, "loose"), units: first.value.units }, cursor: first.cursor };
|
|
161
|
+
const connector = wordAt(first.cursor, words.connectors);
|
|
162
|
+
if (connector === undefined) return undefined;
|
|
163
|
+
const second = figureAt(advance(first.cursor, connector), words);
|
|
164
|
+
if (second === undefined)
|
|
165
|
+
return { value: { low: boundOf(first.value, "loose"), high: undefined, units: first.value.units }, cursor: advance(first.cursor, connector) };
|
|
166
|
+
return {
|
|
167
|
+
value: { low: boundOf(first.value, "loose"), high: boundOf(second.value, "loose"), units: [...first.value.units, ...second.value.units] },
|
|
168
|
+
cursor: second.cursor,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/** The band a cell or the head of a list item states, or undefined when the whole text is not one band in one unit. */
|
|
173
|
+
export const parseBand = (written: string, words: BandWords): Band | undefined => {
|
|
174
|
+
const text = normalizeBandText(written);
|
|
175
|
+
const start = skipSpace({ text, at: 0 });
|
|
176
|
+
const begun = advance(start, wordAt(start, words.leads));
|
|
177
|
+
const read = [begun, start]
|
|
178
|
+
.flatMap((cursor) => [markedBand(cursor, words), spannedBand(cursor, words)])
|
|
179
|
+
.find((reading) => reading !== undefined && reading.cursor.at === text.length);
|
|
180
|
+
if (read === undefined) return undefined;
|
|
181
|
+
const units = new Set(read.value.units.map(unitKey));
|
|
182
|
+
if (units.size > 1) return undefined;
|
|
183
|
+
const { low, high } = read.value;
|
|
184
|
+
if (low !== undefined && high !== undefined && low.value >= high.value) return undefined;
|
|
185
|
+
return { low, high, unit: [...units][0] ?? "" };
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/** The kind of a unit, by the unit lexicon. */
|
|
189
|
+
export const unitKindOf = (unit: string, words: BandWords): UnitKind | undefined =>
|
|
190
|
+
words.units.find((entry) => unitKey(normalizeWord(entry.pattern)) === unit)?.kind;
|
|
191
|
+
|
|
192
|
+
/** What bare numbers under a column heading count: by a word of the heading lexicon, or a unit in brackets (体重(kg)). */
|
|
193
|
+
export const headingOf = (heading: string, words: BandWords): { readonly unit: string; readonly kind: UnitKind } | undefined => {
|
|
194
|
+
const { bare, note } = splitNote(plainOf(heading).replaceAll("[", "(").replaceAll("]", ")"));
|
|
195
|
+
const unit = note === undefined ? undefined : unitKey(note);
|
|
196
|
+
const unitKind = unit === undefined ? undefined : unitKindOf(unit, words);
|
|
197
|
+
if (unit !== undefined && unitKind !== undefined) return { unit, kind: unitKind };
|
|
198
|
+
const named = words.headings.find((entry) => normalizeWord(entry.pattern) === bare);
|
|
199
|
+
return named === undefined ? undefined : { unit: "", kind: named.kind };
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
type Span = { readonly low: number; readonly high: number };
|
|
203
|
+
|
|
204
|
+
const POSITIVE = Number.POSITIVE_INFINITY;
|
|
205
|
+
const NEGATIVE = Number.NEGATIVE_INFINITY;
|
|
206
|
+
|
|
207
|
+
/** The band as the values it holds. An integer band's exclusive end is the next whole number in (7歳未満 holds up to 6). */
|
|
208
|
+
const spanOf = (band: Band, integer: boolean): Span => {
|
|
209
|
+
const step = integer ? 1 : 0;
|
|
210
|
+
const inward = (bound: Bound): number => (bound.kind === "exclusive" ? step : 0);
|
|
211
|
+
return {
|
|
212
|
+
low: band.low === undefined ? NEGATIVE : band.low.value + inward(band.low),
|
|
213
|
+
high: band.high === undefined ? POSITIVE : band.high.value - inward(band.high),
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/** Bands written in one direction, each starting and ending past the one before. Nested tiers (〜100万円, 〜200万円) are not. */
|
|
218
|
+
const orderOf = (spans: readonly Span[]): "up" | "down" | undefined => {
|
|
219
|
+
const pairs = spans.slice(1).flatMap((span, index): [Span, Span][] => {
|
|
220
|
+
const previous = spans[index];
|
|
221
|
+
return previous === undefined ? [] : [[previous, span]];
|
|
222
|
+
});
|
|
223
|
+
if (pairs.every(([a, b]) => a.low < b.low && a.high < b.high)) return "up";
|
|
224
|
+
if (pairs.every(([a, b]) => a.low > b.low && a.high > b.high)) return "down";
|
|
225
|
+
return undefined;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/** Smallest step the two numbers are written to (59 and 60: 1; 59.9 and 60: 0.1). */
|
|
229
|
+
const stepOf = (a: Bound, b: Bound): number => 10 ** -Math.max(a.decimals, b.decimals);
|
|
230
|
+
|
|
231
|
+
const ROUNDING = 1e-9;
|
|
232
|
+
|
|
233
|
+
type Meeting = "overlap" | "gap" | undefined;
|
|
234
|
+
|
|
235
|
+
/** Whole numbers: the next band starts one past the end of the one below. */
|
|
236
|
+
const integerJunction = (below: Band, above: Band): Meeting => {
|
|
237
|
+
const distance = spanOf(above, true).low - spanOf(below, true).high;
|
|
238
|
+
if (distance <= 0) return "overlap";
|
|
239
|
+
return distance > 1 ? "gap" : undefined;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/** At one number, an end included on both sides overlaps and one excluded on both sides leaves the number out. */
|
|
243
|
+
const sameNumber = (end: Bound, start: Bound): Meeting => {
|
|
244
|
+
if (start.kind === "inclusive" && end.kind === "inclusive") return "overlap";
|
|
245
|
+
return start.kind === "exclusive" && end.kind === "exclusive" ? "gap" : undefined;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** Values in between: a shared end with a range mark, or ends a written step apart, are contiguous. */
|
|
249
|
+
const continuousJunction = (end: Bound, start: Bound): Meeting => {
|
|
250
|
+
if (start.value < end.value) return "overlap";
|
|
251
|
+
if (start.value === end.value) return sameNumber(end, start);
|
|
252
|
+
if (start.kind === "exclusive" || end.kind === "exclusive") return "gap";
|
|
253
|
+
return start.value - end.value > stepOf(start, end) + ROUNDING ? "gap" : undefined;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/** Where the band below ends and the band above starts. */
|
|
257
|
+
const junctionOf = (below: Band, above: Band, integer: boolean): Meeting => {
|
|
258
|
+
if (below.high === undefined || above.low === undefined) return undefined;
|
|
259
|
+
return integer ? integerJunction(below, above) : continuousJunction(below.high, above.low);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const widthOf = (span: Span, integer: boolean): number => span.high - span.low + (integer ? 1 : 0);
|
|
263
|
+
|
|
264
|
+
type Junction = { readonly kind: "overlap" | "gap"; readonly size: number; readonly narrower: number };
|
|
265
|
+
|
|
266
|
+
/** How much the bands overlap or leave out, next to the narrower of the two. */
|
|
267
|
+
const junctionSize = (kind: "overlap" | "gap", below: Span, above: Span, integer: boolean): Junction => {
|
|
268
|
+
const edge = integer ? 1 : 0;
|
|
269
|
+
const size = kind === "overlap" ? below.high - above.low + edge : above.low - below.high - edge;
|
|
270
|
+
return { kind, size, narrower: Math.min(widthOf(below, integer), widthOf(above, integer)) };
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/** An overlap of more than half the narrower band is deliberate: a size guide whose bands share a range. */
|
|
274
|
+
const isDeliberate = (junction: Junction): boolean => junction.kind === "overlap" && junction.size * 2 > junction.narrower;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The overlaps and gaps between neighbouring bands of one column or list. The bands must all be counted in one unit (bare
|
|
278
|
+
* numbers take the column's), written in one direction; the slip is reported at the later of the two in the document. A run
|
|
279
|
+
* with one deliberate overlap is a scale meant to overlap, and two bands alone are reported only when the hole or overlap is
|
|
280
|
+
* no wider than the narrower band.
|
|
281
|
+
*/
|
|
282
|
+
export const bandSlips = (bands: readonly PlacedBand[], kind: UnitKind): BandSlip[] => {
|
|
283
|
+
if (bands.length < 2) return [];
|
|
284
|
+
const integer = kind === "integer" && bands.every(({ band }) => [band.low, band.high].every((bound) => bound === undefined || bound.decimals === 0));
|
|
285
|
+
const order = orderOf(bands.map(({ band }) => spanOf(band, integer)));
|
|
286
|
+
if (order === undefined) return [];
|
|
287
|
+
const ascending = order === "up" ? [...bands] : [...bands].reverse();
|
|
288
|
+
const junctions = ascending.slice(1).flatMap((above, index) => {
|
|
289
|
+
const below = ascending[index];
|
|
290
|
+
const slip = below === undefined ? undefined : junctionOf(below.band, above.band, integer);
|
|
291
|
+
return below === undefined || slip === undefined
|
|
292
|
+
? []
|
|
293
|
+
: [{ below, above, ...junctionSize(slip, spanOf(below.band, integer), spanOf(above.band, integer), integer) }];
|
|
294
|
+
});
|
|
295
|
+
if (junctions.some(isDeliberate)) return [];
|
|
296
|
+
const pair = bands.length === 2;
|
|
297
|
+
return junctions
|
|
298
|
+
.filter((junction) => !pair || junction.size <= junction.narrower)
|
|
299
|
+
.map(({ below, above, kind: slip }) => {
|
|
300
|
+
const [earlier, later] = below.start < above.start ? [below, above] : [above, below];
|
|
301
|
+
return { kind: slip, earlier, later };
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
/** The unit and kind of a run of bands: one unit for all (bare numbers take the heading's), or undefined. */
|
|
306
|
+
export const runKindOf = (
|
|
307
|
+
bands: readonly Band[],
|
|
308
|
+
heading: { readonly unit: string; readonly kind: UnitKind } | undefined,
|
|
309
|
+
words: BandWords,
|
|
310
|
+
): UnitKind | undefined => {
|
|
311
|
+
const units = new Set([...bands.map((band) => band.unit), heading?.unit ?? ""].filter((unit) => unit !== ""));
|
|
312
|
+
if (units.size > 1) return undefined;
|
|
313
|
+
const unit = [...units][0];
|
|
314
|
+
if (unit === undefined) return heading?.kind;
|
|
315
|
+
return unitKindOf(unit, words);
|
|
316
|
+
};
|