hyper-html-api 0.14.0 → 0.15.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/conformance/MANIFEST.json +2 -2
- package/conformance/cases/codec-form-nested.error.json +5 -0
- package/conformance/cases/codec-form-nested.html +4 -0
- package/conformance/cases/codec-form-nested.meta +6 -0
- package/conformance/cases/codec-form-nested.parsed.json +5 -0
- package/conformance/cases/codec-form-star.error.json +5 -0
- package/conformance/cases/codec-form-star.html +4 -0
- package/conformance/cases/codec-form-star.meta +6 -0
- package/conformance/cases/codec-form-star.parsed.json +3 -0
- package/conformance/cases/codec-form-under-v1.error.json +5 -0
- package/conformance/cases/codec-form-under-v1.html +4 -0
- package/conformance/cases/codec-form-under-v1.meta +6 -0
- package/conformance/cases/codec-form-under-v1.parsed.json +3 -0
- package/conformance/cases/codec-unknown-name.error.json +5 -0
- package/conformance/cases/codec-unknown-name.html +4 -0
- package/conformance/cases/codec-unknown-name.meta +6 -0
- package/conformance/cases/codec-unknown-name.parsed.json +3 -0
- package/conformance/cases/tag-version-2-plain.expected.json +7 -0
- package/conformance/cases/tag-version-2-plain.html +5 -0
- package/conformance/cases/tag-version-2-plain.meta +6 -0
- package/conformance/cases/tag-version-2-plain.parsed.json +4 -0
- package/conformance/cases/tag-wrong-version.error.json +1 -1
- package/conformance/cases/tag-wrong-version.html +1 -1
- package/conformance/sheet/body-data-write.body.json +3 -0
- package/conformance/sheet/body-data-write.data.json +3 -0
- package/conformance/sheet/body-data-write.html +25 -0
- package/conformance/sheet/body-data-write.meta +5 -0
- package/conformance/sheet/body-patch-key-in-rules.body.json +3 -0
- package/conformance/sheet/body-patch-key-in-rules.data.json +13 -0
- package/conformance/sheet/body-patch-key-in-rules.html +18 -0
- package/conformance/sheet/body-patch-key-in-rules.meta +5 -0
- package/conformance/sheet/body-patch-not-array.body.json +3 -0
- package/conformance/sheet/body-patch-not-array.data.json +3 -0
- package/conformance/sheet/body-patch-not-array.html +25 -0
- package/conformance/sheet/body-patch-not-array.meta +5 -0
- package/conformance/sheet/body-patch-on-sheet.body.json +3 -0
- package/conformance/sheet/body-patch-on-sheet.data.json +14 -0
- package/conformance/sheet/body-patch-on-sheet.html +25 -0
- package/conformance/sheet/body-patch-on-sheet.meta +5 -0
- package/conformance/sheet/body-patch-version-1.body.json +3 -0
- package/conformance/sheet/body-patch-version-1.data.json +13 -0
- package/conformance/sheet/body-patch-version-1.html +4 -0
- package/conformance/sheet/body-patch-version-1.meta +5 -0
- package/conformance/sheet/body-patch-with-other-key.body.json +3 -0
- package/conformance/sheet/body-patch-with-other-key.data.json +14 -0
- package/conformance/sheet/body-patch-with-other-key.html +25 -0
- package/conformance/sheet/body-patch-with-other-key.meta +5 -0
- package/conformance/sheet/body-patch-without-operation-id.body.json +3 -0
- package/conformance/sheet/body-patch-without-operation-id.data.json +13 -0
- package/conformance/sheet/body-patch-without-operation-id.html +25 -0
- package/conformance/sheet/body-patch-without-operation-id.meta +5 -0
- package/conformance/sheet/params-bad-range.error.json +6 -0
- package/conformance/sheet/params-bad-range.html +25 -0
- package/conformance/sheet/params-bad-range.meta +6 -0
- package/conformance/sheet/params-bad-render.error.json +6 -0
- package/conformance/sheet/params-bad-render.html +25 -0
- package/conformance/sheet/params-bad-render.meta +6 -0
- package/conformance/sheet/params-bad-shape.error.json +6 -0
- package/conformance/sheet/params-bad-shape.html +25 -0
- package/conformance/sheet/params-bad-shape.meta +6 -0
- package/conformance/sheet/params-cache-buster.expected.json +128 -0
- package/conformance/sheet/params-cache-buster.html +25 -0
- package/conformance/sheet/params-cache-buster.meta +6 -0
- package/conformance/sheet/params-data-alone.expected.json +128 -0
- package/conformance/sheet/params-data-alone.html +25 -0
- package/conformance/sheet/params-data-alone.meta +6 -0
- package/conformance/sheet/params-empty.error.json +6 -0
- package/conformance/sheet/params-empty.html +25 -0
- package/conformance/sheet/params-empty.meta +6 -0
- package/conformance/sheet/params-index.expected.json +19 -0
- package/conformance/sheet/params-index.html +25 -0
- package/conformance/sheet/params-index.meta +6 -0
- package/conformance/sheet/params-none.expected.json +128 -0
- package/conformance/sheet/params-none.html +25 -0
- package/conformance/sheet/params-none.meta +6 -0
- package/conformance/sheet/params-range.expected.json +17 -0
- package/conformance/sheet/params-range.html +25 -0
- package/conformance/sheet/params-range.meta +6 -0
- package/conformance/sheet/params-render-without-range.error.json +6 -0
- package/conformance/sheet/params-render-without-range.html +25 -0
- package/conformance/sheet/params-render-without-range.meta +6 -0
- package/conformance/sheet/params-repeated.error.json +6 -0
- package/conformance/sheet/params-repeated.html +25 -0
- package/conformance/sheet/params-repeated.meta +6 -0
- package/conformance/sheet/params-unknown-sheet.error.json +6 -0
- package/conformance/sheet/params-unknown-sheet.html +25 -0
- package/conformance/sheet/params-unknown-sheet.meta +6 -0
- package/conformance/sheet/params-with-data.error.json +6 -0
- package/conformance/sheet/params-with-data.html +25 -0
- package/conformance/sheet/params-with-data.meta +6 -0
- package/conformance/sheet/sheet-contract-cells.expected.json +57 -0
- package/conformance/sheet/sheet-contract-cells.html +10 -0
- package/conformance/sheet/sheet-contract-cells.meta +6 -0
- package/conformance/sheet/sheet-contract-formulas.expected.json +29 -0
- package/conformance/sheet/sheet-contract-formulas.html +10 -0
- package/conformance/sheet/sheet-contract-formulas.meta +6 -0
- package/conformance/sheet/sheet-contract-values.expected.json +29 -0
- package/conformance/sheet/sheet-contract-values.html +10 -0
- package/conformance/sheet/sheet-contract-values.meta +6 -0
- package/conformance/sheet/sheet-contract-whole.expected.json +59 -0
- package/conformance/sheet/sheet-contract-whole.html +10 -0
- package/conformance/sheet/sheet-contract-whole.meta +5 -0
- package/conformance/sheet/sheet-hostile-01.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-01.html +6 -0
- package/conformance/sheet/sheet-hostile-01.meta +5 -0
- package/conformance/sheet/sheet-hostile-02.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-02.html +6 -0
- package/conformance/sheet/sheet-hostile-02.meta +5 -0
- package/conformance/sheet/sheet-hostile-03.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-03.html +6 -0
- package/conformance/sheet/sheet-hostile-03.meta +5 -0
- package/conformance/sheet/sheet-hostile-04.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-04.html +6 -0
- package/conformance/sheet/sheet-hostile-04.meta +5 -0
- package/conformance/sheet/sheet-hostile-05.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-05.html +6 -0
- package/conformance/sheet/sheet-hostile-05.meta +5 -0
- package/conformance/sheet/sheet-hostile-06.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-06.html +6 -0
- package/conformance/sheet/sheet-hostile-06.meta +5 -0
- package/conformance/sheet/sheet-hostile-07.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-07.html +6 -0
- package/conformance/sheet/sheet-hostile-07.meta +5 -0
- package/conformance/sheet/sheet-hostile-08.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-08.html +6 -0
- package/conformance/sheet/sheet-hostile-08.meta +5 -0
- package/conformance/sheet/sheet-hostile-09.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-09.html +6 -0
- package/conformance/sheet/sheet-hostile-09.meta +5 -0
- package/conformance/sheet/sheet-hostile-10.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-10.html +6 -0
- package/conformance/sheet/sheet-hostile-10.meta +5 -0
- package/conformance/sheet/sheet-hostile-11.expected.json +22 -0
- package/conformance/sheet/sheet-hostile-11.html +6 -0
- package/conformance/sheet/sheet-hostile-11.meta +5 -0
- package/conformance/sheet/sheet-hostile-12.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-12.html +6 -0
- package/conformance/sheet/sheet-hostile-12.meta +5 -0
- package/conformance/sheet/sheet-hostile-13.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-13.html +6 -0
- package/conformance/sheet/sheet-hostile-13.meta +5 -0
- package/conformance/sheet/sheet-hostile-14.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-14.html +6 -0
- package/conformance/sheet/sheet-hostile-14.meta +5 -0
- package/conformance/sheet/sheet-hostile-15.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-15.html +0 -0
- package/conformance/sheet/sheet-hostile-15.meta +5 -0
- package/conformance/sheet/sheet-hostile-16.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-16.html +6 -0
- package/conformance/sheet/sheet-hostile-16.meta +5 -0
- package/conformance/sheet/sheet-hostile-17.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-17.html +6 -0
- package/conformance/sheet/sheet-hostile-17.meta +5 -0
- package/conformance/sheet/sheet-hostile-18.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-18.html +6 -0
- package/conformance/sheet/sheet-hostile-18.meta +5 -0
- package/conformance/sheet/sheet-hostile-19.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-19.html +6 -0
- package/conformance/sheet/sheet-hostile-19.meta +5 -0
- package/conformance/sheet/sheet-hostile-20.expected.json +16 -0
- package/conformance/sheet/sheet-hostile-20.html +6 -0
- package/conformance/sheet/sheet-hostile-20.meta +5 -0
- package/conformance/sheet/sheet-hostile-21.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-21.html +6 -0
- package/conformance/sheet/sheet-hostile-21.meta +5 -0
- package/conformance/sheet/sheet-hostile-22.expected.json +21 -0
- package/conformance/sheet/sheet-hostile-22.html +6 -0
- package/conformance/sheet/sheet-hostile-22.meta +5 -0
- package/conformance/sheet/sheet-hostile-23.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-23.html +6 -0
- package/conformance/sheet/sheet-hostile-23.meta +5 -0
- package/conformance/sheet/sheet-hostile-24.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-24.html +6 -0
- package/conformance/sheet/sheet-hostile-24.meta +5 -0
- package/conformance/sheet/sheet-hostile-25.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-25.html +6 -0
- package/conformance/sheet/sheet-hostile-25.meta +5 -0
- package/conformance/sheet/sheet-hostile-26.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-26.html +6 -0
- package/conformance/sheet/sheet-hostile-26.meta +5 -0
- package/conformance/sheet/sheet-hostile-27.expected.json +24 -0
- package/conformance/sheet/sheet-hostile-27.html +7 -0
- package/conformance/sheet/sheet-hostile-27.meta +5 -0
- package/conformance/sheet/sheet-hostile-28.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-28.html +6 -0
- package/conformance/sheet/sheet-hostile-28.meta +5 -0
- package/conformance/sheet/sheet-hostile-29.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-29.html +6 -0
- package/conformance/sheet/sheet-hostile-29.meta +5 -0
- package/conformance/sheet/sheet-hostile-30.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-30.html +6 -0
- package/conformance/sheet/sheet-hostile-30.meta +5 -0
- package/conformance/sheet/sheet-hostile-31.expected.json +19 -0
- package/conformance/sheet/sheet-hostile-31.html +6 -0
- package/conformance/sheet/sheet-hostile-31.meta +5 -0
- package/conformance/sheet/sheet-hostile-32.expected.json +24 -0
- package/conformance/sheet/sheet-hostile-32.html +6 -0
- package/conformance/sheet/sheet-hostile-32.meta +5 -0
- package/conformance/sheet/sheet-hostile-33.expected.json +18 -0
- package/conformance/sheet/sheet-hostile-33.html +6 -0
- package/conformance/sheet/sheet-hostile-33.meta +5 -0
- package/conformance/sheet/sheet-hostile-34.expected.json +24 -0
- package/conformance/sheet/sheet-hostile-34.html +8 -0
- package/conformance/sheet/sheet-hostile-34.meta +5 -0
- package/conformance/sheet/sheet-hostile-35.expected.json +24 -0
- package/conformance/sheet/sheet-hostile-35.html +8 -0
- package/conformance/sheet/sheet-hostile-35.meta +5 -0
- package/conformance/sheet/sheet-patch-append.after.html +27 -0
- package/conformance/sheet/sheet-patch-append.after.json +143 -0
- package/conformance/sheet/sheet-patch-append.data.json +15 -0
- package/conformance/sheet/sheet-patch-append.html +25 -0
- package/conformance/sheet/sheet-patch-append.meta +5 -0
- package/conformance/sheet/sheet-patch-append.write.json +7 -0
- package/conformance/sheet/sheet-patch-bad-range.data.json +11 -0
- package/conformance/sheet/sheet-patch-bad-range.error.json +6 -0
- package/conformance/sheet/sheet-patch-bad-range.html +25 -0
- package/conformance/sheet/sheet-patch-bad-range.meta +5 -0
- package/conformance/sheet/sheet-patch-bad-value.data.json +13 -0
- package/conformance/sheet/sheet-patch-bad-value.error.json +6 -0
- package/conformance/sheet/sheet-patch-bad-value.html +25 -0
- package/conformance/sheet/sheet-patch-bad-value.meta +5 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.after.html +25 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.after.json +129 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.data.json +11 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.html +25 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.meta +5 -0
- package/conformance/sheet/sheet-patch-clean-tab-beside-edited.write.json +7 -0
- package/conformance/sheet/sheet-patch-covered-cell.data.json +10 -0
- package/conformance/sheet/sheet-patch-covered-cell.error.json +6 -0
- package/conformance/sheet/sheet-patch-covered-cell.html +10 -0
- package/conformance/sheet/sheet-patch-covered-cell.meta +5 -0
- package/conformance/sheet/sheet-patch-empty.data.json +1 -0
- package/conformance/sheet/sheet-patch-empty.error.json +6 -0
- package/conformance/sheet/sheet-patch-empty.html +25 -0
- package/conformance/sheet/sheet-patch-empty.meta +5 -0
- package/conformance/sheet/sheet-patch-fallback-route.after.html +24 -0
- package/conformance/sheet/sheet-patch-fallback-route.after.json +86 -0
- package/conformance/sheet/sheet-patch-fallback-route.data.json +10 -0
- package/conformance/sheet/sheet-patch-fallback-route.html +24 -0
- package/conformance/sheet/sheet-patch-fallback-route.meta +5 -0
- package/conformance/sheet/sheet-patch-fallback-route.write.json +7 -0
- package/conformance/sheet/sheet-patch-first-tab.after.html +25 -0
- package/conformance/sheet/sheet-patch-first-tab.after.json +129 -0
- package/conformance/sheet/sheet-patch-first-tab.data.json +10 -0
- package/conformance/sheet/sheet-patch-first-tab.html +25 -0
- package/conformance/sheet/sheet-patch-first-tab.meta +5 -0
- package/conformance/sheet/sheet-patch-first-tab.write.json +7 -0
- package/conformance/sheet/sheet-patch-formula.after.html +25 -0
- package/conformance/sheet/sheet-patch-formula.after.json +128 -0
- package/conformance/sheet/sheet-patch-formula.data.json +11 -0
- package/conformance/sheet/sheet-patch-formula.html +25 -0
- package/conformance/sheet/sheet-patch-formula.meta +5 -0
- package/conformance/sheet/sheet-patch-formula.write.json +7 -0
- package/conformance/sheet/sheet-patch-no-sheet-rule.data.json +10 -0
- package/conformance/sheet/sheet-patch-no-sheet-rule.error.json +6 -0
- package/conformance/sheet/sheet-patch-no-sheet-rule.html +18 -0
- package/conformance/sheet/sheet-patch-no-sheet-rule.meta +5 -0
- package/conformance/sheet/sheet-patch-no-values.data.json +6 -0
- package/conformance/sheet/sheet-patch-no-values.error.json +6 -0
- package/conformance/sheet/sheet-patch-no-values.html +25 -0
- package/conformance/sheet/sheet-patch-no-values.meta +5 -0
- package/conformance/sheet/sheet-patch-not-canonical.data.json +11 -0
- package/conformance/sheet/sheet-patch-not-canonical.error.json +6 -0
- package/conformance/sheet/sheet-patch-not-canonical.html +25 -0
- package/conformance/sheet/sheet-patch-not-canonical.meta +5 -0
- package/conformance/sheet/sheet-patch-outside-sheet.data.json +11 -0
- package/conformance/sheet/sheet-patch-outside-sheet.error.json +6 -0
- package/conformance/sheet/sheet-patch-outside-sheet.html +25 -0
- package/conformance/sheet/sheet-patch-outside-sheet.meta +5 -0
- package/conformance/sheet/sheet-patch-range.after.html +25 -0
- package/conformance/sheet/sheet-patch-range.after.json +126 -0
- package/conformance/sheet/sheet-patch-range.data.json +11 -0
- package/conformance/sheet/sheet-patch-range.html +25 -0
- package/conformance/sheet/sheet-patch-range.meta +5 -0
- package/conformance/sheet/sheet-patch-range.write.json +7 -0
- package/conformance/sheet/sheet-patch-two-tabs.after.html +25 -0
- package/conformance/sheet/sheet-patch-two-tabs.after.json +130 -0
- package/conformance/sheet/sheet-patch-two-tabs.data.json +20 -0
- package/conformance/sheet/sheet-patch-two-tabs.html +25 -0
- package/conformance/sheet/sheet-patch-two-tabs.meta +5 -0
- package/conformance/sheet/sheet-patch-two-tabs.write.json +7 -0
- package/conformance/sheet/sheet-patch-typed.after.html +25 -0
- package/conformance/sheet/sheet-patch-typed.after.json +121 -0
- package/conformance/sheet/sheet-patch-typed.data.json +13 -0
- package/conformance/sheet/sheet-patch-typed.html +25 -0
- package/conformance/sheet/sheet-patch-typed.meta +5 -0
- package/conformance/sheet/sheet-patch-typed.write.json +7 -0
- package/conformance/sheet/sheet-patch-unknown-sheet.data.json +11 -0
- package/conformance/sheet/sheet-patch-unknown-sheet.error.json +6 -0
- package/conformance/sheet/sheet-patch-unknown-sheet.html +25 -0
- package/conformance/sheet/sheet-patch-unknown-sheet.meta +5 -0
- package/conformance/sheet/sheet-read-bad-range.error.json +6 -0
- package/conformance/sheet/sheet-read-bad-range.html +25 -0
- package/conformance/sheet/sheet-read-bad-range.meta +6 -0
- package/conformance/sheet/sheet-read-bad-render.error.json +6 -0
- package/conformance/sheet/sheet-read-bad-render.html +25 -0
- package/conformance/sheet/sheet-read-bad-render.meta +6 -0
- package/conformance/sheet/sheet-read-digest.expected.json +91 -0
- package/conformance/sheet/sheet-read-digest.html +25 -0
- package/conformance/sheet/sheet-read-digest.meta +6 -0
- package/conformance/sheet/sheet-read-empty.expected.json +11 -0
- package/conformance/sheet/sheet-read-empty.html +6 -0
- package/conformance/sheet/sheet-read-empty.meta +5 -0
- package/conformance/sheet/sheet-read-escapes.expected.json +108 -0
- package/conformance/sheet/sheet-read-escapes.html +22 -0
- package/conformance/sheet/sheet-read-escapes.meta +5 -0
- package/conformance/sheet/sheet-read-formulas-formatted.expected.json +298 -0
- package/conformance/sheet/sheet-read-formulas-formatted.html +16 -0
- package/conformance/sheet/sheet-read-formulas-formatted.meta +5 -0
- package/conformance/sheet/sheet-read-grid-in-comment.expected.json +85 -0
- package/conformance/sheet/sheet-read-grid-in-comment.html +24 -0
- package/conformance/sheet/sheet-read-grid-in-comment.meta +5 -0
- package/conformance/sheet/sheet-read-grid-in-script.expected.json +85 -0
- package/conformance/sheet/sheet-read-grid-in-script.html +24 -0
- package/conformance/sheet/sheet-read-grid-in-script.meta +5 -0
- package/conformance/sheet/sheet-read-grid-in-template.expected.json +85 -0
- package/conformance/sheet/sheet-read-grid-in-template.html +24 -0
- package/conformance/sheet/sheet-read-grid-in-template.meta +5 -0
- package/conformance/sheet/sheet-read-grid-in-textarea.expected.json +85 -0
- package/conformance/sheet/sheet-read-grid-in-textarea.html +24 -0
- package/conformance/sheet/sheet-read-grid-in-textarea.meta +5 -0
- package/conformance/sheet/sheet-read-grid-outside-read-by-rule.expected.json +94 -0
- package/conformance/sheet/sheet-read-grid-outside-read-by-rule.html +24 -0
- package/conformance/sheet/sheet-read-grid-outside-read-by-rule.meta +5 -0
- package/conformance/sheet/sheet-read-grid-outside-sheet.expected.json +85 -0
- package/conformance/sheet/sheet-read-grid-outside-sheet.html +24 -0
- package/conformance/sheet/sheet-read-grid-outside-sheet.meta +5 -0
- package/conformance/sheet/sheet-read-hand-edited.expected.json +85 -0
- package/conformance/sheet/sheet-read-hand-edited.html +18 -0
- package/conformance/sheet/sheet-read-hand-edited.meta +5 -0
- package/conformance/sheet/sheet-read-index.expected.json +19 -0
- package/conformance/sheet/sheet-read-index.html +25 -0
- package/conformance/sheet/sheet-read-index.meta +6 -0
- package/conformance/sheet/sheet-read-merged.expected.json +59 -0
- package/conformance/sheet/sheet-read-merged.html +10 -0
- package/conformance/sheet/sheet-read-merged.meta +5 -0
- package/conformance/sheet/sheet-read-no-tag.error.json +5 -0
- package/conformance/sheet/sheet-read-no-tag.html +18 -0
- package/conformance/sheet/sheet-read-no-tag.meta +5 -0
- package/conformance/sheet/sheet-read-padded-name-index.expected.json +19 -0
- package/conformance/sheet/sheet-read-padded-name-index.html +25 -0
- package/conformance/sheet/sheet-read-padded-name-index.meta +6 -0
- package/conformance/sheet/sheet-read-padded-name-lookup.expected.json +83 -0
- package/conformance/sheet/sheet-read-padded-name-lookup.html +25 -0
- package/conformance/sheet/sheet-read-padded-name-lookup.meta +6 -0
- package/conformance/sheet/sheet-read-padded-name-trimmed-lookup.error.json +6 -0
- package/conformance/sheet/sheet-read-padded-name-trimmed-lookup.html +25 -0
- package/conformance/sheet/sheet-read-padded-name-trimmed-lookup.meta +6 -0
- package/conformance/sheet/sheet-read-padded-name.expected.json +128 -0
- package/conformance/sheet/sheet-read-padded-name.html +25 -0
- package/conformance/sheet/sheet-read-padded-name.meta +5 -0
- package/conformance/sheet/sheet-read-range-cells.expected.json +55 -0
- package/conformance/sheet/sheet-read-range-cells.html +25 -0
- package/conformance/sheet/sheet-read-range-cells.meta +6 -0
- package/conformance/sheet/sheet-read-range-first-tab.expected.json +12 -0
- package/conformance/sheet/sheet-read-range-first-tab.html +25 -0
- package/conformance/sheet/sheet-read-range-first-tab.meta +6 -0
- package/conformance/sheet/sheet-read-range-formulas.expected.json +24 -0
- package/conformance/sheet/sheet-read-range-formulas.html +25 -0
- package/conformance/sheet/sheet-read-range-formulas.meta +6 -0
- package/conformance/sheet/sheet-read-range-values.expected.json +24 -0
- package/conformance/sheet/sheet-read-range-values.html +25 -0
- package/conformance/sheet/sheet-read-range-values.meta +6 -0
- package/conformance/sheet/sheet-read-sheet-by-id.expected.json +46 -0
- package/conformance/sheet/sheet-read-sheet-by-id.html +25 -0
- package/conformance/sheet/sheet-read-sheet-by-id.meta +6 -0
- package/conformance/sheet/sheet-read-sheet-by-name.expected.json +46 -0
- package/conformance/sheet/sheet-read-sheet-by-name.html +25 -0
- package/conformance/sheet/sheet-read-sheet-by-name.meta +6 -0
- package/conformance/sheet/sheet-read-styled.expected.json +48 -0
- package/conformance/sheet/sheet-read-styled.html +10 -0
- package/conformance/sheet/sheet-read-styled.meta +5 -0
- package/conformance/sheet/sheet-read-tiny.expected.json +85 -0
- package/conformance/sheet/sheet-read-tiny.html +18 -0
- package/conformance/sheet/sheet-read-tiny.meta +5 -0
- package/conformance/sheet/sheet-read-two-tabs.expected.json +128 -0
- package/conformance/sheet/sheet-read-two-tabs.html +25 -0
- package/conformance/sheet/sheet-read-two-tabs.meta +5 -0
- package/conformance/sheet/sheet-read-unknown-sheet.error.json +6 -0
- package/conformance/sheet/sheet-read-unknown-sheet.html +25 -0
- package/conformance/sheet/sheet-read-unknown-sheet.meta +6 -0
- package/conformance/sheet/sheet-read-version-1-codec.error.json +5 -0
- package/conformance/sheet/sheet-read-version-1-codec.html +25 -0
- package/conformance/sheet/sheet-read-version-1-codec.meta +5 -0
- package/conformance/sheet/sheet-write-whole-refused.data.json +3 -0
- package/conformance/sheet/sheet-write-whole-refused.error.json +7 -0
- package/conformance/sheet/sheet-write-whole-refused.html +25 -0
- package/conformance/sheet/sheet-write-whole-refused.meta +5 -0
- package/conformance/sheet-guard-extraction.json +616 -0
- package/conformance/sheet-guard.json +32362 -0
- package/conformance/sheet-read-shapes.json +1 -0
- package/dist/hyper-html-api.engine.esm.js +1 -1
- package/dist/hyper-html-api.engine.min.js +1 -1
- package/dist/hyper-html-api.min.js +7 -7
- package/dist/hyper-html-api.upgrade.min.js +2 -2
- package/package.json +5 -3
- package/src/codecs/sheet.js +127 -0
- package/src/codecs/sheet.vendor.js +887 -0
- package/src/dom-api.js +20 -11
- package/src/engine/apply.js +12 -1
- package/src/engine/codecs.js +80 -0
- package/src/engine/errors.js +20 -1
- package/src/engine/extract.js +11 -0
- package/src/engine/index.js +9 -5
- package/src/engine/round-trip.js +16 -10
- package/src/engine/rule-syntax.js +16 -0
- package/src/engine/rules-tag.js +3 -2
- package/src/engine/write-plan.js +2 -0
- package/src/patch-document.js +122 -0
- package/src/read.js +163 -0
- package/src/upgrade/codec-carry.js +23 -0
- package/src/upgrade/extract-all.js +12 -3
- package/src/upgrade/migrate.js +30 -3
- package/src/upgrade/rules-tags.js +4 -4
- package/src/write.js +44 -5
package/src/read.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import cheerioAdapter from './adapters/cheerio.js'
|
|
2
|
+
import { extract } from './engine/extract.js'
|
|
3
|
+
import { findRulesIn } from './engine/rules-tag.js'
|
|
4
|
+
import { codecOf } from './engine/rule-syntax.js'
|
|
5
|
+
import { sheet } from './codecs/sheet.js'
|
|
6
|
+
import { checkCodecRules } from './engine/codecs.js'
|
|
7
|
+
import { holeMarker, QueryRefused } from './codecs/sheet.vendor.js'
|
|
8
|
+
|
|
9
|
+
// The URL parameters a host passes to readDocument as `query`, from a
|
|
10
|
+
// URLSearchParams. Returns null when none of them is present (a whole read,
|
|
11
|
+
// exactly as before). Each may appear once with a value, and none may be
|
|
12
|
+
// mixed with ?data= (a caller-supplied rule set); anything else is
|
|
13
|
+
// QueryRefused('bad_query'), which hosts answer with 400. Values are not
|
|
14
|
+
// checked here: readDocument refuses a bad one with its own code.
|
|
15
|
+
export const SHEET_QUERY_PARAMS = ['shape', 'sheet', 'range', 'render']
|
|
16
|
+
|
|
17
|
+
export function parseSheetQuery(params) {
|
|
18
|
+
const query = {}
|
|
19
|
+
for (const key of SHEET_QUERY_PARAMS) {
|
|
20
|
+
const values = params.getAll(key)
|
|
21
|
+
if (values.length === 0) continue
|
|
22
|
+
if (values.length > 1) throw new QueryRefused('bad_query', `${key} appears ${values.length} times; send it once`)
|
|
23
|
+
if (values[0] === '') throw new QueryRefused('bad_query', `${key} is empty; give it a value or leave it out`)
|
|
24
|
+
query[key] = values[0]
|
|
25
|
+
}
|
|
26
|
+
if (Object.keys(query).length === 0) return null
|
|
27
|
+
if (params.has('data')) throw new QueryRefused('bad_query', `data cannot be combined with ${Object.keys(query).join(', ')}; a sheet query reads the document's own rules`)
|
|
28
|
+
return query
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Reads a document's data through its rules tag, from source. `load` is
|
|
32
|
+
// cheerio.load, passed in so this package keeps cheerio out of its browser
|
|
33
|
+
// bundles. Returns { data, version, fast }; data is null when no rules tag
|
|
34
|
+
// carries `token`.
|
|
35
|
+
//
|
|
36
|
+
// A codec with cut() lets a host skip parsing its regions: the source is cut,
|
|
37
|
+
// only the rest is parsed, and each hole hands the codec its region's bytes.
|
|
38
|
+
// The holes are verified first: every hole is a real element, each index
|
|
39
|
+
// appears exactly once and in order, and every hole lies under the element a
|
|
40
|
+
// rule naming that codec selected, which only that codec reads. Anything else
|
|
41
|
+
// (a grid inside a comment, a script or a textarea, a grid outside the sheet)
|
|
42
|
+
// discards the cut and reads the whole source through the tree. `fast` is false whenever a
|
|
43
|
+
// `<table grid` was read through the tree (that fallback, or a hand-edited table
|
|
44
|
+
// the cut left in place), so a host can count how often the slow route runs.
|
|
45
|
+
//
|
|
46
|
+
// options: { token = 'api', query, view, codecs = { sheet } }. query and view
|
|
47
|
+
// reach every codec rule (see src/codecs/sheet.js for the sheet's shapes).
|
|
48
|
+
export function readDocument(load, src, options = {}) {
|
|
49
|
+
const { token = 'api', query, view, codecs = { sheet } } = options
|
|
50
|
+
const call = { codecs, query, view }
|
|
51
|
+
const cutting = Object.entries(codecs).filter(([, codec]) => typeof codec.cut === 'function')
|
|
52
|
+
if (cutting.length > 1) throw new Error('hyper-html-api: readDocument supports one codec with cut()')
|
|
53
|
+
|
|
54
|
+
if (cutting.length === 1) {
|
|
55
|
+
const [name, codec] = cutting[0]
|
|
56
|
+
const marker = holeMarker(src)
|
|
57
|
+
const { rest, regions } = codec.cut(src, marker)
|
|
58
|
+
if (regions.length > 0) {
|
|
59
|
+
const $ = load(rest)
|
|
60
|
+
const root = $.root()
|
|
61
|
+
const found = findRulesIn(cheerioAdapter, root, token)
|
|
62
|
+
const fast = countGrids(rest) === regions.length
|
|
63
|
+
if (!found) return { data: null, version: null, fast }
|
|
64
|
+
if (codec === sheet && readHolesHold($, root, found.rules, name, marker, regions.length)) {
|
|
65
|
+
const region = (table) => regionBytes(table, src, marker, regions)
|
|
66
|
+
const opts = { ...call, version: found.version, region }
|
|
67
|
+
checkCodecRules(found.rules, opts)
|
|
68
|
+
let tree
|
|
69
|
+
const data = {}
|
|
70
|
+
for (const [key, rule] of Object.entries(found.rules)) {
|
|
71
|
+
const codec = codecOf(rule)
|
|
72
|
+
const context = codec ? root : (tree ??= load(src).root())
|
|
73
|
+
data[key] = extract(cheerioAdapter, context, { [key]: rule }, { ...opts, region: codec ? region : undefined })[key]
|
|
74
|
+
}
|
|
75
|
+
return { data, version: found.version, fast }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const fast = !src.includes(GRID)
|
|
81
|
+
|
|
82
|
+
const root = load(src).root()
|
|
83
|
+
const found = findRulesIn(cheerioAdapter, root, token)
|
|
84
|
+
if (!found) return { data: null, version: null, fast }
|
|
85
|
+
return { data: extract(cheerioAdapter, root, found.rules, { ...call, version: found.version }), version: found.version, fast }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// A document's rules tag as { rules, version }, or null when no tag carries
|
|
89
|
+
// `token`, without parsing its canonical tables: what a host needs to classify
|
|
90
|
+
// a request body (isPatchBody) before it reads or patches. Same cut and checks
|
|
91
|
+
// as readDocument; anything they reject is found by parsing the whole source.
|
|
92
|
+
export function documentRules(load, src, options = {}) {
|
|
93
|
+
const { token = 'api', codecs = { sheet } } = options
|
|
94
|
+
const cutting = Object.entries(codecs).filter(([, codec]) => typeof codec.cut === 'function')
|
|
95
|
+
if (cutting.length === 1) {
|
|
96
|
+
const [name, codec] = cutting[0]
|
|
97
|
+
const marker = holeMarker(src)
|
|
98
|
+
const { rest, regions } = codec.cut(src, marker)
|
|
99
|
+
if (regions.length > 0) {
|
|
100
|
+
const $ = load(rest)
|
|
101
|
+
const root = $.root()
|
|
102
|
+
const found = findRulesIn(cheerioAdapter, root, token)
|
|
103
|
+
if (!found) return null
|
|
104
|
+
if (holesHold($, root, found.rules, name, marker, regions.length)) return { rules: found.rules, version: found.version }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const found = findRulesIn(cheerioAdapter, load(src).root(), token)
|
|
108
|
+
return found ? { rules: found.rules, version: found.version } : null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const GRID = '<table grid'
|
|
112
|
+
|
|
113
|
+
function countGrids(text) {
|
|
114
|
+
let n = 0
|
|
115
|
+
for (let at = text.indexOf(GRID); at !== -1; at = text.indexOf(GRID, at + 1)) n++
|
|
116
|
+
return n
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function holesHold($, root, rules, name, marker, count) {
|
|
120
|
+
const holes = $('table[data-hole]').toArray()
|
|
121
|
+
if (holes.length !== count) return false
|
|
122
|
+
const containers = codecContainers(root, rules, name)
|
|
123
|
+
if (containers.length === 0) return false
|
|
124
|
+
return holes.every((hole, n) =>
|
|
125
|
+
hole.attribs['data-hole'] === `${marker}-${n}` &&
|
|
126
|
+
containers.some((container) => container === hole || $.contains(container, hole)))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Only this selector cannot match within canonical grid bytes or depend on their children.
|
|
130
|
+
const SHEET_CONTAINER = /^\[items\s*=\s*(?:sheets|"sheets"|'sheets')\]$/
|
|
131
|
+
|
|
132
|
+
function readHolesHold($, root, rules, name, marker, count) {
|
|
133
|
+
if (!rules || typeof rules !== 'object' || Array.isArray(rules)) return false
|
|
134
|
+
for (const rule of Object.values(rules)) {
|
|
135
|
+
const form = codecOf(rule)
|
|
136
|
+
if (form && (form.name !== name || !SHEET_CONTAINER.test(form.selector))) return false
|
|
137
|
+
}
|
|
138
|
+
if (!holesHold($, root, rules, name, marker, count)) return false
|
|
139
|
+
const containers = new Set(codecContainers(root, rules, name))
|
|
140
|
+
return $('table[grid]').length === count && $('table[data-hole]').toArray().every(hole =>
|
|
141
|
+
hole.parent?.name === 'section' && Object.hasOwn(hole.parent.attribs, 'item') && containers.has(hole.parent.parent))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// The element each top level `selector@codec(name)` rule selects, as the engine
|
|
145
|
+
// would read it: the first match, or the document itself for a bare "@codec(name)".
|
|
146
|
+
function codecContainers(root, rules, name) {
|
|
147
|
+
if (!rules || typeof rules !== 'object' || Array.isArray(rules)) return []
|
|
148
|
+
const out = []
|
|
149
|
+
for (const rule of Object.values(rules)) {
|
|
150
|
+
const form = codecOf(rule)
|
|
151
|
+
if (!form || form.name !== name) continue
|
|
152
|
+
const node = form.selector ? cheerioAdapter.find(root, form.selector)[0] : root
|
|
153
|
+
if (node && node.get(0)) out.push(node.get(0))
|
|
154
|
+
}
|
|
155
|
+
return out
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function regionBytes(table, src, marker, regions) {
|
|
159
|
+
const hole = cheerioAdapter.attr(table, 'data-hole')
|
|
160
|
+
if (!hole || !hole.startsWith(`${marker}-`)) return null
|
|
161
|
+
const region = regions[Number(hole.slice(marker.length + 1))]
|
|
162
|
+
return region ? src.slice(region.start, region.end) : null
|
|
163
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { codecOf } from '../engine/rule-syntax.js'
|
|
2
|
+
|
|
3
|
+
// Under a version 2 rules tag, a top level `@codec(name)` key (a sheet) is
|
|
4
|
+
// carried whole on upgrade: the extract side keeps its container's markup as
|
|
5
|
+
// a string, and the migrate side puts that string into the same key's
|
|
6
|
+
// container in the new template. The value is never read into data and
|
|
7
|
+
// written back, so the codec needs no whole-value write and the canonical
|
|
8
|
+
// bytes its grammar reads stay as they were.
|
|
9
|
+
export function splitCarried(rules, version) {
|
|
10
|
+
if (version !== '2' || !rules || typeof rules !== 'object' || Array.isArray(rules)) return { rules, carried: [] }
|
|
11
|
+
const rest = {}
|
|
12
|
+
const carried = []
|
|
13
|
+
for (const [key, rule] of Object.entries(rules)) {
|
|
14
|
+
const codec = codecOf(rule)
|
|
15
|
+
if (codec) carried.push({ key, selector: codec.selector })
|
|
16
|
+
else rest[key] = rule
|
|
17
|
+
}
|
|
18
|
+
return { rules: rest, carried }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function carriedNode(adapter, root, selector) {
|
|
22
|
+
return adapter.find(root, selector)[0] || null
|
|
23
|
+
}
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { extract } from '../engine/extract.js'
|
|
2
2
|
import domAdapter from '../adapters/dom.js'
|
|
3
3
|
import { collectRulesTags } from './rules-tags.js'
|
|
4
|
+
import { splitCarried, carriedNode } from './codec-carry.js'
|
|
4
5
|
import { readMeta } from './check.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Keyed extraction: one entry per rules tag under `root`, keyed by the
|
|
8
9
|
* normalized data-rules-name value. This is the v1 side of an upgrade:
|
|
9
|
-
* pack the page's data into labeled boxes.
|
|
10
|
+
* pack the page's data into labeled boxes. A `@codec(name)` key (a sheet,
|
|
11
|
+
* version 2 tags only) packs as its container's markup string, which a
|
|
12
|
+
* transform passes through unchanged.
|
|
10
13
|
*/
|
|
11
14
|
export function extractAllFrom(adapter, root) {
|
|
12
15
|
const dataByName = {}
|
|
13
|
-
for (const { name, rules } of collectRulesTags(adapter, root)) {
|
|
14
|
-
|
|
16
|
+
for (const { name, rules, version } of collectRulesTags(adapter, root)) {
|
|
17
|
+
const { rules: plain, carried } = splitCarried(rules, version)
|
|
18
|
+
const data = extract(adapter, root, plain, { version })
|
|
19
|
+
for (const { key, selector } of carried) {
|
|
20
|
+
const node = carriedNode(adapter, root, selector)
|
|
21
|
+
data[key] = node ? adapter.prop(node, 'innerHTML') : null
|
|
22
|
+
}
|
|
23
|
+
dataByName[name] = data
|
|
15
24
|
}
|
|
16
25
|
return dataByName
|
|
17
26
|
}
|
package/src/upgrade/migrate.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { apply } from '../engine/apply.js'
|
|
2
2
|
import { collectRulesTags } from './rules-tags.js'
|
|
3
3
|
import { shapeMatch, countScalarLeaves } from './shape-match.js'
|
|
4
|
+
import { splitCarried, carriedNode } from './codec-carry.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Pour keyed v1 data into the v2 document. Exact-name join: each v2 rules
|
|
7
8
|
* tag pulls the entry with the same normalized name; tags with no matching
|
|
8
9
|
* entry keep their template defaults; v1 entries with no matching tag are
|
|
9
10
|
* counted as discarded. Renames are the transform's job, not the join's.
|
|
11
|
+
* A `@codec(name)` key takes its markup string whole into the new
|
|
12
|
+
* template's container for that key.
|
|
10
13
|
*/
|
|
11
14
|
export function migrateInto(adapter, root, dataByName) {
|
|
12
15
|
const tags = collectRulesTags(adapter, root)
|
|
@@ -14,15 +17,28 @@ export function migrateInto(adapter, root, dataByName) {
|
|
|
14
17
|
const byName = {}
|
|
15
18
|
const v2Names = new Set()
|
|
16
19
|
|
|
17
|
-
for (const { name, rules } of tags) {
|
|
20
|
+
for (const { name, rules, version } of tags) {
|
|
18
21
|
v2Names.add(name)
|
|
19
22
|
if (!Object.prototype.hasOwnProperty.call(dataByName, name)) {
|
|
20
23
|
byName[name] = { carriedOver: 0, discarded: 0, listItems: 0 }
|
|
21
24
|
continue
|
|
22
25
|
}
|
|
23
|
-
const {
|
|
26
|
+
const { rules: plain, carried } = splitCarried(rules, version)
|
|
27
|
+
const entry = dataByName[name]
|
|
28
|
+
const { data, summary } = shapeMatch(withoutCarried(entry, carried), plain)
|
|
24
29
|
// A row whose nested list is empty at that spot in v2 grows from the page's seeds, as a write does.
|
|
25
|
-
apply(adapter, root,
|
|
30
|
+
apply(adapter, root, plain, data, { templateAttr: 'cms-template' })
|
|
31
|
+
for (const { key, selector } of carried) {
|
|
32
|
+
const markup = isPlainObject(entry) ? entry[key] : undefined
|
|
33
|
+
if (markup === undefined || markup === null) continue
|
|
34
|
+
const node = carriedNode(adapter, root, selector)
|
|
35
|
+
if (typeof markup === 'string' && node) {
|
|
36
|
+
adapter.prop(node, 'innerHTML', markup)
|
|
37
|
+
summary.carriedOver += 1
|
|
38
|
+
} else {
|
|
39
|
+
summary.discarded += 1
|
|
40
|
+
}
|
|
41
|
+
}
|
|
26
42
|
byName[name] = summary
|
|
27
43
|
totals.carriedOver += summary.carriedOver
|
|
28
44
|
totals.discarded += summary.discarded
|
|
@@ -35,3 +51,14 @@ export function migrateInto(adapter, root, dataByName) {
|
|
|
35
51
|
|
|
36
52
|
return { totals, byName, rulesTagCount: tags.length }
|
|
37
53
|
}
|
|
54
|
+
|
|
55
|
+
function isPlainObject(value) {
|
|
56
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function withoutCarried(entry, carried) {
|
|
60
|
+
if (!carried.length || !isPlainObject(entry)) return entry
|
|
61
|
+
const rest = { ...entry }
|
|
62
|
+
for (const { key } of carried) delete rest[key]
|
|
63
|
+
return rest
|
|
64
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseRelaxed } from '../engine/rules.js'
|
|
2
|
-
import {
|
|
2
|
+
import { SUPPORTED_VERSIONS } from '../engine/rules-tag.js'
|
|
3
3
|
import { UnknownRulesVersion } from '../engine/errors.js'
|
|
4
4
|
|
|
5
5
|
const RULES_SELECTOR = 'script[data-rules-name]'
|
|
@@ -9,7 +9,7 @@ export function normalizeName(raw) {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Collect every rules tag under `root` as [{ name, rules }], keyed by the
|
|
12
|
+
* Collect every rules tag under `root` as [{ name, rules, version }], keyed by the
|
|
13
13
|
* whitespace-normalized data-rules-name attribute value. Duplicate names:
|
|
14
14
|
* first tag wins with a warning (mirrors findRulesIn). Unsupported
|
|
15
15
|
* data-rules-version throws so engine-format skew fails loudly instead of
|
|
@@ -29,9 +29,9 @@ export function collectRulesTags(adapter, root) {
|
|
|
29
29
|
continue
|
|
30
30
|
}
|
|
31
31
|
const version = adapter.attr(tag, 'data-rules-version')
|
|
32
|
-
if (version
|
|
32
|
+
if (!SUPPORTED_VERSIONS.includes(version)) throw new UnknownRulesVersion(version)
|
|
33
33
|
seen.add(name)
|
|
34
|
-
out.push({ name, rules: parseRelaxed(adapter.text(tag)) })
|
|
34
|
+
out.push({ name, rules: parseRelaxed(adapter.text(tag)), version })
|
|
35
35
|
}
|
|
36
36
|
return out
|
|
37
37
|
}
|
package/src/write.js
CHANGED
|
@@ -7,18 +7,23 @@ import { planWrite } from './engine/write-plan.js'
|
|
|
7
7
|
import { assertRoundTrip } from './engine/round-trip.js'
|
|
8
8
|
import { trackAdapter, spliceDocument } from './engine/splice.js'
|
|
9
9
|
import { NoRulesTag, RulesParseError, WriteRejected } from './engine/errors.js'
|
|
10
|
+
import { sheet } from './codecs/sheet.js'
|
|
11
|
+
import { codecOf } from './engine/rule-syntax.js'
|
|
10
12
|
|
|
11
13
|
// Applies a JSON body to a document's source through caller-provided rules
|
|
12
14
|
// (options.rules) or the document's own rules tag, under the content-only
|
|
13
15
|
// policy. `load` is cheerio.load, passed in so this package keeps cheerio out
|
|
14
16
|
// of its browser bundles. Returns the new source and whether anything changed.
|
|
15
17
|
// Throws NoRulesTag, RulesParseError, WriteRejected, WriteRefused, ShapeMismatch,
|
|
16
|
-
// EmptyListInsert or WriteNotRoundTripped, always before producing
|
|
18
|
+
// EmptyListInsert, UnknownCodec or WriteNotRoundTripped, always before producing
|
|
19
|
+
// any output. options.codecs maps a name to a codec for `@codec(name)` rules,
|
|
20
|
+
// which only a version 2 rules tag may use (default: the sheet codec).
|
|
17
21
|
export function writeDocument(load, src, data, options = {}) {
|
|
18
|
-
const { token = 'api' } = options
|
|
22
|
+
const { token = 'api', codecs = { sheet } } = options
|
|
19
23
|
const $ = load(src, { sourceCodeLocationInfo: true })
|
|
20
24
|
const root = $.root()
|
|
21
25
|
let rules
|
|
26
|
+
let version = '1'
|
|
22
27
|
if (Object.prototype.hasOwnProperty.call(options, 'rules')) {
|
|
23
28
|
rules = options.rules
|
|
24
29
|
if (rules === null || !['string', 'object'].includes(typeof rules)) {
|
|
@@ -28,10 +33,11 @@ export function writeDocument(load, src, data, options = {}) {
|
|
|
28
33
|
const found = findRulesIn(cheerioAdapter, root, token)
|
|
29
34
|
if (!found) throw new NoRulesTag(token)
|
|
30
35
|
rules = found.rules
|
|
36
|
+
version = found.version
|
|
31
37
|
}
|
|
32
|
-
const plan = planWrite(cheerioAdapter, root, rules, data)
|
|
38
|
+
const plan = planWrite(cheerioAdapter, root, rules, data, { version, codecs })
|
|
33
39
|
if (plan.unknownKeys.length || plan.unmatched.length) throw new WriteRejected(plan.unknownKeys, plan.unmatched)
|
|
34
|
-
const opts = { templateAttr: 'cms-template' }
|
|
40
|
+
const opts = { templateAttr: 'cms-template', version, codecs }
|
|
35
41
|
const tracker = trackAdapter(cheerioAdapter)
|
|
36
42
|
const guarded = guardAdapter(tracker)
|
|
37
43
|
apply(guarded, root, rules, data, opts)
|
|
@@ -46,7 +52,7 @@ export function writeDocument(load, src, data, options = {}) {
|
|
|
46
52
|
// pays for the field it wrote, not for every rule in the document.
|
|
47
53
|
const written = writtenRules(rules, data)
|
|
48
54
|
const writtenRoot = load(html).root()
|
|
49
|
-
assertRoundTrip(written, data, extract(cheerioAdapter, writtenRoot, written, { ...opts, allMatches: true }))
|
|
55
|
+
assertRoundTrip(written, data, extract(cheerioAdapter, writtenRoot, written, { ...opts, allMatches: true }), codecs)
|
|
50
56
|
return { html, changed: html !== src, spliced }
|
|
51
57
|
}
|
|
52
58
|
|
|
@@ -65,3 +71,36 @@ function writtenRules(rules, data) {
|
|
|
65
71
|
function isPlainObject(value) {
|
|
66
72
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
67
73
|
}
|
|
74
|
+
|
|
75
|
+
export { patchDocument, NOT_CANONICAL_MESSAGE } from './patch-document.js'
|
|
76
|
+
|
|
77
|
+
// The one rule every host uses to tell a patch body from a data write: an
|
|
78
|
+
// object whose `patch` value is an array and whose only other key is
|
|
79
|
+
// `operationId`, sent to a document whose rules have no top level key named
|
|
80
|
+
// `patch`. Anything else is a data write, exactly as before patches existed.
|
|
81
|
+
export function isPatchBody(body, rules) {
|
|
82
|
+
if (!isPlainObject(body) || !Array.isArray(body.patch)) return false
|
|
83
|
+
if (Object.keys(body).some((key) => key !== 'patch' && key !== 'operationId')) return false
|
|
84
|
+
return !(isPlainObject(rules) && Object.prototype.hasOwnProperty.call(rules, 'patch'))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Rows in a write body, for a host's size limit: every array item counts, at
|
|
88
|
+
// any depth. Under a version 2 rules tag a top level key whose rule is a
|
|
89
|
+
// `@codec(name)` rule is skipped, because its value is not a list of rows (a
|
|
90
|
+
// sheet's size is its cells, and hosts limit those per patch).
|
|
91
|
+
export function countRows(value, rules, version = '1') {
|
|
92
|
+
if (version === '2' && isPlainObject(value) && isPlainObject(rules)) {
|
|
93
|
+
let sum = 0
|
|
94
|
+
for (const [key, item] of Object.entries(value)) {
|
|
95
|
+
if (!codecOf(rules[key])) sum += countAll(item)
|
|
96
|
+
}
|
|
97
|
+
return sum
|
|
98
|
+
}
|
|
99
|
+
return countAll(value)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function countAll(value) {
|
|
103
|
+
if (Array.isArray(value)) return value.reduce((sum, item) => sum + 1 + countAll(item), 0)
|
|
104
|
+
if (value !== null && typeof value === 'object') return Object.values(value).reduce((sum, item) => sum + countAll(item), 0)
|
|
105
|
+
return 0
|
|
106
|
+
}
|