@microsoft/fast-element 2.10.4 → 3.0.0-rc.1
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/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +1 -1
- package/ARCHITECTURE_OVERVIEW.md +2 -2
- package/CHANGELOG.json +1 -1
- package/CHANGELOG.md +2 -2
- package/DECLARATIVE_DESIGN.md +806 -0
- package/DECLARATIVE_HTML.md +470 -0
- package/DECLARATIVE_MIGRATION.md +215 -0
- package/DECLARATIVE_RENDERING.md +530 -0
- package/DECLARATIVE_RENDERING_LIFECYCLE.md +288 -0
- package/DECLARATIVE_SCHEMA_OBSERVER_MAP.md +489 -0
- package/DESIGN.md +138 -33
- package/MIGRATION.md +387 -0
- package/README.md +208 -1
- package/SIZES.md +25 -0
- package/api-extractor.arrays.json +15 -0
- package/api-extractor.context.json +1 -0
- package/api-extractor.declarative.json +15 -0
- package/api-extractor.di.json +1 -0
- package/api-extractor.hydration.json +15 -0
- package/api-extractor.styles.json +15 -0
- package/dist/arrays/arrays.api.json +2621 -0
- package/dist/declarative/declarative.api.json +7844 -0
- package/dist/di/di.api.json +1 -1
- package/dist/dts/array-observer.d.ts +2 -0
- package/dist/dts/arrays.d.ts +2 -0
- package/dist/dts/attr.d.ts +1 -0
- package/dist/dts/binding/signal.d.ts +6 -6
- package/dist/dts/binding/two-way.d.ts +1 -0
- package/dist/dts/binding.d.ts +7 -0
- package/dist/dts/components/attributes.d.ts +2 -5
- package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
- package/dist/dts/components/element-controller.d.ts +80 -114
- package/dist/dts/components/element-hydration.d.ts +1 -1
- package/dist/dts/components/enable-hydration.d.ts +34 -0
- package/dist/dts/components/fast-definitions.d.ts +91 -42
- package/dist/dts/components/fast-element.d.ts +5 -8
- package/dist/dts/components/hydration-tracker.d.ts +40 -0
- package/dist/dts/components/hydration.d.ts +18 -53
- package/dist/dts/components/schema.d.ts +205 -0
- package/dist/dts/context.d.ts +6 -6
- package/dist/dts/css.d.ts +3 -0
- package/dist/dts/debug.d.ts +5 -1
- package/dist/dts/declarative/attribute-map.d.ts +58 -0
- package/dist/dts/declarative/debug.d.ts +5 -0
- package/dist/dts/declarative/index.d.ts +13 -0
- package/dist/dts/declarative/interfaces.d.ts +9 -0
- package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
- package/dist/dts/declarative/observer-map.d.ts +89 -0
- package/dist/dts/declarative/runtime.d.ts +5 -0
- package/dist/dts/declarative/syntax.d.ts +21 -0
- package/dist/dts/declarative/template-bridge.d.ts +33 -0
- package/dist/dts/declarative/template-parser.d.ts +98 -0
- package/dist/dts/declarative/template.d.ts +9 -0
- package/dist/dts/declarative/utilities.d.ts +312 -0
- package/dist/dts/di/di.d.ts +1 -1
- package/dist/dts/directives/children.d.ts +2 -0
- package/dist/dts/directives/node-observation.d.ts +2 -0
- package/dist/dts/directives/ref.d.ts +2 -0
- package/dist/dts/directives/repeat.d.ts +4 -0
- package/dist/dts/directives/slotted.d.ts +2 -0
- package/dist/dts/directives/when.d.ts +3 -0
- package/dist/dts/dom-policy.d.ts +1 -1
- package/dist/dts/html.d.ts +5 -0
- package/dist/dts/hydration/runtime.d.ts +7 -0
- package/dist/dts/hydration/target-builder.d.ts +15 -12
- package/dist/dts/hydration.d.ts +14 -0
- package/dist/dts/index.d.ts +38 -42
- package/dist/dts/index.debug.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +1 -49
- package/dist/dts/observable.d.ts +3 -6
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/update-queue.d.ts +1 -1
- package/dist/dts/platform.d.ts +25 -4
- package/dist/dts/render.d.ts +7 -0
- package/dist/dts/schema.d.ts +1 -0
- package/dist/dts/state/exports.d.ts +1 -1
- package/dist/dts/state/state.d.ts +2 -2
- package/dist/dts/styles/css-directive.d.ts +5 -12
- package/dist/dts/styles/css.d.ts +5 -7
- package/dist/dts/styles/element-styles.d.ts +0 -10
- package/dist/dts/styles.d.ts +6 -0
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/html-binding-directive.d.ts +4 -0
- package/dist/dts/templating/html-directive.d.ts +17 -0
- package/dist/dts/templating/hydration-view.d.ts +109 -0
- package/dist/dts/templating/ref.d.ts +1 -1
- package/dist/dts/templating/render.d.ts +1 -1
- package/dist/dts/templating/repeat.d.ts +2 -2
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +17 -9
- package/dist/dts/templating/view.d.ts +25 -102
- package/dist/dts/templating/when.d.ts +1 -1
- package/dist/dts/templating.d.ts +10 -0
- package/dist/dts/testing/exports.d.ts +2 -2
- package/dist/dts/updates.d.ts +1 -0
- package/dist/dts/volatile.d.ts +2 -0
- package/dist/esm/array-observer.js +1 -0
- package/dist/esm/arrays.js +1 -0
- package/dist/esm/attr.js +1 -0
- package/dist/esm/binding/normalize.js +1 -1
- package/dist/esm/binding/signal.js +4 -4
- package/dist/esm/binding/two-way.js +2 -1
- package/dist/esm/binding.js +4 -0
- package/dist/esm/components/attributes.js +8 -5
- package/dist/esm/components/definition-schema-transforms.js +23 -0
- package/dist/esm/components/element-controller.js +200 -269
- package/dist/esm/components/element-hydration.js +1 -1
- package/dist/esm/components/enable-hydration.js +100 -0
- package/dist/esm/components/fast-definitions.js +211 -49
- package/dist/esm/components/fast-element.js +18 -27
- package/dist/esm/components/hydration-tracker.js +93 -0
- package/dist/esm/components/hydration.js +62 -144
- package/dist/esm/components/schema.js +253 -0
- package/dist/esm/context.js +6 -6
- package/dist/esm/css.js +3 -0
- package/dist/esm/debug.js +26 -26
- package/dist/esm/declarative/attribute-map.js +121 -0
- package/dist/esm/declarative/debug.js +5 -0
- package/dist/esm/declarative/index.js +3 -0
- package/dist/esm/declarative/interfaces.js +10 -0
- package/dist/esm/declarative/observer-map-utilities.js +562 -0
- package/dist/esm/declarative/observer-map.js +216 -0
- package/dist/esm/declarative/runtime.js +14 -0
- package/dist/esm/declarative/syntax.js +36 -0
- package/dist/esm/declarative/template-bridge.js +170 -0
- package/dist/esm/declarative/template-parser.js +306 -0
- package/dist/esm/declarative/template.js +142 -0
- package/dist/esm/declarative/utilities.js +834 -0
- package/dist/esm/di/di.js +6 -8
- package/dist/esm/directives/children.js +1 -0
- package/dist/esm/directives/node-observation.js +1 -0
- package/dist/esm/directives/ref.js +1 -0
- package/dist/esm/directives/repeat.js +1 -0
- package/dist/esm/directives/slotted.js +1 -0
- package/dist/esm/directives/when.js +1 -0
- package/dist/esm/dom-policy.js +2 -2
- package/dist/esm/dom.js +1 -1
- package/dist/esm/html.js +2 -0
- package/dist/esm/hydration/runtime.js +33 -0
- package/dist/esm/hydration/target-builder.js +97 -90
- package/dist/esm/hydration.js +4 -0
- package/dist/esm/index.debug.js +2 -1
- package/dist/esm/index.js +34 -29
- package/dist/esm/index.rollup.debug.js +3 -2
- package/dist/esm/index.rollup.js +1 -1
- package/dist/esm/interfaces.js +1 -45
- package/dist/esm/observable.js +1 -4
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/observable.js +5 -5
- package/dist/esm/observation/update-queue.js +47 -58
- package/dist/esm/platform.js +31 -30
- package/dist/esm/render.js +1 -0
- package/dist/esm/schema.js +1 -0
- package/dist/esm/state/exports.js +1 -1
- package/dist/esm/styles/css-directive.js +1 -2
- package/dist/esm/styles/css.js +15 -56
- package/dist/esm/styles/element-styles.js +69 -15
- package/dist/esm/styles.js +2 -0
- package/dist/esm/templating/html-binding-directive.js +10 -8
- package/dist/esm/templating/hydration-view.js +235 -0
- package/dist/esm/templating/render.js +1 -1
- package/dist/esm/templating/repeat.js +36 -34
- package/dist/esm/templating/template.js +7 -7
- package/dist/esm/templating/view.js +24 -233
- package/dist/esm/templating.js +7 -0
- package/dist/esm/testing/exports.js +2 -2
- package/dist/esm/updates.js +1 -0
- package/dist/esm/volatile.js +1 -0
- package/dist/fast-element.api.json +9016 -6995
- package/dist/fast-element.d.ts +3557 -796
- package/dist/fast-element.debug.js +5088 -4437
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +5369 -4649
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +863 -475
- package/dist/hydration/hydration.api.json +5237 -0
- package/dist/styles/styles.api.json +2672 -0
- package/docs/api-report.api.md +343 -166
- package/docs/arrays/api-report.api.md +114 -0
- package/docs/declarative/api-report.api.md +397 -0
- package/docs/hydration/api-report.api.md +285 -0
- package/docs/styles/api-report.api.md +135 -0
- package/package.json +149 -41
- package/playwright.declarative.config.ts +26 -0
- package/playwright.declarative.webui.config.ts +20 -0
- package/scripts/declarative/build-fixtures-with-webui.js +135 -0
- package/scripts/declarative/build-fixtures.js +49 -0
- package/scripts/declarative/build-fixtures.utilities.js +101 -0
- package/scripts/measure-sizes.js +219 -0
- package/scripts/run-api-extractor.js +39 -20
- package/test/declarative/fixtures/README.md +72 -0
- package/test/declarative/fixtures/WRITING_FIXTURES.md +330 -0
- package/test/declarative/fixtures/bindings/README.md +12 -0
- package/test/declarative/fixtures/bindings/attribute/entry.html +13 -0
- package/test/declarative/fixtures/bindings/attribute/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/attribute/index.html +25 -0
- package/test/declarative/fixtures/bindings/attribute/main.ts +41 -0
- package/test/declarative/fixtures/bindings/attribute/state.json +8 -0
- package/test/declarative/fixtures/bindings/attribute/templates.html +11 -0
- package/test/declarative/fixtures/bindings/content/entry.html +12 -0
- package/test/declarative/fixtures/bindings/content/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/content/index.html +19 -0
- package/test/declarative/fixtures/bindings/content/main.ts +27 -0
- package/test/declarative/fixtures/bindings/content/state.json +4 -0
- package/test/declarative/fixtures/bindings/content/templates.html +6 -0
- package/test/declarative/fixtures/bindings/dot-syntax/entry.html +11 -0
- package/test/declarative/fixtures/bindings/dot-syntax/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/dot-syntax/index.html +47 -0
- package/test/declarative/fixtures/bindings/dot-syntax/main.ts +59 -0
- package/test/declarative/fixtures/bindings/dot-syntax/state.json +16 -0
- package/test/declarative/fixtures/bindings/dot-syntax/templates.html +17 -0
- package/test/declarative/fixtures/bindings/event/entry.html +11 -0
- package/test/declarative/fixtures/bindings/event/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/event/index.html +43 -0
- package/test/declarative/fixtures/bindings/event/main.ts +43 -0
- package/test/declarative/fixtures/bindings/event/state.json +3 -0
- package/test/declarative/fixtures/bindings/event/templates.html +18 -0
- package/test/declarative/fixtures/bindings/host/entry.html +40 -0
- package/test/declarative/fixtures/bindings/host/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/host/index.html +96 -0
- package/test/declarative/fixtures/bindings/host/main.ts +222 -0
- package/test/declarative/fixtures/bindings/host/state.json +9 -0
- package/test/declarative/fixtures/bindings/host/templates.html +55 -0
- package/test/declarative/fixtures/directives/README.md +12 -0
- package/test/declarative/fixtures/directives/children/entry.html +11 -0
- package/test/declarative/fixtures/directives/children/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/children/index.html +15 -0
- package/test/declarative/fixtures/directives/children/main.ts +22 -0
- package/test/declarative/fixtures/directives/children/state.json +3 -0
- package/test/declarative/fixtures/directives/children/templates.html +3 -0
- package/test/declarative/fixtures/directives/ref/entry.html +11 -0
- package/test/declarative/fixtures/directives/ref/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/ref/index.html +15 -0
- package/test/declarative/fixtures/directives/ref/main.ts +17 -0
- package/test/declarative/fixtures/directives/ref/state.json +1 -0
- package/test/declarative/fixtures/directives/ref/templates.html +3 -0
- package/test/declarative/fixtures/directives/repeat/entry.html +21 -0
- package/test/declarative/fixtures/directives/repeat/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/repeat/index.html +133 -0
- package/test/declarative/fixtures/directives/repeat/main.ts +110 -0
- package/test/declarative/fixtures/directives/repeat/sprites.svg +8 -0
- package/test/declarative/fixtures/directives/repeat/state.json +10 -0
- package/test/declarative/fixtures/directives/repeat/templates.html +75 -0
- package/test/declarative/fixtures/directives/slotted/entry.html +17 -0
- package/test/declarative/fixtures/directives/slotted/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/slotted/index.html +27 -0
- package/test/declarative/fixtures/directives/slotted/main.ts +29 -0
- package/test/declarative/fixtures/directives/slotted/state.json +1 -0
- package/test/declarative/fixtures/directives/slotted/templates.html +7 -0
- package/test/declarative/fixtures/directives/when/entry.html +51 -0
- package/test/declarative/fixtures/directives/when/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/when/index.html +136 -0
- package/test/declarative/fixtures/directives/when/main.ts +172 -0
- package/test/declarative/fixtures/directives/when/state.json +12 -0
- package/test/declarative/fixtures/directives/when/templates.html +75 -0
- package/test/declarative/fixtures/ecosystem/README.md +11 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/entry.html +12 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/index.html +20 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/main.ts +68 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/state.json +4 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/templates.html +7 -0
- package/test/declarative/fixtures/ecosystem/errors/entry.html +12 -0
- package/test/declarative/fixtures/ecosystem/errors/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/errors/index.html +20 -0
- package/test/declarative/fixtures/ecosystem/errors/main.ts +17 -0
- package/test/declarative/fixtures/ecosystem/errors/state.json +1 -0
- package/test/declarative/fixtures/ecosystem/errors/templates.html +7 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/entry.html +17 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/index.html +56 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/main.ts +134 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/state.json +12 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/templates.html +34 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/entry.html +25 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-card.css +10 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/index.html +181 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/main.ts +58 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/state.json +6 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/templates.html +15 -0
- package/test/declarative/fixtures/extensions/README.md +15 -0
- package/test/declarative/fixtures/extensions/attribute-map/entry.html +14 -0
- package/test/declarative/fixtures/extensions/attribute-map/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/attribute-map/index.html +31 -0
- package/test/declarative/fixtures/extensions/attribute-map/main.ts +40 -0
- package/test/declarative/fixtures/extensions/attribute-map/state.json +4 -0
- package/test/declarative/fixtures/extensions/attribute-map/templates.html +14 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/entry.html +12 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/fast-build.config.json +7 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/index.html +25 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/main.ts +31 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/state.json +5 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/templates.html +11 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/entry.html +13 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/fast-build.config.json +7 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/index.html +23 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/main.ts +37 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/state.json +1 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/templates.html +9 -0
- package/test/declarative/fixtures/extensions/observer-map/entry.html +15 -0
- package/test/declarative/fixtures/extensions/observer-map/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map/index.html +442 -0
- package/test/declarative/fixtures/extensions/observer-map/main.ts +482 -0
- package/test/declarative/fixtures/extensions/observer-map/state.json +158 -0
- package/test/declarative/fixtures/extensions/observer-map/templates.html +172 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/entry.html +16 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/index.html +27 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/main.ts +53 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/state.json +9 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/templates.html +12 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/README.md +98 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/entry.html +156 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/index.html +376 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/main.ts +366 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/state.json +69 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/templates.html +91 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/entry.html +14 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/index.html +110 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/main.ts +175 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/state.json +29 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/templates.html +55 -0
- package/test/declarative/fixtures/scenarios/README.md +7 -0
- package/test/declarative/fixtures/scenarios/nested-elements/entry.html +16 -0
- package/test/declarative/fixtures/scenarios/nested-elements/fast-build.config.json +6 -0
- package/test/declarative/fixtures/scenarios/nested-elements/index.html +126 -0
- package/test/declarative/fixtures/scenarios/nested-elements/main.ts +214 -0
- package/test/declarative/fixtures/scenarios/nested-elements/state.json +10 -0
- package/test/declarative/fixtures/scenarios/nested-elements/templates.html +54 -0
- package/test/declarative/index.html +12 -0
- package/test/declarative/vite.config.ts +55 -0
- package/test/declarative-main.ts +6 -0
- package/test/extension-subpaths-main.ts +9 -0
- package/test/main.ts +38 -33
- package/test/pure-declarative-main.ts +1 -0
- package/dist/dts/components/install-hydration.d.ts +0 -1
- package/dist/dts/pending-task.d.ts +0 -32
- package/dist/dts/polyfills.d.ts +0 -0
- package/dist/dts/styles/css-binding-directive.d.ts +0 -60
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
- package/dist/esm/components/install-hydration.js +0 -3
- package/dist/esm/pending-task.js +0 -28
- package/dist/esm/polyfills.js +0 -60
- package/dist/esm/styles/css-binding-directive.js +0 -76
- package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
|
@@ -0,0 +1,834 @@
|
|
|
1
|
+
import { defsPropertyName, fastContextMetaData, } from "../components/schema.js";
|
|
2
|
+
import { attributeDirectivePrefix, clientSideCloseExpression, clientSideOpenExpression, closeExpression, eventArgAccessor, executionContextAccessor, openExpression, repeatDirectiveClose, repeatDirectiveOpen, unescapedCloseExpression, unescapedOpenExpression, whenDirectiveClose, whenDirectiveOpen, } from "./syntax.js";
|
|
3
|
+
export { assignObservables, assignProxy, deepEqual, deepMerge, findDef, isPlainObject, } from "./observer-map-utilities.js";
|
|
4
|
+
/**
|
|
5
|
+
* Prefix used for execution context paths.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export const contextPrefixDot = `${executionContextAccessor}.`;
|
|
9
|
+
export { eventArgAccessor, executionContextAccessor };
|
|
10
|
+
/**
|
|
11
|
+
* Parses the arguments string of an event handler binding into an array of
|
|
12
|
+
* typed argument descriptors. Unrecognised tokens are returned as `"binding"`
|
|
13
|
+
* type with their raw string preserved.
|
|
14
|
+
*
|
|
15
|
+
* Special arguments:
|
|
16
|
+
* - `$e` — resolves to the DOM event object
|
|
17
|
+
* - `$c` — resolves to the full execution context object
|
|
18
|
+
*
|
|
19
|
+
* Any other token is treated as a binding path and resolved against the current
|
|
20
|
+
* data source.
|
|
21
|
+
*
|
|
22
|
+
* @param argsString - The raw arguments string from between the parentheses,
|
|
23
|
+
* e.g. `""`, `"$e"`, `"$c"`, or `"$e, $c"`.
|
|
24
|
+
* @returns An array of {@link ParsedEventArg} descriptors.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export function parseEventArgs(argsString) {
|
|
28
|
+
if (argsString.trim() === "")
|
|
29
|
+
return [];
|
|
30
|
+
return argsString
|
|
31
|
+
.split(",")
|
|
32
|
+
.map(arg => arg.trim())
|
|
33
|
+
.filter(arg => arg !== "")
|
|
34
|
+
.map((arg) => {
|
|
35
|
+
switch (arg) {
|
|
36
|
+
case eventArgAccessor:
|
|
37
|
+
return { type: "event" };
|
|
38
|
+
case executionContextAccessor:
|
|
39
|
+
return { type: "context" };
|
|
40
|
+
default:
|
|
41
|
+
return { type: "binding", rawArg: arg };
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const startInnerHTMLDiv = `<div :innerHTML="{{`;
|
|
46
|
+
const startInnerHTMLDivLength = startInnerHTMLDiv.length;
|
|
47
|
+
const endInnerHTMLDiv = `}}"></div>`;
|
|
48
|
+
const endInnerHTMLDivLength = endInnerHTMLDiv.length;
|
|
49
|
+
/**
|
|
50
|
+
* Logical operator tokens.
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export const LogicalOperator = {
|
|
54
|
+
AND: "&&",
|
|
55
|
+
OR: "||",
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Comparison operator tokens.
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export const ComparisonOperator = {
|
|
62
|
+
ACCESS: "access",
|
|
63
|
+
EQUALS: "==",
|
|
64
|
+
GREATER_THAN: ">",
|
|
65
|
+
GREATER_THAN_OR_EQUALS: ">=",
|
|
66
|
+
LESS_THAN: "<",
|
|
67
|
+
LESS_THAN_OR_EQUALS: "<=",
|
|
68
|
+
NOT: "!",
|
|
69
|
+
NOT_EQUALS: "!=",
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Declarative expression operator tokens.
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export const Operator = Object.assign(Object.assign({}, LogicalOperator), ComparisonOperator);
|
|
76
|
+
/**
|
|
77
|
+
* Get the index of the next matching tag
|
|
78
|
+
* @param openingTagStartSlice - The slice starting from the opening tag
|
|
79
|
+
* @param openingTag - The opening tag string
|
|
80
|
+
* @param closingTag - The closing tag
|
|
81
|
+
* @param openingTagStartIndex - The opening tag start index derived from the innerHTML
|
|
82
|
+
* @returns index
|
|
83
|
+
* @public
|
|
84
|
+
*/
|
|
85
|
+
export function getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) {
|
|
86
|
+
let tagCount = 1;
|
|
87
|
+
let matchingCloseTagIndex = -1;
|
|
88
|
+
const openingTagLength = openingTag.length;
|
|
89
|
+
const closingTagLength = closingTag.length;
|
|
90
|
+
let nextSlice = openingTagStartSlice.slice(openingTagLength);
|
|
91
|
+
let nextOpenTag = nextSlice.indexOf(openingTag);
|
|
92
|
+
let nextCloseTag = nextSlice.indexOf(closingTag);
|
|
93
|
+
let tagOffset = openingTagStartIndex + openingTagLength;
|
|
94
|
+
do {
|
|
95
|
+
// if a closing tag has been found for the last open tag, decrement the tag count
|
|
96
|
+
if (nextOpenTag > nextCloseTag || nextOpenTag === -1) {
|
|
97
|
+
tagCount--;
|
|
98
|
+
if (tagCount === 0) {
|
|
99
|
+
matchingCloseTagIndex = nextCloseTag + tagOffset;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
tagOffset += nextCloseTag + closingTagLength;
|
|
103
|
+
nextSlice = nextSlice.slice(nextCloseTag + closingTagLength);
|
|
104
|
+
nextOpenTag = nextSlice.indexOf(openingTag);
|
|
105
|
+
nextCloseTag = nextSlice.indexOf(closingTag);
|
|
106
|
+
}
|
|
107
|
+
else if (nextOpenTag !== -1) {
|
|
108
|
+
tagCount++;
|
|
109
|
+
tagOffset += nextOpenTag + openingTagLength;
|
|
110
|
+
nextSlice = nextSlice.slice(nextOpenTag + openingTagLength);
|
|
111
|
+
nextOpenTag = nextSlice.indexOf(openingTag);
|
|
112
|
+
nextCloseTag = nextSlice.indexOf(closingTag);
|
|
113
|
+
}
|
|
114
|
+
if (tagCount === 0) {
|
|
115
|
+
matchingCloseTagIndex = nextCloseTag + tagOffset;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
} while (tagCount > 0);
|
|
119
|
+
return matchingCloseTagIndex;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the next directive
|
|
123
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
124
|
+
* @returns DirectiveBehaviorConfig - A configuration object
|
|
125
|
+
*/
|
|
126
|
+
function getNextDirectiveBehavior(innerHTML) {
|
|
127
|
+
const whenIndex = innerHTML.indexOf(whenDirectiveOpen);
|
|
128
|
+
const repeatIndex = innerHTML.indexOf(repeatDirectiveOpen);
|
|
129
|
+
const isWhen = whenIndex !== -1 && (repeatIndex === -1 || whenIndex < repeatIndex);
|
|
130
|
+
let openingTag = repeatDirectiveOpen;
|
|
131
|
+
let closingTag = repeatDirectiveClose;
|
|
132
|
+
let directiveTag = "repeat";
|
|
133
|
+
let openingTagStartIndex = repeatIndex;
|
|
134
|
+
if (isWhen) {
|
|
135
|
+
openingTag = whenDirectiveOpen;
|
|
136
|
+
closingTag = whenDirectiveClose;
|
|
137
|
+
directiveTag = "when";
|
|
138
|
+
openingTagStartIndex = whenIndex;
|
|
139
|
+
}
|
|
140
|
+
const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
|
|
141
|
+
const openingTagEndIndex = // account for f-when which may include >= or > as operators, but will always include a condition attr
|
|
142
|
+
openingTagStartSlice.indexOf(`">`) + openingTagStartIndex + 2;
|
|
143
|
+
const directiveValue = getNextDataBindingBehavior(innerHTML);
|
|
144
|
+
const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex);
|
|
145
|
+
return {
|
|
146
|
+
type: "templateDirective",
|
|
147
|
+
name: directiveTag,
|
|
148
|
+
value: innerHTML.slice(directiveValue.openingEndIndex, directiveValue.closingStartIndex),
|
|
149
|
+
openingTagStartIndex,
|
|
150
|
+
openingTagEndIndex,
|
|
151
|
+
closingTagStartIndex: matchingCloseTagIndex,
|
|
152
|
+
closingTagEndIndex: matchingCloseTagIndex + closingTag.length,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Determine if this binding is an attribute binding
|
|
157
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
158
|
+
* @param openingStartIndex - The index of the binding opening marker
|
|
159
|
+
* @returns boolean
|
|
160
|
+
*/
|
|
161
|
+
function isAttribute(innerHTML, openingStartIndex) {
|
|
162
|
+
return innerHTML.slice(openingStartIndex - 2, openingStartIndex - 1) === "=";
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Determine if this binding is an attribute directive binding
|
|
166
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
167
|
+
* @param openingStartIndex - The index of the binding opening marker
|
|
168
|
+
* @returns boolean
|
|
169
|
+
*/
|
|
170
|
+
function isAttributeDirective(innerHTML, openingStartIndex) {
|
|
171
|
+
const splitHTML = innerHTML.slice(0, openingStartIndex - 2).split(" ");
|
|
172
|
+
return splitHTML[splitHTML.length - 1].startsWith(attributeDirectivePrefix);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the attribute binding config
|
|
176
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
177
|
+
* @param config - The base configuration of the binding
|
|
178
|
+
* @returns AttributeDataBindingBehaviorConfig
|
|
179
|
+
*/
|
|
180
|
+
function getAttributeDataBindingConfig(innerHTML, config) {
|
|
181
|
+
const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
|
|
182
|
+
const firstCharOfAttribute = splitInnerHTML[splitInnerHTML.length - 1][0];
|
|
183
|
+
const aspect = firstCharOfAttribute === "?" ||
|
|
184
|
+
firstCharOfAttribute === "@" ||
|
|
185
|
+
firstCharOfAttribute === ":"
|
|
186
|
+
? firstCharOfAttribute
|
|
187
|
+
: null;
|
|
188
|
+
return Object.assign(Object.assign({}, config), { subtype: "attribute", aspect });
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get the attribute directive binding config
|
|
192
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
193
|
+
* @param config - The base configuration of the binding
|
|
194
|
+
* @returns AttributeDirectiveBindingBehaviorConfig
|
|
195
|
+
*/
|
|
196
|
+
function getAttributeDirectiveDataBindingConfig(innerHTML, config) {
|
|
197
|
+
const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
|
|
198
|
+
const lastItem = splitInnerHTML[splitInnerHTML.length - 1];
|
|
199
|
+
const equals = lastItem.indexOf("=");
|
|
200
|
+
const name = lastItem.slice(2, equals);
|
|
201
|
+
return Object.assign(Object.assign({}, config), { subtype: "attributeDirective", name: name });
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get the content data binding config
|
|
205
|
+
* @param config - The base configuration of the binding
|
|
206
|
+
* @returns ContentDataBindingBehaviorConfig
|
|
207
|
+
*/
|
|
208
|
+
function getContentDataBindingConfig(config) {
|
|
209
|
+
return Object.assign(Object.assign({}, config), { subtype: "content" });
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Finds the next data binding in innerHTML and determines its type and indices
|
|
213
|
+
* @param innerHTML - The innerHTML string to search for data bindings
|
|
214
|
+
* @returns NextDataBindingBehaviorConfig containing the binding type and start indices
|
|
215
|
+
*/
|
|
216
|
+
function getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML) {
|
|
217
|
+
// {{{}}} binding
|
|
218
|
+
const openingUnescapedStartIndex = innerHTML.indexOf(unescapedOpenExpression);
|
|
219
|
+
const closingUnescapedStartIndex = innerHTML.indexOf(unescapedCloseExpression);
|
|
220
|
+
// {{}} binding
|
|
221
|
+
const openingContentStartIndex = innerHTML.indexOf(openExpression);
|
|
222
|
+
const closingContentStartIndex = innerHTML.indexOf(closeExpression);
|
|
223
|
+
// {} binding
|
|
224
|
+
const openingClientStartIndex = innerHTML.indexOf(clientSideOpenExpression);
|
|
225
|
+
const closingClientStartIndex = innerHTML.indexOf(clientSideCloseExpression);
|
|
226
|
+
if (openingUnescapedStartIndex !== -1 &&
|
|
227
|
+
openingUnescapedStartIndex <= openingContentStartIndex &&
|
|
228
|
+
openingUnescapedStartIndex <= openingClientStartIndex) {
|
|
229
|
+
// is unescaped {{{}}}
|
|
230
|
+
return {
|
|
231
|
+
openingStartIndex: openingUnescapedStartIndex,
|
|
232
|
+
closingStartIndex: closingUnescapedStartIndex,
|
|
233
|
+
bindingType: "unescaped",
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
else if (openingContentStartIndex !== -1 &&
|
|
237
|
+
openingContentStartIndex <= openingClientStartIndex) {
|
|
238
|
+
// is default {{}}
|
|
239
|
+
return {
|
|
240
|
+
openingStartIndex: openingContentStartIndex,
|
|
241
|
+
closingStartIndex: closingContentStartIndex,
|
|
242
|
+
bindingType: "default",
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// is client {}
|
|
246
|
+
return {
|
|
247
|
+
openingStartIndex: openingClientStartIndex,
|
|
248
|
+
closingStartIndex: closingClientStartIndex,
|
|
249
|
+
bindingType: "client",
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get the next data binding
|
|
254
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
255
|
+
* @returns DataBindingBehaviorConfig - A configuration object
|
|
256
|
+
*/
|
|
257
|
+
function getNextDataBindingBehavior(innerHTML) {
|
|
258
|
+
const { openingStartIndex, closingStartIndex, bindingType } = getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML);
|
|
259
|
+
const bindingLength = bindingType === "client" ? 1 : bindingType === "default" ? 2 : 3;
|
|
260
|
+
const partialConfig = {
|
|
261
|
+
type: "dataBinding",
|
|
262
|
+
bindingType,
|
|
263
|
+
openingStartIndex,
|
|
264
|
+
openingEndIndex: openingStartIndex + bindingLength,
|
|
265
|
+
closingStartIndex,
|
|
266
|
+
closingEndIndex: closingStartIndex + bindingLength,
|
|
267
|
+
};
|
|
268
|
+
return isAttributeDirective(innerHTML, openingStartIndex)
|
|
269
|
+
? getAttributeDirectiveDataBindingConfig(innerHTML, partialConfig)
|
|
270
|
+
: isAttribute(innerHTML, openingStartIndex)
|
|
271
|
+
? getAttributeDataBindingConfig(innerHTML, partialConfig)
|
|
272
|
+
: getContentDataBindingConfig(partialConfig);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get the next behavior
|
|
276
|
+
* @param innerHTML - The innerHTML string to evaluate
|
|
277
|
+
* @param offset - The current offset in the original string.
|
|
278
|
+
* @returns DataBindingBehaviorConfig | DirectiveBehaviorConfig | null - A configuration object or null
|
|
279
|
+
* @public
|
|
280
|
+
*/
|
|
281
|
+
export function getNextBehavior(innerHTML, offset = 0) {
|
|
282
|
+
// eslint-disable-next-line no-constant-condition
|
|
283
|
+
while (true) {
|
|
284
|
+
const currentSlice = innerHTML.slice(offset);
|
|
285
|
+
// client side binding will capture all bindings starting with "{"
|
|
286
|
+
const dataBindingOpen = currentSlice.indexOf(clientSideOpenExpression);
|
|
287
|
+
const whenDirectiveIndex = currentSlice.indexOf(whenDirectiveOpen);
|
|
288
|
+
const repeatDirectiveIndex = currentSlice.indexOf(repeatDirectiveOpen);
|
|
289
|
+
const directiveBindingOpen = whenDirectiveIndex === -1
|
|
290
|
+
? repeatDirectiveIndex
|
|
291
|
+
: repeatDirectiveIndex === -1
|
|
292
|
+
? whenDirectiveIndex
|
|
293
|
+
: Math.min(whenDirectiveIndex, repeatDirectiveIndex);
|
|
294
|
+
const nextDataBindingBehavior = getNextDataBindingBehavior(currentSlice);
|
|
295
|
+
if (dataBindingOpen === -1 && directiveBindingOpen === -1) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
if (dataBindingOpen !== -1 &&
|
|
299
|
+
nextDataBindingBehavior.bindingType === "client" &&
|
|
300
|
+
!isLegitimateClientSideBinding(nextDataBindingBehavior)) {
|
|
301
|
+
offset = nextDataBindingBehavior.closingEndIndex + offset;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (directiveBindingOpen !== -1 &&
|
|
305
|
+
(dataBindingOpen === -1 || dataBindingOpen > directiveBindingOpen)) {
|
|
306
|
+
return offsetDirective(getNextDirectiveBehavior(currentSlice), offset);
|
|
307
|
+
}
|
|
308
|
+
return offsetDataBinding(nextDataBindingBehavior, offset);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Apply an offset to a data binding
|
|
313
|
+
* @param config DataBindingBehaviorConfig
|
|
314
|
+
* @param offset number
|
|
315
|
+
* @returns DataBindingBehaviorConfig
|
|
316
|
+
*/
|
|
317
|
+
function offsetDataBinding(config, offset) {
|
|
318
|
+
config.openingStartIndex = config.openingStartIndex + offset;
|
|
319
|
+
config.openingEndIndex = config.openingEndIndex + offset;
|
|
320
|
+
config.closingStartIndex = config.closingStartIndex + offset;
|
|
321
|
+
config.closingEndIndex = config.closingEndIndex + offset;
|
|
322
|
+
return config;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Apply an offset to a directive
|
|
326
|
+
* @param config TemplateDirectiveBehaviorConfig
|
|
327
|
+
* @param offset number
|
|
328
|
+
* @returns TemplateDirectiveBehaviorConfig
|
|
329
|
+
*/
|
|
330
|
+
function offsetDirective(config, offset) {
|
|
331
|
+
config.openingTagStartIndex = config.openingTagStartIndex + offset;
|
|
332
|
+
config.openingTagEndIndex = config.openingTagEndIndex + offset;
|
|
333
|
+
config.closingTagStartIndex = config.closingTagStartIndex + offset;
|
|
334
|
+
config.closingTagEndIndex = config.closingTagEndIndex + offset;
|
|
335
|
+
return config;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Determine if this client side binding is legitimate.
|
|
339
|
+
* Single-brace (client) bindings are only valid for events, properties, and attribute directives.
|
|
340
|
+
* Checking for this prevents CSS/JS curly braces from being misinterpreted as bindings.
|
|
341
|
+
* @param result
|
|
342
|
+
* @returns
|
|
343
|
+
*/
|
|
344
|
+
function isLegitimateClientSideBinding(result) {
|
|
345
|
+
return ((result.subtype === "attribute" &&
|
|
346
|
+
(result.aspect === "@" || result.aspect === ":")) ||
|
|
347
|
+
result.subtype === "attributeDirective");
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Create a function to resolve a value from an object using a path with dot syntax.
|
|
351
|
+
* e.g. "foo.bar"
|
|
352
|
+
* @param path - The dot syntax path to an objects property.
|
|
353
|
+
* @param contextPath - The current repeat context path.
|
|
354
|
+
* @param level - The current repeat nesting level.
|
|
355
|
+
* @param rootSchema - The root schema for resolving context paths.
|
|
356
|
+
* @returns A function to access the value from a given path.
|
|
357
|
+
* @public
|
|
358
|
+
*/
|
|
359
|
+
export function pathResolver(path, contextPath, level, rootSchema) {
|
|
360
|
+
var _a, _b;
|
|
361
|
+
let splitPath = path.split(".");
|
|
362
|
+
// Explicit context access via executionContextAccessor — resolve directly from ExecutionContext
|
|
363
|
+
if (splitPath[0] === executionContextAccessor) {
|
|
364
|
+
const contextAccessPath = splitPath.slice(1);
|
|
365
|
+
return (_accessibleObject, context) => {
|
|
366
|
+
return contextAccessPath.reduce((prev, item) => prev === null || prev === void 0 ? void 0 : prev[item], context);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
let levelCount = level;
|
|
370
|
+
let self = splitPath[0] === contextPath;
|
|
371
|
+
const parentContexts = [];
|
|
372
|
+
if (level > 0 &&
|
|
373
|
+
((_b = (_a = rootSchema === null || rootSchema === void 0 ? void 0 : rootSchema[defsPropertyName]) === null || _a === void 0 ? void 0 : _a[contextPath]) === null || _b === void 0 ? void 0 : _b[fastContextMetaData]) ===
|
|
374
|
+
splitPath[splitPath.length - 1]) {
|
|
375
|
+
self = true;
|
|
376
|
+
}
|
|
377
|
+
while (levelCount > 0 && !self) {
|
|
378
|
+
if (levelCount !== 1) {
|
|
379
|
+
parentContexts.push("parentContext");
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
parentContexts.push("parent");
|
|
383
|
+
}
|
|
384
|
+
levelCount--;
|
|
385
|
+
}
|
|
386
|
+
splitPath = [...parentContexts, ...splitPath];
|
|
387
|
+
return pathWithContextResolver(splitPath, self);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Creates a resolver function that can access properties from an object using a split path array
|
|
391
|
+
* @param splitPath - The dot syntax path split into an array of property names
|
|
392
|
+
* @param self - Whether the first item in the path refers to the item itself
|
|
393
|
+
* @returns A function that resolves the value from the given path on an accessible object
|
|
394
|
+
*/
|
|
395
|
+
function pathWithContextResolver(splitPath, self) {
|
|
396
|
+
const isInPreviousContext = splitPath[0] === "parent" || splitPath[0] === "parentContext";
|
|
397
|
+
if (self && !isInPreviousContext) {
|
|
398
|
+
if (splitPath.length > 1) {
|
|
399
|
+
splitPath = splitPath.slice(1);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
return (accessibleObject) => {
|
|
403
|
+
return accessibleObject;
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (isInPreviousContext) {
|
|
408
|
+
return (accessibleObject, context) => {
|
|
409
|
+
return splitPath.reduce((previousAccessors, pathItem) => {
|
|
410
|
+
return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
|
|
411
|
+
}, context);
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
return (accessibleObject) => {
|
|
415
|
+
return splitPath.reduce((previousAccessors, pathItem) => {
|
|
416
|
+
return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
|
|
417
|
+
}, accessibleObject);
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Creates a binding resolver and records the binding path in the schema.
|
|
422
|
+
* @param previousString - The previous literal string before the binding.
|
|
423
|
+
* @param rootPropertyName - The current root property name.
|
|
424
|
+
* @param path - The binding path to resolve.
|
|
425
|
+
* @param parentContext - The parent repeat context.
|
|
426
|
+
* @param type - The schema path type.
|
|
427
|
+
* @param schema - The schema to record paths in.
|
|
428
|
+
* @param currentContext - The current repeat context.
|
|
429
|
+
* @param level - The current repeat nesting level.
|
|
430
|
+
* @returns A function that resolves the binding path.
|
|
431
|
+
* @public
|
|
432
|
+
*/
|
|
433
|
+
export function bindingResolver(previousString, rootPropertyName, path, parentContext, type, schema, currentContext, level) {
|
|
434
|
+
// Explicit context access — resolve from ExecutionContext, skip schema tracking
|
|
435
|
+
if (path.startsWith(contextPrefixDot)) {
|
|
436
|
+
const segments = path.split(".").slice(1);
|
|
437
|
+
return (_x, context) => {
|
|
438
|
+
return segments.reduce((prev, item) => prev === null || prev === void 0 ? void 0 : prev[item], context);
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
rootPropertyName = getRootPropertyName(rootPropertyName, path, currentContext, type);
|
|
442
|
+
if (type !== "event" && rootPropertyName !== null) {
|
|
443
|
+
const childrenMap = getChildrenMap(previousString);
|
|
444
|
+
schema.addPath({
|
|
445
|
+
pathConfig: {
|
|
446
|
+
type,
|
|
447
|
+
currentContext,
|
|
448
|
+
parentContext,
|
|
449
|
+
path,
|
|
450
|
+
},
|
|
451
|
+
rootPropertyName,
|
|
452
|
+
childrenMap,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
return pathResolver(path, currentContext, level, schema.getSchema(rootPropertyName));
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Creates a resolver for a chained expression and records its paths in the schema.
|
|
459
|
+
* @param rootPropertyName - The current root property name.
|
|
460
|
+
* @param expression - The expression to resolve.
|
|
461
|
+
* @param parentContext - The parent repeat context.
|
|
462
|
+
* @param level - The current repeat nesting level.
|
|
463
|
+
* @param schema - The schema to record paths in.
|
|
464
|
+
* @returns A function that resolves the expression.
|
|
465
|
+
* @public
|
|
466
|
+
*/
|
|
467
|
+
export function expressionResolver(rootPropertyName, expression, parentContext, level, schema) {
|
|
468
|
+
// Extract all paths from the expression and add them to the schema
|
|
469
|
+
if (rootPropertyName !== null) {
|
|
470
|
+
const paths = extractPathsFromChainedExpression(expression);
|
|
471
|
+
paths.forEach(path => {
|
|
472
|
+
if (path.startsWith(contextPrefixDot))
|
|
473
|
+
return;
|
|
474
|
+
schema.addPath({
|
|
475
|
+
pathConfig: {
|
|
476
|
+
type: "access",
|
|
477
|
+
currentContext: parentContext,
|
|
478
|
+
parentContext: null,
|
|
479
|
+
path,
|
|
480
|
+
},
|
|
481
|
+
rootPropertyName,
|
|
482
|
+
childrenMap: null,
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
return (x, c) => resolveChainedExpression(x, c, level, parentContext || null, expression, schema.getSchema(rootPropertyName));
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Extracts all paths from a ChainedExpression, including nested expressions
|
|
490
|
+
* @param chainedExpression - The chained expression to extract paths from
|
|
491
|
+
* @returns A Set containing all unique paths found in the expression chain
|
|
492
|
+
* @public
|
|
493
|
+
*/
|
|
494
|
+
export function extractPathsFromChainedExpression(chainedExpression) {
|
|
495
|
+
const paths = new Set();
|
|
496
|
+
function processExpression(expr) {
|
|
497
|
+
// Check left operand (only add if it's not a literal value)
|
|
498
|
+
if (typeof expr.left === "string" && !expr.leftIsValue) {
|
|
499
|
+
paths.add(expr.left);
|
|
500
|
+
}
|
|
501
|
+
// Check right operand (only add if it's not a literal value)
|
|
502
|
+
if (typeof expr.right === "string" && !expr.rightIsValue) {
|
|
503
|
+
paths.add(expr.right);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
let current = chainedExpression;
|
|
507
|
+
while (current !== undefined) {
|
|
508
|
+
processExpression(current.expression);
|
|
509
|
+
current = current.next;
|
|
510
|
+
}
|
|
511
|
+
return paths;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Determine if the operand is a value (boolean, number, string) or an accessor.
|
|
515
|
+
* @param operand - The string to evaluate as either a literal value or property accessor
|
|
516
|
+
* @returns An object containing the parsed value and whether it represents a literal value
|
|
517
|
+
*/
|
|
518
|
+
function isOperandValue(operand) {
|
|
519
|
+
try {
|
|
520
|
+
operand = operand.replace(/'/g, '"');
|
|
521
|
+
const value = JSON.parse(operand);
|
|
522
|
+
return {
|
|
523
|
+
value,
|
|
524
|
+
isValue: true,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
catch (_a) {
|
|
528
|
+
return {
|
|
529
|
+
value: operand,
|
|
530
|
+
isValue: false,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Evaluates parts of an expression chain and chains them with the specified operator
|
|
536
|
+
* @param parts - Each part of an expression chain to be evaluated
|
|
537
|
+
* @param operator - The logical operator used to chain the expression parts
|
|
538
|
+
* @returns A ChainedExpression object representing the linked expressions, or void if no valid expressions found
|
|
539
|
+
*/
|
|
540
|
+
function evaluatePartsInExpressionChain(parts, operator) {
|
|
541
|
+
// Process each part recursively and chain them with ||
|
|
542
|
+
const firstPart = getExpressionChain(parts[0]);
|
|
543
|
+
if (firstPart) {
|
|
544
|
+
let current = firstPart;
|
|
545
|
+
for (let i = 1; i < parts.length; i++) {
|
|
546
|
+
const nextPart = getExpressionChain(parts[i]);
|
|
547
|
+
if (nextPart) {
|
|
548
|
+
// Find the end of the current chain
|
|
549
|
+
while (current.next) {
|
|
550
|
+
current = current.next;
|
|
551
|
+
}
|
|
552
|
+
current.next = Object.assign({ operator }, nextPart);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return firstPart;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Gets the expression chain as a configuration object
|
|
560
|
+
* @param value - The binding string value
|
|
561
|
+
* @returns - A configuration object containing information about the expression
|
|
562
|
+
* @public
|
|
563
|
+
*/
|
|
564
|
+
export function getExpressionChain(value) {
|
|
565
|
+
// Decode HTML entities in the expression value first
|
|
566
|
+
const decodedValue = decodeExpressionOperators(value);
|
|
567
|
+
// Handle operator precedence: || has lower precedence than &&
|
|
568
|
+
// First, split by || (lowest precedence)
|
|
569
|
+
const orParts = decodedValue.split(/\s*\|\|\s*/);
|
|
570
|
+
if (orParts.length > 1) {
|
|
571
|
+
const firstPart = evaluatePartsInExpressionChain(orParts, Operator.OR);
|
|
572
|
+
if (firstPart) {
|
|
573
|
+
return firstPart;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// If no ||, check for && (higher precedence)
|
|
577
|
+
const andParts = decodedValue.split(/\s*&&\s*/);
|
|
578
|
+
if (andParts.length > 1) {
|
|
579
|
+
// Process each part recursively and chain them with &&
|
|
580
|
+
const firstPart = evaluatePartsInExpressionChain(andParts, "&&");
|
|
581
|
+
if (firstPart) {
|
|
582
|
+
return firstPart;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
// No chaining operators found, create a single expression
|
|
586
|
+
if (decodedValue.trim()) {
|
|
587
|
+
return {
|
|
588
|
+
expression: getExpression(decodedValue.trim()),
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
return void 0;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Parses a binding value string into an Expression object
|
|
595
|
+
* @param value - The binding string value to parse (e.g., "!condition", "foo == bar", "property")
|
|
596
|
+
* @returns An Expression object containing the operator, operands, and whether operands are literal values
|
|
597
|
+
*/
|
|
598
|
+
function getExpression(value) {
|
|
599
|
+
if (value[0] === Operator.NOT) {
|
|
600
|
+
const left = value.slice(1);
|
|
601
|
+
const operandValue = isOperandValue(left);
|
|
602
|
+
return {
|
|
603
|
+
operator: Operator.NOT,
|
|
604
|
+
left,
|
|
605
|
+
leftIsValue: operandValue.isValue,
|
|
606
|
+
right: null,
|
|
607
|
+
rightIsValue: null,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const split = value.split(/\s*([=!]=|[><]=?)\s*/);
|
|
611
|
+
if (split.length === 3) {
|
|
612
|
+
const operator = split[1];
|
|
613
|
+
const right = split[2];
|
|
614
|
+
const rightOperandValue = isOperandValue(right);
|
|
615
|
+
const left = split[0];
|
|
616
|
+
const leftOperandValue = isOperandValue(left);
|
|
617
|
+
return {
|
|
618
|
+
operator,
|
|
619
|
+
left: split[0],
|
|
620
|
+
leftIsValue: leftOperandValue.isValue,
|
|
621
|
+
right: rightOperandValue.isValue ? rightOperandValue.value : right,
|
|
622
|
+
rightIsValue: rightOperandValue.isValue,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
operator: Operator.ACCESS,
|
|
627
|
+
left: value,
|
|
628
|
+
leftIsValue: false,
|
|
629
|
+
right: null,
|
|
630
|
+
rightIsValue: null,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Decodes HTML entities within expression strings only (for operators like &&, <, >)
|
|
635
|
+
* This is safer than decoding the entire template as it preserves HTML-encoded content
|
|
636
|
+
* and only decodes operators needed for expression evaluation
|
|
637
|
+
* @param expression - The expression string to decode
|
|
638
|
+
* @returns The expression with operators decoded
|
|
639
|
+
*/
|
|
640
|
+
function decodeExpressionOperators(expression) {
|
|
641
|
+
return expression
|
|
642
|
+
.replace(/&&/g, Operator.AND)
|
|
643
|
+
.replace(/</g, Operator.LESS_THAN)
|
|
644
|
+
.replace(/>/g, Operator.GREATER_THAN);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Resolve a single expression by evaluating its operator and operands
|
|
648
|
+
* @param x - The current data context
|
|
649
|
+
* @param c - The parent context for accessing parent scope data
|
|
650
|
+
* @param level - The nesting level for context resolution
|
|
651
|
+
* @param contextPath - The current context path for property resolution
|
|
652
|
+
* @param expression - The expression object to evaluate
|
|
653
|
+
* @param rootSchema - The root JSON schema for data validation and navigation
|
|
654
|
+
* @returns The resolved value of the expression
|
|
655
|
+
*/
|
|
656
|
+
function resolveExpression(x, c, level, contextPath, expression, rootSchema) {
|
|
657
|
+
const { operator, left, right, rightIsValue } = expression;
|
|
658
|
+
const resolvedLeft = pathResolver(left, contextPath, level, rootSchema)(x, c);
|
|
659
|
+
let resolvedRight = right;
|
|
660
|
+
if (!rightIsValue && typeof right === "string") {
|
|
661
|
+
resolvedRight = pathResolver(right, contextPath, level, rootSchema)(x, c);
|
|
662
|
+
}
|
|
663
|
+
switch (operator) {
|
|
664
|
+
case Operator.NOT: {
|
|
665
|
+
return !resolvedLeft;
|
|
666
|
+
}
|
|
667
|
+
case Operator.EQUALS: {
|
|
668
|
+
// biome-ignore lint/suspicious/noDoubleEquals: Breaks prior existing functionality - see when fixture
|
|
669
|
+
return resolvedLeft == resolvedRight;
|
|
670
|
+
}
|
|
671
|
+
case Operator.NOT_EQUALS: {
|
|
672
|
+
// biome-ignore lint/suspicious/noDoubleEquals: Breaks prior existing functionality - see when fixture
|
|
673
|
+
return resolvedLeft != resolvedRight;
|
|
674
|
+
}
|
|
675
|
+
case Operator.GREATER_THAN_OR_EQUALS: {
|
|
676
|
+
return resolvedLeft >= resolvedRight;
|
|
677
|
+
}
|
|
678
|
+
case Operator.GREATER_THAN: {
|
|
679
|
+
return resolvedLeft > resolvedRight;
|
|
680
|
+
}
|
|
681
|
+
case Operator.LESS_THAN_OR_EQUALS: {
|
|
682
|
+
return resolvedLeft <= resolvedRight;
|
|
683
|
+
}
|
|
684
|
+
case Operator.LESS_THAN: {
|
|
685
|
+
return resolvedLeft < resolvedRight;
|
|
686
|
+
}
|
|
687
|
+
default: {
|
|
688
|
+
if (typeof resolvedLeft === "boolean") {
|
|
689
|
+
return resolvedLeft;
|
|
690
|
+
}
|
|
691
|
+
if (typeof resolvedLeft === "number") {
|
|
692
|
+
return resolvedLeft !== 0;
|
|
693
|
+
}
|
|
694
|
+
if (typeof resolvedLeft === "string") {
|
|
695
|
+
return resolvedLeft.length > 0;
|
|
696
|
+
}
|
|
697
|
+
return !!resolvedLeft;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Resolve a chained expression by evaluating expressions linked with logical operators
|
|
703
|
+
* @param x - The current data context
|
|
704
|
+
* @param c - The parent context for accessing parent scope data
|
|
705
|
+
* @param level - The nesting level for context resolution
|
|
706
|
+
* @param contextPath - The current context path for property resolution
|
|
707
|
+
* @param expression - The chained expression object containing linked expressions
|
|
708
|
+
* @param rootSchema - The root JSON schema for data validation and navigation
|
|
709
|
+
* @returns The resolved boolean result of the chained expression
|
|
710
|
+
*/
|
|
711
|
+
function resolveChainedExpression(x, c, level, contextPath, expression, rootSchema) {
|
|
712
|
+
const { expression: expr, next } = expression;
|
|
713
|
+
const resolvedLeft = resolveExpression(x, c, level, contextPath, expr, rootSchema);
|
|
714
|
+
if (next) {
|
|
715
|
+
const resolvedRight = resolveChainedExpression(x, c, level, contextPath, next, rootSchema);
|
|
716
|
+
switch (next.operator) {
|
|
717
|
+
case Operator.AND: {
|
|
718
|
+
return resolvedLeft && resolvedRight;
|
|
719
|
+
}
|
|
720
|
+
case Operator.OR: {
|
|
721
|
+
return resolvedLeft || resolvedRight;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return resolvedLeft;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* This is the transform utility for rationalizing declarative HTML syntax
|
|
729
|
+
* with bindings in the ViewTemplate
|
|
730
|
+
* @param innerHTML - The innerHTML to transform.
|
|
731
|
+
* @param index - The index to start the current slice of HTML to evaluate.
|
|
732
|
+
* @public
|
|
733
|
+
*/
|
|
734
|
+
export function transformInnerHTML(innerHTML, index = 0) {
|
|
735
|
+
const sliceToEvaluate = innerHTML.slice(index);
|
|
736
|
+
const nextBinding = getNextBehavior(sliceToEvaluate);
|
|
737
|
+
let transformedInnerHTML = innerHTML;
|
|
738
|
+
if (nextBinding && nextBinding.type === "dataBinding") {
|
|
739
|
+
if (nextBinding.bindingType === "unescaped") {
|
|
740
|
+
transformedInnerHTML = `${innerHTML.slice(0, index)}${sliceToEvaluate.slice(0, nextBinding.openingStartIndex)}${startInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.openingStartIndex + 3, nextBinding.closingStartIndex)}${endInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.closingStartIndex + 3)}`;
|
|
741
|
+
return transformInnerHTML(transformedInnerHTML, index +
|
|
742
|
+
startInnerHTMLDivLength +
|
|
743
|
+
endInnerHTMLDivLength +
|
|
744
|
+
nextBinding.closingStartIndex -
|
|
745
|
+
3);
|
|
746
|
+
}
|
|
747
|
+
else if (nextBinding.bindingType === "client") {
|
|
748
|
+
return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
|
|
749
|
+
}
|
|
750
|
+
return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
|
|
751
|
+
}
|
|
752
|
+
else if (nextBinding) {
|
|
753
|
+
return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingTagEndIndex);
|
|
754
|
+
}
|
|
755
|
+
return transformedInnerHTML;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Resolves boolean logic
|
|
759
|
+
* used for f-when and boolean attributes
|
|
760
|
+
* @param rootPropertyName - The current root property name.
|
|
761
|
+
* @param expression - The chained expression to resolve.
|
|
762
|
+
* @param parentContext - The parent repeat context.
|
|
763
|
+
* @param level - The current repeat nesting level.
|
|
764
|
+
* @param schema - The schema to record paths in.
|
|
765
|
+
* @returns - A binding that resolves the chained expression logic
|
|
766
|
+
* @public
|
|
767
|
+
*/
|
|
768
|
+
export function getBooleanBinding(rootPropertyName, expression, parentContext, level, schema) {
|
|
769
|
+
const binding = expressionResolver(rootPropertyName, expression, parentContext, level, schema);
|
|
770
|
+
return (x, c) => binding(x, c);
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Get the root property name
|
|
774
|
+
* @param rootPropertyName - The root property
|
|
775
|
+
* @param path - The dot syntax path
|
|
776
|
+
* @param context - The context created by a repeat
|
|
777
|
+
* @param type - The type of path binding
|
|
778
|
+
* @returns
|
|
779
|
+
* @public
|
|
780
|
+
*/
|
|
781
|
+
export function getRootPropertyName(rootPropertyName, path, context, type) {
|
|
782
|
+
return (rootPropertyName === null || context === null) && type !== "event"
|
|
783
|
+
? path.split(".")[0]
|
|
784
|
+
: rootPropertyName;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Get details of bindings to the attributes of child custom elements
|
|
788
|
+
* @param previousString - The previous string before the binding
|
|
789
|
+
* @returns null, or a custom element name and attribute name
|
|
790
|
+
* @public
|
|
791
|
+
*/
|
|
792
|
+
export function getChildrenMap(previousString) {
|
|
793
|
+
if (typeof previousString === "string" &&
|
|
794
|
+
isAttribute(previousString, previousString.length)) {
|
|
795
|
+
const customElementName = getAttributesCustomElementName(previousString);
|
|
796
|
+
if (customElementName) {
|
|
797
|
+
return {
|
|
798
|
+
customElementName,
|
|
799
|
+
attributeName: getAttributeName(previousString),
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Get the HTML element that is passing the attribute binding
|
|
807
|
+
* @param previousString - The previous string before the binding
|
|
808
|
+
* @returns null if this is not a custom element, or the custom element that is passing the binding as an attribute
|
|
809
|
+
*/
|
|
810
|
+
function getAttributesCustomElementName(previousString) {
|
|
811
|
+
const indexOfElementTagStart = previousString.lastIndexOf("<") + 1;
|
|
812
|
+
const indexOfElementTagEnd = previousString.slice(indexOfElementTagStart).indexOf(" ") +
|
|
813
|
+
indexOfElementTagStart;
|
|
814
|
+
const elementName = previousString.slice(indexOfElementTagStart, indexOfElementTagEnd);
|
|
815
|
+
if (elementName.includes("-")) {
|
|
816
|
+
return elementName;
|
|
817
|
+
}
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Gets a non-aspected attribute name
|
|
822
|
+
* @param previousString - The previous string before the binding
|
|
823
|
+
* @returns The attribute name with any aspects (:, ?, @) removed
|
|
824
|
+
*/
|
|
825
|
+
function getAttributeName(previousString) {
|
|
826
|
+
const indexOfAttributeStart = previousString.lastIndexOf(" ") + 1;
|
|
827
|
+
const indexOfAttributeEnd = previousString.slice(indexOfAttributeStart).indexOf("=") + indexOfAttributeStart;
|
|
828
|
+
const attributeName = previousString.slice(indexOfAttributeStart, indexOfAttributeEnd);
|
|
829
|
+
const potentialAspect = attributeName.charAt(0);
|
|
830
|
+
if (potentialAspect === ":" || potentialAspect === "@" || potentialAspect === "?") {
|
|
831
|
+
return attributeName.slice(1);
|
|
832
|
+
}
|
|
833
|
+
return attributeName;
|
|
834
|
+
}
|