@microsoft/fast-element 3.0.0-rc.1 → 3.0.0-rc.2
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/CHANGELOG.md +51 -1
- package/README.md +50 -14
- package/dist/context/context.api.json +13 -13
- package/dist/declarative/declarative.api.json +654 -15
- package/dist/di/di.api.json +15 -15
- package/dist/dts/__test__/helpers.d.ts +6 -0
- package/dist/dts/__test__/setup-node.d.ts +0 -0
- package/dist/dts/binding/binding.d.ts +15 -5
- package/dist/dts/binding/one-time.d.ts +1 -1
- package/dist/dts/binding/one-way.d.ts +1 -1
- package/dist/dts/binding/signal.d.ts +1 -1
- package/dist/dts/binding/two-way.d.ts +1 -1
- package/dist/dts/components/attributes.d.ts +1 -1
- package/dist/dts/components/enable-hydration.d.ts +22 -2
- package/dist/dts/components/fast-definitions.d.ts +7 -4
- package/dist/dts/components/fast-element.d.ts +42 -12
- package/dist/dts/components/hydration-tracker.d.ts +47 -4
- package/dist/dts/components/hydration.d.ts +5 -0
- package/dist/dts/context.d.ts +7 -7
- package/dist/dts/declarative/debug.d.ts +2 -3
- package/dist/dts/declarative/index.d.ts +3 -2
- package/dist/dts/declarative/interfaces.d.ts +1 -2
- package/dist/dts/declarative/template.d.ts +2 -1
- package/dist/dts/declarative/utilities.d.ts +50 -4
- package/dist/dts/di/di.d.ts +6 -6
- package/dist/dts/dom-policy.d.ts +22 -4
- package/dist/dts/dom.d.ts +4 -16
- package/dist/dts/hydration/diagnostics.d.ts +93 -0
- package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
- package/dist/dts/hydration/messages.d.ts +62 -0
- package/dist/dts/hydration/target-builder.d.ts +26 -1
- package/dist/dts/hydration.d.ts +7 -3
- package/dist/dts/index.d.ts +7 -3
- package/dist/dts/interfaces.d.ts +1 -0
- package/dist/dts/observation/observable.d.ts +3 -3
- package/dist/dts/platform.d.ts +20 -4
- package/dist/dts/registry.d.ts +1 -0
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/compiler.d.ts +1 -1
- package/dist/dts/templating/html-binding-directive.d.ts +6 -2
- package/dist/dts/templating/html-directive.d.ts +2 -1
- package/dist/dts/templating/hydration-view.d.ts +24 -3
- package/dist/dts/templating/ref.d.ts +1 -1
- package/dist/dts/templating/render.d.ts +2 -2
- package/dist/dts/templating/repeat.d.ts +1 -1
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +5 -5
- package/dist/dts/templating/when.d.ts +1 -1
- package/dist/dts/testing/fakes.d.ts +4 -4
- package/dist/esm/__test__/helpers.js +22 -0
- package/dist/esm/__test__/setup-node.js +18 -0
- package/dist/esm/binding/two-way.js +1 -2
- package/dist/esm/components/attributes.js +12 -8
- package/dist/esm/components/element-controller.js +11 -6
- package/dist/esm/components/enable-hydration.js +27 -3
- package/dist/esm/components/fast-definitions.js +19 -18
- package/dist/esm/components/hydration-tracker.js +34 -5
- package/dist/esm/components/hydration.js +85 -6
- package/dist/esm/debug.js +1 -0
- package/dist/esm/declarative/attribute-map.js +2 -1
- package/dist/esm/declarative/debug.js +0 -1
- package/dist/esm/declarative/index.js +1 -0
- package/dist/esm/declarative/interfaces.js +0 -1
- package/dist/esm/declarative/observer-map-utilities.js +58 -55
- package/dist/esm/declarative/template-bridge.js +4 -14
- package/dist/esm/declarative/template.js +4 -3
- package/dist/esm/declarative/utilities.js +236 -1
- package/dist/esm/di/di.js +2 -1
- package/dist/esm/dom-policy.js +33 -4
- package/dist/esm/hydration/diagnostics.js +50 -0
- package/dist/esm/hydration/hydration-debugger.js +112 -0
- package/dist/esm/hydration/messages.js +84 -0
- package/dist/esm/hydration/target-builder.js +65 -19
- package/dist/esm/hydration.js +3 -1
- package/dist/esm/index.js +6 -2
- package/dist/esm/interfaces.js +1 -0
- package/dist/esm/metadata.js +2 -8
- package/dist/esm/observation/notifier.js +2 -4
- package/dist/esm/registry.js +1 -0
- package/dist/esm/templating/html-binding-directive.js +1 -1
- package/dist/esm/templating/hydration-view.js +20 -27
- package/dist/esm/templating/render.js +39 -18
- package/dist/esm/templating/repeat.js +51 -17
- package/dist/esm/templating/view.js +1 -1
- package/dist/esm/testing/fixture.js +2 -2
- package/dist/esm/testing/timeout.js +2 -2
- package/dist/fast-element.api.json +1329 -99
- package/dist/fast-element.d.ts +147 -66
- package/dist/fast-element.debug.js +392 -99
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +392 -99
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +133 -70
- package/dist/hydration/hydration.api.json +1280 -57
- package/dist/styles/styles.api.json +1 -1
- package/package.json +21 -9
- package/ARCHITECTURE_FASTELEMENT.md +0 -63
- package/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +0 -36
- package/ARCHITECTURE_INTRO.md +0 -10
- package/ARCHITECTURE_OVERVIEW.md +0 -52
- package/ARCHITECTURE_UPDATES.md +0 -11
- package/CHANGELOG.json +0 -2275
- package/DECLARATIVE_DESIGN.md +0 -806
- package/DECLARATIVE_HTML.md +0 -470
- package/DECLARATIVE_MIGRATION.md +0 -215
- package/DECLARATIVE_RENDERING.md +0 -530
- package/DECLARATIVE_RENDERING_LIFECYCLE.md +0 -288
- package/DECLARATIVE_SCHEMA_OBSERVER_MAP.md +0 -489
- package/DESIGN.md +0 -615
- package/MIGRATION.md +0 -387
- package/SIZES.md +0 -25
- package/api-extractor.arrays.json +0 -15
- package/api-extractor.context.json +0 -15
- package/api-extractor.declarative.json +0 -15
- package/api-extractor.di.json +0 -15
- package/api-extractor.hydration.json +0 -15
- package/api-extractor.styles.json +0 -15
- package/biome.json +0 -4
- package/docs/ACKNOWLEDGEMENTS.md +0 -12
- package/docs/api-report.api.md +0 -1299
- package/docs/arrays/api-report.api.md +0 -114
- package/docs/context/api-report.api.md +0 -69
- package/docs/declarative/api-report.api.md +0 -397
- package/docs/di/api-report.api.md +0 -315
- package/docs/fast-element-2-changes.md +0 -15
- package/docs/hydration/api-report.api.md +0 -285
- package/docs/styles/api-report.api.md +0 -135
- package/playwright.config.ts +0 -26
- package/playwright.declarative.config.ts +0 -26
- package/playwright.declarative.webui.config.ts +0 -20
- package/scripts/declarative/build-fixtures-with-webui.js +0 -135
- package/scripts/declarative/build-fixtures.js +0 -49
- package/scripts/declarative/build-fixtures.utilities.js +0 -101
- package/scripts/measure-sizes.js +0 -219
- package/scripts/run-api-extractor.js +0 -70
- package/test/declarative/fixtures/README.md +0 -72
- package/test/declarative/fixtures/WRITING_FIXTURES.md +0 -330
- package/test/declarative/fixtures/bindings/README.md +0 -12
- package/test/declarative/fixtures/bindings/attribute/entry.html +0 -13
- package/test/declarative/fixtures/bindings/attribute/fast-build.config.json +0 -6
- package/test/declarative/fixtures/bindings/attribute/index.html +0 -25
- package/test/declarative/fixtures/bindings/attribute/main.ts +0 -41
- package/test/declarative/fixtures/bindings/attribute/state.json +0 -8
- package/test/declarative/fixtures/bindings/attribute/templates.html +0 -11
- package/test/declarative/fixtures/bindings/content/entry.html +0 -12
- package/test/declarative/fixtures/bindings/content/fast-build.config.json +0 -6
- package/test/declarative/fixtures/bindings/content/index.html +0 -19
- package/test/declarative/fixtures/bindings/content/main.ts +0 -27
- package/test/declarative/fixtures/bindings/content/state.json +0 -4
- package/test/declarative/fixtures/bindings/content/templates.html +0 -6
- package/test/declarative/fixtures/bindings/dot-syntax/entry.html +0 -11
- package/test/declarative/fixtures/bindings/dot-syntax/fast-build.config.json +0 -6
- package/test/declarative/fixtures/bindings/dot-syntax/index.html +0 -47
- package/test/declarative/fixtures/bindings/dot-syntax/main.ts +0 -59
- package/test/declarative/fixtures/bindings/dot-syntax/state.json +0 -16
- package/test/declarative/fixtures/bindings/dot-syntax/templates.html +0 -17
- package/test/declarative/fixtures/bindings/event/entry.html +0 -11
- package/test/declarative/fixtures/bindings/event/fast-build.config.json +0 -6
- package/test/declarative/fixtures/bindings/event/index.html +0 -43
- package/test/declarative/fixtures/bindings/event/main.ts +0 -43
- package/test/declarative/fixtures/bindings/event/state.json +0 -3
- package/test/declarative/fixtures/bindings/event/templates.html +0 -18
- package/test/declarative/fixtures/bindings/host/entry.html +0 -40
- package/test/declarative/fixtures/bindings/host/fast-build.config.json +0 -6
- package/test/declarative/fixtures/bindings/host/index.html +0 -96
- package/test/declarative/fixtures/bindings/host/main.ts +0 -222
- package/test/declarative/fixtures/bindings/host/state.json +0 -9
- package/test/declarative/fixtures/bindings/host/templates.html +0 -55
- package/test/declarative/fixtures/directives/README.md +0 -12
- package/test/declarative/fixtures/directives/children/entry.html +0 -11
- package/test/declarative/fixtures/directives/children/fast-build.config.json +0 -6
- package/test/declarative/fixtures/directives/children/index.html +0 -15
- package/test/declarative/fixtures/directives/children/main.ts +0 -22
- package/test/declarative/fixtures/directives/children/state.json +0 -3
- package/test/declarative/fixtures/directives/children/templates.html +0 -3
- package/test/declarative/fixtures/directives/ref/entry.html +0 -11
- package/test/declarative/fixtures/directives/ref/fast-build.config.json +0 -6
- package/test/declarative/fixtures/directives/ref/index.html +0 -15
- package/test/declarative/fixtures/directives/ref/main.ts +0 -17
- package/test/declarative/fixtures/directives/ref/state.json +0 -1
- package/test/declarative/fixtures/directives/ref/templates.html +0 -3
- package/test/declarative/fixtures/directives/repeat/entry.html +0 -21
- package/test/declarative/fixtures/directives/repeat/fast-build.config.json +0 -6
- package/test/declarative/fixtures/directives/repeat/index.html +0 -133
- package/test/declarative/fixtures/directives/repeat/main.ts +0 -110
- package/test/declarative/fixtures/directives/repeat/sprites.svg +0 -8
- package/test/declarative/fixtures/directives/repeat/state.json +0 -10
- package/test/declarative/fixtures/directives/repeat/templates.html +0 -75
- package/test/declarative/fixtures/directives/slotted/entry.html +0 -17
- package/test/declarative/fixtures/directives/slotted/fast-build.config.json +0 -6
- package/test/declarative/fixtures/directives/slotted/index.html +0 -27
- package/test/declarative/fixtures/directives/slotted/main.ts +0 -29
- package/test/declarative/fixtures/directives/slotted/state.json +0 -1
- package/test/declarative/fixtures/directives/slotted/templates.html +0 -7
- package/test/declarative/fixtures/directives/when/entry.html +0 -51
- package/test/declarative/fixtures/directives/when/fast-build.config.json +0 -6
- package/test/declarative/fixtures/directives/when/index.html +0 -136
- package/test/declarative/fixtures/directives/when/main.ts +0 -172
- package/test/declarative/fixtures/directives/when/state.json +0 -12
- package/test/declarative/fixtures/directives/when/templates.html +0 -75
- package/test/declarative/fixtures/ecosystem/README.md +0 -11
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/entry.html +0 -12
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/fast-build.config.json +0 -6
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/index.html +0 -20
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/main.ts +0 -68
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/state.json +0 -4
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/templates.html +0 -7
- package/test/declarative/fixtures/ecosystem/errors/entry.html +0 -12
- package/test/declarative/fixtures/ecosystem/errors/fast-build.config.json +0 -6
- package/test/declarative/fixtures/ecosystem/errors/index.html +0 -20
- package/test/declarative/fixtures/ecosystem/errors/main.ts +0 -17
- package/test/declarative/fixtures/ecosystem/errors/state.json +0 -1
- package/test/declarative/fixtures/ecosystem/errors/templates.html +0 -7
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/entry.html +0 -17
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/fast-build.config.json +0 -6
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/index.html +0 -56
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/main.ts +0 -134
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/state.json +0 -12
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/templates.html +0 -34
- package/test/declarative/fixtures/ecosystem/performance-metrics/entry.html +0 -25
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-build.config.json +0 -6
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-card.css +0 -10
- package/test/declarative/fixtures/ecosystem/performance-metrics/index.html +0 -181
- package/test/declarative/fixtures/ecosystem/performance-metrics/main.ts +0 -58
- package/test/declarative/fixtures/ecosystem/performance-metrics/state.json +0 -6
- package/test/declarative/fixtures/ecosystem/performance-metrics/templates.html +0 -15
- package/test/declarative/fixtures/extensions/README.md +0 -15
- package/test/declarative/fixtures/extensions/attribute-map/entry.html +0 -14
- package/test/declarative/fixtures/extensions/attribute-map/fast-build.config.json +0 -6
- package/test/declarative/fixtures/extensions/attribute-map/index.html +0 -31
- package/test/declarative/fixtures/extensions/attribute-map/main.ts +0 -40
- package/test/declarative/fixtures/extensions/attribute-map/state.json +0 -4
- package/test/declarative/fixtures/extensions/attribute-map/templates.html +0 -14
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/entry.html +0 -12
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/fast-build.config.json +0 -7
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/index.html +0 -25
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/main.ts +0 -31
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/state.json +0 -5
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/templates.html +0 -11
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/entry.html +0 -13
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/fast-build.config.json +0 -7
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/index.html +0 -23
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/main.ts +0 -37
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/state.json +0 -1
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/templates.html +0 -9
- package/test/declarative/fixtures/extensions/observer-map/entry.html +0 -15
- package/test/declarative/fixtures/extensions/observer-map/fast-build.config.json +0 -6
- package/test/declarative/fixtures/extensions/observer-map/index.html +0 -442
- package/test/declarative/fixtures/extensions/observer-map/main.ts +0 -482
- package/test/declarative/fixtures/extensions/observer-map/state.json +0 -158
- package/test/declarative/fixtures/extensions/observer-map/templates.html +0 -172
- package/test/declarative/fixtures/extensions/observer-map-config-object/entry.html +0 -16
- package/test/declarative/fixtures/extensions/observer-map-config-object/fast-build.config.json +0 -6
- package/test/declarative/fixtures/extensions/observer-map-config-object/index.html +0 -27
- package/test/declarative/fixtures/extensions/observer-map-config-object/main.ts +0 -53
- package/test/declarative/fixtures/extensions/observer-map-config-object/state.json +0 -9
- package/test/declarative/fixtures/extensions/observer-map-config-object/templates.html +0 -12
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/README.md +0 -98
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/entry.html +0 -156
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/fast-build.config.json +0 -6
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/index.html +0 -376
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/main.ts +0 -366
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/state.json +0 -69
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/templates.html +0 -91
- package/test/declarative/fixtures/extensions/observer-map-properties/entry.html +0 -14
- package/test/declarative/fixtures/extensions/observer-map-properties/fast-build.config.json +0 -6
- package/test/declarative/fixtures/extensions/observer-map-properties/index.html +0 -110
- package/test/declarative/fixtures/extensions/observer-map-properties/main.ts +0 -175
- package/test/declarative/fixtures/extensions/observer-map-properties/state.json +0 -29
- package/test/declarative/fixtures/extensions/observer-map-properties/templates.html +0 -55
- package/test/declarative/fixtures/scenarios/README.md +0 -7
- package/test/declarative/fixtures/scenarios/nested-elements/entry.html +0 -16
- package/test/declarative/fixtures/scenarios/nested-elements/fast-build.config.json +0 -6
- package/test/declarative/fixtures/scenarios/nested-elements/index.html +0 -126
- package/test/declarative/fixtures/scenarios/nested-elements/main.ts +0 -214
- package/test/declarative/fixtures/scenarios/nested-elements/state.json +0 -10
- package/test/declarative/fixtures/scenarios/nested-elements/templates.html +0 -54
- package/test/declarative/index.html +0 -12
- package/test/declarative/vite.config.ts +0 -55
- package/test/declarative-main.ts +0 -6
- package/test/extension-subpaths-main.ts +0 -9
- package/test/index.html +0 -11
- package/test/main.ts +0 -109
- package/test/pure-declarative-main.ts +0 -1
- package/test/vite.config.ts +0 -19
- package/tsconfig.api-extractor.json +0 -6
package/dist/fast-element.js
CHANGED
|
@@ -18,6 +18,7 @@ var Message;
|
|
|
18
18
|
Message[Message["cannotSetTemplatePolicyAfterCompilation"] = 1208] = "cannotSetTemplatePolicyAfterCompilation";
|
|
19
19
|
Message[Message["blockedByDOMPolicy"] = 1209] = "blockedByDOMPolicy";
|
|
20
20
|
Message[Message["invalidHydrationAttributeMarker"] = 1210] = "invalidHydrationAttributeMarker";
|
|
21
|
+
Message[Message["duplicateRenderInstruction"] = 1211] = "duplicateRenderInstruction";
|
|
21
22
|
// 1301 - 1400 Styles
|
|
22
23
|
// 1401 - 1500 Components
|
|
23
24
|
Message[Message["missingElementDefinition"] = 1401] = "missingElementDefinition";
|
|
@@ -251,10 +252,40 @@ const DOM = Object.freeze({
|
|
|
251
252
|
},
|
|
252
253
|
});
|
|
253
254
|
|
|
255
|
+
const surroundingWhitespaceAndControlChars = /^[\u0000-\u0020\u007F]+|[\u0000-\u0020\u007F]+$/g;
|
|
256
|
+
const whitespaceAndControlChars = /[\u0000-\u0020\u007F]+/g;
|
|
257
|
+
const unsafeURLProtocol = /^(?:javascript|vbscript|data):/;
|
|
258
|
+
function trimURL(value) {
|
|
259
|
+
return value.replace(surroundingWhitespaceAndControlChars, "");
|
|
260
|
+
}
|
|
261
|
+
function decodeURL(value) {
|
|
262
|
+
try {
|
|
263
|
+
return decodeURIComponent(value);
|
|
264
|
+
}
|
|
265
|
+
catch (_a) {
|
|
266
|
+
return value;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function hasUnsafeURLProtocol(value) {
|
|
270
|
+
let normalized = trimURL(value);
|
|
271
|
+
for (let i = 0; i < 3; ++i) {
|
|
272
|
+
const decoded = decodeURL(normalized);
|
|
273
|
+
if (decoded === normalized) {
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
normalized = trimURL(decoded);
|
|
277
|
+
}
|
|
278
|
+
normalized = normalized.replace(whitespaceAndControlChars, "").toLowerCase();
|
|
279
|
+
return unsafeURLProtocol.test(normalized);
|
|
280
|
+
}
|
|
281
|
+
function sanitizeURL(value) {
|
|
282
|
+
const trimmed = trimURL(value);
|
|
283
|
+
return hasUnsafeURLProtocol(trimmed) ? "" : trimmed;
|
|
284
|
+
}
|
|
254
285
|
function safeURL(tagName, aspect, aspectName, sink) {
|
|
255
286
|
return (target, name, value, ...rest) => {
|
|
256
287
|
if (isString(value)) {
|
|
257
|
-
value = value
|
|
288
|
+
value = sanitizeURL(value);
|
|
258
289
|
}
|
|
259
290
|
sink(target, name, value, ...rest);
|
|
260
291
|
};
|
|
@@ -516,7 +547,7 @@ function createElementGuards(config, defaults) {
|
|
|
516
547
|
break;
|
|
517
548
|
case undefined:
|
|
518
549
|
// keep the default
|
|
519
|
-
result[tag] = createDOMAspectGuards(
|
|
550
|
+
result[tag] = createDOMAspectGuards(defaultValue, {});
|
|
520
551
|
break;
|
|
521
552
|
default:
|
|
522
553
|
// override the default aspects
|
|
@@ -1170,14 +1201,10 @@ const AttributeConfiguration = Object.freeze({
|
|
|
1170
1201
|
*/
|
|
1171
1202
|
const booleanConverter = {
|
|
1172
1203
|
toView(value) {
|
|
1173
|
-
return value ? "
|
|
1204
|
+
return value ? "" : null;
|
|
1174
1205
|
},
|
|
1175
1206
|
fromView(value) {
|
|
1176
|
-
return
|
|
1177
|
-
value === void 0 ||
|
|
1178
|
-
value === "false" ||
|
|
1179
|
-
value === false ||
|
|
1180
|
-
value === 0);
|
|
1207
|
+
return !!value;
|
|
1181
1208
|
},
|
|
1182
1209
|
};
|
|
1183
1210
|
/**
|
|
@@ -1217,7 +1244,7 @@ const nullableNumberConverter = {
|
|
|
1217
1244
|
fromView: toNumber,
|
|
1218
1245
|
};
|
|
1219
1246
|
/**
|
|
1220
|
-
* An implementation of
|
|
1247
|
+
* An implementation of {@link Accessor} that supports reactivity,
|
|
1221
1248
|
* change callbacks, attribute reflection, and type conversion for
|
|
1222
1249
|
* custom elements.
|
|
1223
1250
|
* @public
|
|
@@ -1280,7 +1307,15 @@ class AttributeDefinition {
|
|
|
1280
1307
|
return;
|
|
1281
1308
|
}
|
|
1282
1309
|
this.guards.add(element);
|
|
1283
|
-
this.
|
|
1310
|
+
if (this.mode === booleanMode) {
|
|
1311
|
+
// Native HTML boolean attribute semantics: presence of the attribute
|
|
1312
|
+
// (any string value, including "") means `true`; `null` (the value
|
|
1313
|
+
// passed by the platform on `removeAttribute`) means `false`.
|
|
1314
|
+
this.setValue(element, value !== null);
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
this.setValue(element, value);
|
|
1318
|
+
}
|
|
1284
1319
|
this.guards.delete(element);
|
|
1285
1320
|
}
|
|
1286
1321
|
tryReflectToAttribute(element) {
|
|
@@ -1829,8 +1864,11 @@ const defaultShadowOptions = { mode: "open" };
|
|
|
1829
1864
|
const defaultElementOptions = {};
|
|
1830
1865
|
const fastElementBaseTypes = new Set();
|
|
1831
1866
|
/**
|
|
1832
|
-
* The FAST custom element registry
|
|
1833
|
-
* @
|
|
1867
|
+
* The FAST custom element registry.
|
|
1868
|
+
* @remarks
|
|
1869
|
+
* This registry stores FAST element definitions by constructor so consumers can
|
|
1870
|
+
* look up the `FASTElementDefinition` associated with an element type or instance.
|
|
1871
|
+
* @public
|
|
1834
1872
|
*/
|
|
1835
1873
|
const fastElementRegistry = createTypeRegistry();
|
|
1836
1874
|
const templateResolvers = new WeakMap();
|
|
@@ -2095,7 +2133,7 @@ FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
|
|
|
2095
2133
|
* @param name - The name of the defined custom element.
|
|
2096
2134
|
* @alpha
|
|
2097
2135
|
*/
|
|
2098
|
-
FASTElementDefinition.register = (
|
|
2136
|
+
FASTElementDefinition.register = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, registry = customElements) {
|
|
2099
2137
|
const registeredTypes = getRegisteredTypes(registry);
|
|
2100
2138
|
if (!Object.prototype.hasOwnProperty.call(registeredTypes, name)) {
|
|
2101
2139
|
Observable.defineProperty(registeredTypes, name);
|
|
@@ -2595,7 +2633,8 @@ class ElementController {
|
|
|
2595
2633
|
* customElements.define() completed.
|
|
2596
2634
|
*/
|
|
2597
2635
|
observeLateAttributes() {
|
|
2598
|
-
|
|
2636
|
+
const lateAttributes = getLateAttributeLookup(this.definition);
|
|
2637
|
+
if (lateAttributes === null) {
|
|
2599
2638
|
return;
|
|
2600
2639
|
}
|
|
2601
2640
|
const element = this.source;
|
|
@@ -2616,7 +2655,10 @@ class ElementController {
|
|
|
2616
2655
|
controller.onAttributeChangedCallback(attributeName, null, element.getAttribute(attributeName));
|
|
2617
2656
|
}
|
|
2618
2657
|
});
|
|
2619
|
-
element[lateAttributeObserver].observe(element, {
|
|
2658
|
+
element[lateAttributeObserver].observe(element, {
|
|
2659
|
+
attributes: true,
|
|
2660
|
+
attributeFilter: Object.keys(lateAttributes),
|
|
2661
|
+
});
|
|
2620
2662
|
}
|
|
2621
2663
|
/**
|
|
2622
2664
|
* Connects any existing behaviors on the associated element.
|
|
@@ -3023,6 +3065,7 @@ const baseDebugMessages = {
|
|
|
3023
3065
|
[1208 /* cannotSetTemplatePolicyAfterCompilation */]: "The DOM Policy cannot be set after a template is compiled.",
|
|
3024
3066
|
[1209 /* blockedByDOMPolicy */]: "'${aspectName}' on '${tagName}' is blocked by the current DOMPolicy.",
|
|
3025
3067
|
[1210 /* invalidHydrationAttributeMarker */]: "Invalid data-fe attribute value '${value}'. Expected a positive integer.",
|
|
3068
|
+
[1211 /* duplicateRenderInstruction */]: "Replacing existing RenderInstruction for '${type}' with name '${name}'.",
|
|
3026
3069
|
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
3027
3070
|
[1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
|
|
3028
3071
|
[1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
|
|
@@ -3465,7 +3508,17 @@ const ref = (propertyName) => new RefDirective(propertyName);
|
|
|
3465
3508
|
* Attribute bindings use a single `data-fe` attribute whose value is
|
|
3466
3509
|
* the count of attribute binding factories targeting the element:
|
|
3467
3510
|
* <div data-fe="3"> (3 attribute bindings)
|
|
3511
|
+
*
|
|
3512
|
+
* WebUI versions that predate the data-free marker format still emit indexed
|
|
3513
|
+
* markers. The parser below accepts those legacy markers so existing WebUI SSR
|
|
3514
|
+
* output can hydrate against the newer FAST runtime.
|
|
3468
3515
|
*/
|
|
3516
|
+
const legacyBindingStartMarker = /fe-b\$\$start\$\$(\d+)\$\$(.+)\$\$fe-b/;
|
|
3517
|
+
const legacyBindingEndMarker = /fe-b\$\$end\$\$(\d+)\$\$(.+)\$\$fe-b/;
|
|
3518
|
+
const legacyRepeatViewStartMarker = /fe-repeat\$\$start\$\$(\d+)\$\$fe-repeat/;
|
|
3519
|
+
const legacyRepeatViewEndMarker = /fe-repeat\$\$end\$\$(\d+)\$\$fe-repeat/;
|
|
3520
|
+
const legacyElementBoundaryStartMarker = /^(?:.{0,1000})fe-eb\$\$start\$\$(.+?)\$\$fe-eb/;
|
|
3521
|
+
const legacyElementBoundaryEndMarker = /fe-eb\$\$end\$\$(.{0,1000})\$\$fe-eb(?:.{0,1000})$/;
|
|
3469
3522
|
function isComment$1(node) {
|
|
3470
3523
|
return node && node.nodeType === Node.COMMENT_NODE;
|
|
3471
3524
|
}
|
|
@@ -3476,6 +3529,8 @@ function isComment$1(node) {
|
|
|
3476
3529
|
const HydrationMarkup = Object.freeze({
|
|
3477
3530
|
// Single attribute marker format (count only)
|
|
3478
3531
|
attributeMarkerName: "data-fe",
|
|
3532
|
+
legacyAttributeMarkerName: "data-fe-b",
|
|
3533
|
+
legacyCompactAttributeMarkerName: "data-fe-c",
|
|
3479
3534
|
// Content binding markers (no arguments)
|
|
3480
3535
|
contentBindingStartMarker() {
|
|
3481
3536
|
return "fe:b";
|
|
@@ -3499,22 +3554,24 @@ const HydrationMarkup = Object.freeze({
|
|
|
3499
3554
|
},
|
|
3500
3555
|
// Detection — simple string equality
|
|
3501
3556
|
isContentBindingStartMarker(data) {
|
|
3502
|
-
return data === "fe:b";
|
|
3557
|
+
return data === "fe:b" || legacyBindingStartMarker.test(data);
|
|
3503
3558
|
},
|
|
3504
3559
|
isContentBindingEndMarker(data) {
|
|
3505
|
-
return data === "fe:/b";
|
|
3560
|
+
return data === "fe:/b" || legacyBindingEndMarker.test(data);
|
|
3506
3561
|
},
|
|
3507
3562
|
isRepeatViewStartMarker(data) {
|
|
3508
|
-
return data === "fe:r";
|
|
3563
|
+
return data === "fe:r" || legacyRepeatViewStartMarker.test(data);
|
|
3509
3564
|
},
|
|
3510
3565
|
isRepeatViewEndMarker(data) {
|
|
3511
|
-
return data === "fe:/r";
|
|
3566
|
+
return data === "fe:/r" || legacyRepeatViewEndMarker.test(data);
|
|
3512
3567
|
},
|
|
3513
3568
|
isElementBoundaryStartMarker(node) {
|
|
3514
|
-
return isComment$1(node) &&
|
|
3569
|
+
return (isComment$1(node) &&
|
|
3570
|
+
(node.data === "fe:e" || legacyElementBoundaryStartMarker.test(node.data)));
|
|
3515
3571
|
},
|
|
3516
3572
|
isElementBoundaryEndMarker(node) {
|
|
3517
|
-
return isComment$1(node) &&
|
|
3573
|
+
return (isComment$1(node) &&
|
|
3574
|
+
(node.data === "fe:/e" || legacyElementBoundaryEndMarker.test(node.data)));
|
|
3518
3575
|
},
|
|
3519
3576
|
/**
|
|
3520
3577
|
* Returns the count of attribute bindings on the element, or null
|
|
@@ -3542,7 +3599,72 @@ const HydrationMarkup = Object.freeze({
|
|
|
3542
3599
|
}
|
|
3543
3600
|
return count;
|
|
3544
3601
|
},
|
|
3602
|
+
parseLegacyAttributeBindingIndices(node) {
|
|
3603
|
+
const indices = [];
|
|
3604
|
+
const attr = node.getAttribute(this.legacyAttributeMarkerName);
|
|
3605
|
+
if (attr !== null) {
|
|
3606
|
+
for (const value of attr.trim().split(/\s+/)) {
|
|
3607
|
+
if (value === "") {
|
|
3608
|
+
continue;
|
|
3609
|
+
}
|
|
3610
|
+
const index = Number(value);
|
|
3611
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
3612
|
+
throw FAST.error(Message.invalidHydrationAttributeMarker, {
|
|
3613
|
+
value: attr,
|
|
3614
|
+
});
|
|
3615
|
+
}
|
|
3616
|
+
indices.push(index);
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
const enumeratedPrefix = `${this.legacyAttributeMarkerName}-`;
|
|
3620
|
+
const compactPrefix = `${this.legacyCompactAttributeMarkerName}-`;
|
|
3621
|
+
for (const name of node.getAttributeNames()) {
|
|
3622
|
+
if (name.startsWith(enumeratedPrefix)) {
|
|
3623
|
+
const index = Number(name.slice(enumeratedPrefix.length));
|
|
3624
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
3625
|
+
throw FAST.error(Message.invalidHydrationAttributeMarker, {
|
|
3626
|
+
value: name,
|
|
3627
|
+
});
|
|
3628
|
+
}
|
|
3629
|
+
indices.push(index);
|
|
3630
|
+
}
|
|
3631
|
+
else if (name.startsWith(compactPrefix)) {
|
|
3632
|
+
const [start, count] = name
|
|
3633
|
+
.slice(compactPrefix.length)
|
|
3634
|
+
.split("-")
|
|
3635
|
+
.map(value => Number(value));
|
|
3636
|
+
if (!Number.isInteger(start) ||
|
|
3637
|
+
!Number.isInteger(count) ||
|
|
3638
|
+
start < 0 ||
|
|
3639
|
+
count < 1) {
|
|
3640
|
+
throw FAST.error(Message.invalidHydrationAttributeMarker, {
|
|
3641
|
+
value: name,
|
|
3642
|
+
});
|
|
3643
|
+
}
|
|
3644
|
+
for (let i = 0; i < count; i++) {
|
|
3645
|
+
indices.push(start + i);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
return indices.length === 0 ? null : indices;
|
|
3650
|
+
},
|
|
3651
|
+
removeLegacyAttributeBindingMarkers(node) {
|
|
3652
|
+
node.removeAttribute(this.legacyAttributeMarkerName);
|
|
3653
|
+
for (const name of node.getAttributeNames()) {
|
|
3654
|
+
if (name.startsWith(`${this.legacyAttributeMarkerName}-`) ||
|
|
3655
|
+
name.startsWith(`${this.legacyCompactAttributeMarkerName}-`)) {
|
|
3656
|
+
node.removeAttribute(name);
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
},
|
|
3660
|
+
parseLegacyContentBindingStartIndex(data) {
|
|
3661
|
+
return parseLegacyIntMarker(legacyBindingStartMarker, data);
|
|
3662
|
+
},
|
|
3545
3663
|
});
|
|
3664
|
+
function parseLegacyIntMarker(pattern, data) {
|
|
3665
|
+
const match = pattern.exec(data);
|
|
3666
|
+
return match === null ? null : Number(match[1]);
|
|
3667
|
+
}
|
|
3546
3668
|
/**
|
|
3547
3669
|
* @internal
|
|
3548
3670
|
*/
|
|
@@ -4209,6 +4331,94 @@ function sortedCount(array) {
|
|
|
4209
4331
|
return array.sorted;
|
|
4210
4332
|
}
|
|
4211
4333
|
|
|
4334
|
+
/**
|
|
4335
|
+
* Centralized hydration mismatch message strings used by both the default
|
|
4336
|
+
* minimal `HydrationDiagnostic` and the opt-in `hydrationDebugger` rich
|
|
4337
|
+
* formatter, and by the structural-error throw sites in
|
|
4338
|
+
* `target-builder.ts`.
|
|
4339
|
+
*
|
|
4340
|
+
* Static text is exported as a plain `const`; interpolated text is exported
|
|
4341
|
+
* as a small builder function. Plain `export const` declarations tree-shake
|
|
4342
|
+
* better than frozen-object property bags, so unused strings drop out of
|
|
4343
|
+
* bundles cleanly.
|
|
4344
|
+
*/
|
|
4345
|
+
/**
|
|
4346
|
+
* Fallback host tag name used when a hydration mismatch is detected on a
|
|
4347
|
+
* node that is not inside a shadow root.
|
|
4348
|
+
*/
|
|
4349
|
+
const unknownHostName = "unknown";
|
|
4350
|
+
/**
|
|
4351
|
+
* Default minimal hydration mismatch message used when the
|
|
4352
|
+
* `hydrationDebugger` opt-in is not installed. The optional `detail` string
|
|
4353
|
+
* carries the structural expectation surfaced by `target-builder.ts`.
|
|
4354
|
+
*/
|
|
4355
|
+
function formatDefaultMismatchMessage(hostName, detail) {
|
|
4356
|
+
const suffix = detail ? `: ${detail}` : "";
|
|
4357
|
+
return (`Hydration mismatch in <${hostName}>${suffix}. Install ` +
|
|
4358
|
+
`hydrationDebugger() from "@microsoft/fast-element/hydration.js" and ` +
|
|
4359
|
+
`pass it as enableHydration({ debugger: hydrationDebugger() }) for an ` +
|
|
4360
|
+
`"Expected / Received" report including the SSR HTML snippet.`);
|
|
4361
|
+
}
|
|
4362
|
+
// -- Structural expectations (used by target-builder.ts throw sites) ---------
|
|
4363
|
+
const expectedContentAfterStartMarker = "content following `<!--fe:b-->` content binding marker";
|
|
4364
|
+
const expectedContentEndMarker = "matching `<!--fe:/b-->` content binding close marker";
|
|
4365
|
+
const expectedElementBoundaryEndMarker = "matching `<!--fe:/e-->` element boundary close marker";
|
|
4366
|
+
/**
|
|
4367
|
+
* Builds the "no more attribute bindings" structural expectation message
|
|
4368
|
+
* thrown when an element's `data-fe` count claims more attribute bindings
|
|
4369
|
+
* than the compiled template defines.
|
|
4370
|
+
*/
|
|
4371
|
+
function formatNoMoreAttributeBindings(factoryCount) {
|
|
4372
|
+
return `no more attribute bindings (template defines ${factoryCount})`;
|
|
4373
|
+
}
|
|
4374
|
+
/**
|
|
4375
|
+
* Builds the "no more content bindings" structural expectation message
|
|
4376
|
+
* thrown when the SSR DOM contains more content binding markers than the
|
|
4377
|
+
* compiled template defines.
|
|
4378
|
+
*/
|
|
4379
|
+
function formatNoMoreContentBindings(factoryCount) {
|
|
4380
|
+
return `no more content bindings (template defines ${factoryCount})`;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
function formatMinimalMessage(hostName, detail) {
|
|
4384
|
+
const host = (hostName !== null && hostName !== void 0 ? hostName : unknownHostName).toLowerCase();
|
|
4385
|
+
return formatDefaultMismatchMessage(host, detail);
|
|
4386
|
+
}
|
|
4387
|
+
const defaultDiagnostic = {
|
|
4388
|
+
formatBindingMismatch(_factory, _firstChild, _lastChild, hostName) {
|
|
4389
|
+
return {
|
|
4390
|
+
message: formatMinimalMessage(hostName, undefined),
|
|
4391
|
+
};
|
|
4392
|
+
},
|
|
4393
|
+
formatStructuralError(_node, hostName, expectedDescription) {
|
|
4394
|
+
return {
|
|
4395
|
+
message: formatMinimalMessage(hostName, expectedDescription),
|
|
4396
|
+
};
|
|
4397
|
+
},
|
|
4398
|
+
};
|
|
4399
|
+
let activeDiagnostic = defaultDiagnostic;
|
|
4400
|
+
/**
|
|
4401
|
+
* Returns the currently active {@link HydrationDiagnostic} — either the
|
|
4402
|
+
* minimal default or one installed by an opt-in debugger.
|
|
4403
|
+
* @internal
|
|
4404
|
+
*/
|
|
4405
|
+
function getHydrationDiagnostic() {
|
|
4406
|
+
return activeDiagnostic;
|
|
4407
|
+
}
|
|
4408
|
+
/**
|
|
4409
|
+
* Reads the host element's tag name from any node inside a hydration view.
|
|
4410
|
+
* Returns `undefined` when the node is not inside a shadow root.
|
|
4411
|
+
* @internal
|
|
4412
|
+
*/
|
|
4413
|
+
function getHostName(node) {
|
|
4414
|
+
var _a;
|
|
4415
|
+
if (!node) {
|
|
4416
|
+
return undefined;
|
|
4417
|
+
}
|
|
4418
|
+
const root = node.getRootNode();
|
|
4419
|
+
return (_a = root.host) === null || _a === void 0 ? void 0 : _a.nodeName;
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4212
4422
|
class HydrationTargetElementError extends Error {
|
|
4213
4423
|
constructor(
|
|
4214
4424
|
/**
|
|
@@ -4222,10 +4432,24 @@ class HydrationTargetElementError extends Error {
|
|
|
4222
4432
|
/**
|
|
4223
4433
|
* The node to target factory.
|
|
4224
4434
|
*/
|
|
4225
|
-
node
|
|
4435
|
+
node,
|
|
4436
|
+
/**
|
|
4437
|
+
* Structured description of the binding the hydration walk was
|
|
4438
|
+
* attempting to apply when the mismatch was detected. Free-form
|
|
4439
|
+
* string for structural errors that do not correspond to a single
|
|
4440
|
+
* binding factory.
|
|
4441
|
+
*/
|
|
4442
|
+
expected,
|
|
4443
|
+
/**
|
|
4444
|
+
* Structured description of the server-rendered DOM that was
|
|
4445
|
+
* encountered at the mismatch point.
|
|
4446
|
+
*/
|
|
4447
|
+
received) {
|
|
4226
4448
|
super(message);
|
|
4227
4449
|
this.factories = factories;
|
|
4228
4450
|
this.node = node;
|
|
4451
|
+
this.expected = expected;
|
|
4452
|
+
this.received = received;
|
|
4229
4453
|
}
|
|
4230
4454
|
}
|
|
4231
4455
|
function isComment(node) {
|
|
@@ -4274,7 +4498,6 @@ function createRangeForNodes(first, last) {
|
|
|
4274
4498
|
* @returns - A {@link ViewBehaviorTargets } object for the factories in the view.
|
|
4275
4499
|
*/
|
|
4276
4500
|
function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
4277
|
-
var _a, _b;
|
|
4278
4501
|
const range = createRangeForNodes(firstNode, lastNode);
|
|
4279
4502
|
const treeRoot = range.commonAncestorContainer;
|
|
4280
4503
|
const walker = document.createTreeWalker(treeRoot, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_COMMENT + NodeFilter.SHOW_TEXT, {
|
|
@@ -4287,36 +4510,63 @@ function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
|
4287
4510
|
const targets = {};
|
|
4288
4511
|
const boundaries = {};
|
|
4289
4512
|
// Sequential factory pointer — skip host bindings at the start
|
|
4290
|
-
|
|
4513
|
+
const hydrationIndexOffset = getHydrationIndexOffset(factories);
|
|
4514
|
+
let factoryPointer = hydrationIndexOffset;
|
|
4291
4515
|
let node = (walker.currentNode = firstNode);
|
|
4292
4516
|
while (node !== null) {
|
|
4293
4517
|
switch (node.nodeType) {
|
|
4294
4518
|
case Node.ELEMENT_NODE: {
|
|
4295
|
-
const
|
|
4519
|
+
const element = node;
|
|
4520
|
+
const legacyIndices = HydrationMarkup.parseLegacyAttributeBindingIndices(element);
|
|
4521
|
+
if (legacyIndices !== null) {
|
|
4522
|
+
for (const index of legacyIndices) {
|
|
4523
|
+
const factoryIndex = index + hydrationIndexOffset;
|
|
4524
|
+
const factory = factories[factoryIndex];
|
|
4525
|
+
if (!factory) {
|
|
4526
|
+
const expected = formatNoMoreAttributeBindings(factories.length);
|
|
4527
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
4528
|
+
throw new HydrationTargetElementError(result.message, factories, element, result.expected, result.received);
|
|
4529
|
+
}
|
|
4530
|
+
targetFactory(factory, node, targets);
|
|
4531
|
+
factoryPointer = Math.max(factoryPointer, factoryIndex + 1);
|
|
4532
|
+
}
|
|
4533
|
+
HydrationMarkup.removeLegacyAttributeBindingMarkers(element);
|
|
4534
|
+
break;
|
|
4535
|
+
}
|
|
4536
|
+
const count = HydrationMarkup.parseAttributeBindingCount(element);
|
|
4296
4537
|
if (count !== null) {
|
|
4297
4538
|
for (let i = 0; i < count; i++) {
|
|
4298
4539
|
const factory = factories[factoryPointer++];
|
|
4299
4540
|
if (!factory) {
|
|
4300
|
-
|
|
4541
|
+
const expected = formatNoMoreAttributeBindings(factories.length);
|
|
4542
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
4543
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
4301
4544
|
}
|
|
4302
4545
|
targetFactory(factory, node, targets);
|
|
4303
4546
|
}
|
|
4304
|
-
|
|
4547
|
+
element.removeAttribute(HydrationMarkup.attributeMarkerName);
|
|
4305
4548
|
}
|
|
4306
4549
|
break;
|
|
4307
4550
|
}
|
|
4308
4551
|
case Node.COMMENT_NODE: {
|
|
4309
4552
|
const data = node.data;
|
|
4310
|
-
if (
|
|
4553
|
+
if (HydrationMarkup.isElementBoundaryStartMarker(node)) {
|
|
4311
4554
|
// Element boundary — clear start marker and skip subtree
|
|
4312
4555
|
node.data = "";
|
|
4313
4556
|
skipToElementBoundaryEnd(walker, factories, node);
|
|
4314
4557
|
}
|
|
4315
|
-
else if (data
|
|
4558
|
+
else if (HydrationMarkup.isContentBindingStartMarker(data)) {
|
|
4316
4559
|
// Content binding — consume next factory
|
|
4317
|
-
const
|
|
4560
|
+
const legacyIndex = HydrationMarkup.parseLegacyContentBindingStartIndex(data);
|
|
4561
|
+
const factoryIndex = legacyIndex === null
|
|
4562
|
+
? factoryPointer++
|
|
4563
|
+
: legacyIndex + hydrationIndexOffset;
|
|
4564
|
+
const factory = factories[factoryIndex];
|
|
4565
|
+
factoryPointer = Math.max(factoryPointer, factoryIndex + 1);
|
|
4318
4566
|
if (!factory) {
|
|
4319
|
-
|
|
4567
|
+
const expected = formatNoMoreContentBindings(factories.length);
|
|
4568
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
4569
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
4320
4570
|
}
|
|
4321
4571
|
targetContentBinding(node, walker, factory, factories, targets, boundaries);
|
|
4322
4572
|
}
|
|
@@ -4329,22 +4579,23 @@ function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
|
4329
4579
|
return { targets, boundaries };
|
|
4330
4580
|
}
|
|
4331
4581
|
function targetContentBinding(node, walker, factory, factories, targets, boundaries) {
|
|
4332
|
-
var _a, _b, _c, _d;
|
|
4333
4582
|
const nodes = [];
|
|
4334
4583
|
let current = walker.nextSibling();
|
|
4335
4584
|
node.data = "";
|
|
4336
4585
|
if (current === null) {
|
|
4337
|
-
|
|
4586
|
+
const expected = expectedContentAfterStartMarker;
|
|
4587
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
4588
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
4338
4589
|
}
|
|
4339
4590
|
const first = current;
|
|
4340
4591
|
// Balanced depth counting for nested content markers
|
|
4341
4592
|
let depth = 0;
|
|
4342
4593
|
while (current !== null) {
|
|
4343
4594
|
if (isComment(current)) {
|
|
4344
|
-
if (current.data
|
|
4595
|
+
if (HydrationMarkup.isContentBindingStartMarker(current.data)) {
|
|
4345
4596
|
depth++;
|
|
4346
4597
|
}
|
|
4347
|
-
else if (current.data
|
|
4598
|
+
else if (HydrationMarkup.isContentBindingEndMarker(current.data)) {
|
|
4348
4599
|
if (depth === 0)
|
|
4349
4600
|
break;
|
|
4350
4601
|
depth--;
|
|
@@ -4354,7 +4605,9 @@ function targetContentBinding(node, walker, factory, factories, targets, boundar
|
|
|
4354
4605
|
current = walker.nextSibling();
|
|
4355
4606
|
}
|
|
4356
4607
|
if (current === null) {
|
|
4357
|
-
|
|
4608
|
+
const expected = expectedContentEndMarker;
|
|
4609
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
4610
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
4358
4611
|
}
|
|
4359
4612
|
current.data = "";
|
|
4360
4613
|
if (nodes.length === 1 && isText(nodes[0])) {
|
|
@@ -4380,16 +4633,15 @@ function targetContentBinding(node, walker, factory, factories, targets, boundar
|
|
|
4380
4633
|
* depth counting to handle nested element boundaries correctly.
|
|
4381
4634
|
*/
|
|
4382
4635
|
function skipToElementBoundaryEnd(walker, factories, startNode) {
|
|
4383
|
-
var _a, _b;
|
|
4384
4636
|
let depth = 0;
|
|
4385
4637
|
let current = walker.nextSibling();
|
|
4386
4638
|
while (current !== null) {
|
|
4387
4639
|
if (isComment(current)) {
|
|
4388
|
-
if (current
|
|
4640
|
+
if (HydrationMarkup.isElementBoundaryStartMarker(current)) {
|
|
4389
4641
|
current.data = "";
|
|
4390
4642
|
depth++;
|
|
4391
4643
|
}
|
|
4392
|
-
else if (current
|
|
4644
|
+
else if (HydrationMarkup.isElementBoundaryEndMarker(current)) {
|
|
4393
4645
|
if (depth === 0) {
|
|
4394
4646
|
current.data = "";
|
|
4395
4647
|
return;
|
|
@@ -4400,7 +4652,9 @@ function skipToElementBoundaryEnd(walker, factories, startNode) {
|
|
|
4400
4652
|
}
|
|
4401
4653
|
current = walker.nextSibling();
|
|
4402
4654
|
}
|
|
4403
|
-
|
|
4655
|
+
const expected = expectedElementBoundaryEndMarker;
|
|
4656
|
+
const result = getHydrationDiagnostic().formatStructuralError(startNode, getHostName(startNode), expected);
|
|
4657
|
+
throw new HydrationTargetElementError(result.message, factories, startNode, result.expected, result.received);
|
|
4404
4658
|
}
|
|
4405
4659
|
/**
|
|
4406
4660
|
* Counts how many factories at the start of the array are host bindings (targetNodeId='h').
|
|
@@ -4638,7 +4892,7 @@ class HTMLView extends DefaultExecutionContext {
|
|
|
4638
4892
|
* @param context - The execution context to run the behaviors within.
|
|
4639
4893
|
*/
|
|
4640
4894
|
bind(source, context = this) {
|
|
4641
|
-
if (this.source === source) {
|
|
4895
|
+
if (this.source === source && this.context === context) {
|
|
4642
4896
|
return;
|
|
4643
4897
|
}
|
|
4644
4898
|
let behaviors = this.behaviors;
|
|
@@ -4732,11 +4986,23 @@ class HydrationBindingError extends Error {
|
|
|
4732
4986
|
* String representation of the HTML in the template that
|
|
4733
4987
|
* threw the binding error.
|
|
4734
4988
|
*/
|
|
4735
|
-
templateString
|
|
4989
|
+
templateString,
|
|
4990
|
+
/**
|
|
4991
|
+
* Structured description of the binding the hydration walk was
|
|
4992
|
+
* attempting to apply when the mismatch was detected.
|
|
4993
|
+
*/
|
|
4994
|
+
expected,
|
|
4995
|
+
/**
|
|
4996
|
+
* Structured description of the server-rendered DOM that was
|
|
4997
|
+
* encountered at the mismatch point.
|
|
4998
|
+
*/
|
|
4999
|
+
received) {
|
|
4736
5000
|
super(message);
|
|
4737
5001
|
this.factory = factory;
|
|
4738
5002
|
this.fragment = fragment;
|
|
4739
5003
|
this.templateString = templateString;
|
|
5004
|
+
this.expected = expected;
|
|
5005
|
+
this.received = received;
|
|
4740
5006
|
}
|
|
4741
5007
|
}
|
|
4742
5008
|
class HydrationView extends DefaultExecutionContext {
|
|
@@ -4822,13 +5088,12 @@ class HydrationView extends DefaultExecutionContext {
|
|
|
4822
5088
|
fragment.appendChild(end);
|
|
4823
5089
|
}
|
|
4824
5090
|
bind(source, context = this) {
|
|
4825
|
-
|
|
5091
|
+
if (this.source === source && this.context === context) {
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
4826
5094
|
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
4827
5095
|
this._hydrationStage = HydrationStage.hydrating;
|
|
4828
5096
|
}
|
|
4829
|
-
if (this.source === source) {
|
|
4830
|
-
return;
|
|
4831
|
-
}
|
|
4832
5097
|
let behaviors = this.behaviors;
|
|
4833
5098
|
if (behaviors === null) {
|
|
4834
5099
|
this.source = source;
|
|
@@ -4866,28 +5131,9 @@ class HydrationView extends DefaultExecutionContext {
|
|
|
4866
5131
|
if (typeof templateString !== "string") {
|
|
4867
5132
|
templateString = templateString.innerHTML;
|
|
4868
5133
|
}
|
|
4869
|
-
const
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
const factoryInfo = factory;
|
|
4873
|
-
// Build detailed error message
|
|
4874
|
-
const details = [
|
|
4875
|
-
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
4876
|
-
`\nMismatch Details:`,
|
|
4877
|
-
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
4878
|
-
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
4879
|
-
];
|
|
4880
|
-
if (factory.targetTagName) {
|
|
4881
|
-
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
4882
|
-
}
|
|
4883
|
-
if (factoryInfo.sourceAspect) {
|
|
4884
|
-
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
4885
|
-
}
|
|
4886
|
-
if (factoryInfo.aspectType !== undefined) {
|
|
4887
|
-
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
4888
|
-
}
|
|
4889
|
-
details.push(`\nThis usually means:`, ` 1. The server-rendered HTML doesn't match the client template`, ` 2. The hydration markers are missing or corrupted`, ` 3. The DOM structure was modified before hydration`, `\nTemplate: ${templateString.slice(0, 200)}${templateString.length > 200 ? "..." : ""}`);
|
|
4890
|
-
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
5134
|
+
const fragment = createRangeForNodes(this.firstChild, this.lastChild).cloneContents();
|
|
5135
|
+
const result = getHydrationDiagnostic().formatBindingMismatch(factory, this.firstChild, this.lastChild, getHostName(this.firstChild));
|
|
5136
|
+
throw new HydrationBindingError(result.message, factory, fragment, templateString, result.expected, result.received);
|
|
4891
5137
|
}
|
|
4892
5138
|
}
|
|
4893
5139
|
}
|
|
@@ -4955,6 +5201,21 @@ function bindWithPositioning(view, items, index, controller) {
|
|
|
4955
5201
|
function isCommentNode(node) {
|
|
4956
5202
|
return node.nodeType === Node.COMMENT_NODE;
|
|
4957
5203
|
}
|
|
5204
|
+
function removeNodeRange(first, last) {
|
|
5205
|
+
const parentNode = first.parentNode;
|
|
5206
|
+
if (parentNode === null) {
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
let current = first;
|
|
5210
|
+
while (current !== null) {
|
|
5211
|
+
const next = current.nextSibling;
|
|
5212
|
+
parentNode.removeChild(current);
|
|
5213
|
+
if (current === last) {
|
|
5214
|
+
break;
|
|
5215
|
+
}
|
|
5216
|
+
current = next;
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
4958
5219
|
class HydrationRepeatError extends Error {
|
|
4959
5220
|
constructor(
|
|
4960
5221
|
/**
|
|
@@ -5214,23 +5475,26 @@ class RepeatBehavior {
|
|
|
5214
5475
|
}
|
|
5215
5476
|
}
|
|
5216
5477
|
hydrateViews(template) {
|
|
5478
|
+
var _a;
|
|
5217
5479
|
if (!this.items) {
|
|
5218
5480
|
return;
|
|
5219
5481
|
}
|
|
5220
|
-
const
|
|
5221
|
-
|
|
5482
|
+
const items = this.items;
|
|
5483
|
+
const itemCount = items.length;
|
|
5484
|
+
const views = (this.views = new Array(itemCount));
|
|
5222
5485
|
// First pass: collect all repeat marker pairs by walking backward.
|
|
5223
|
-
// Each entry
|
|
5486
|
+
// Each entry tracks both the item content range and its SSR markers.
|
|
5224
5487
|
const itemRanges = [];
|
|
5225
5488
|
let current = this.location.previousSibling;
|
|
5226
5489
|
while (current !== null) {
|
|
5227
|
-
if (!isCommentNode(current) ||
|
|
5490
|
+
if (!isCommentNode(current) ||
|
|
5491
|
+
!HydrationMarkup.isRepeatViewEndMarker(current.data)) {
|
|
5228
5492
|
current = current.previousSibling;
|
|
5229
5493
|
continue;
|
|
5230
5494
|
}
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
const end =
|
|
5495
|
+
const endMarker = current;
|
|
5496
|
+
endMarker.data = "";
|
|
5497
|
+
const end = endMarker.previousSibling;
|
|
5234
5498
|
if (!end) {
|
|
5235
5499
|
throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": end should never be null.`);
|
|
5236
5500
|
}
|
|
@@ -5239,18 +5503,23 @@ class RepeatBehavior {
|
|
|
5239
5503
|
let depth = 0;
|
|
5240
5504
|
while (start !== null) {
|
|
5241
5505
|
if (isCommentNode(start)) {
|
|
5242
|
-
if (start.data
|
|
5506
|
+
if (HydrationMarkup.isRepeatViewEndMarker(start.data)) {
|
|
5243
5507
|
depth++;
|
|
5244
5508
|
}
|
|
5245
|
-
else if (start.data
|
|
5509
|
+
else if (HydrationMarkup.isRepeatViewStartMarker(start.data)) {
|
|
5246
5510
|
if (depth === 0) {
|
|
5247
5511
|
const startMarker = start;
|
|
5248
5512
|
startMarker.data = "";
|
|
5249
5513
|
current = startMarker.previousSibling;
|
|
5250
|
-
const itemStart = startMarker.nextSibling;
|
|
5514
|
+
const itemStart = (_a = startMarker.nextSibling) !== null && _a !== void 0 ? _a : endMarker;
|
|
5251
5515
|
// Empty item: start and end markers are adjacent.
|
|
5252
5516
|
const itemEnd = end === startMarker ? itemStart : end;
|
|
5253
|
-
itemRanges.push({
|
|
5517
|
+
itemRanges.push({
|
|
5518
|
+
start: itemStart,
|
|
5519
|
+
end: itemEnd,
|
|
5520
|
+
startMarker,
|
|
5521
|
+
endMarker,
|
|
5522
|
+
});
|
|
5254
5523
|
break;
|
|
5255
5524
|
}
|
|
5256
5525
|
depth--;
|
|
@@ -5266,11 +5535,22 @@ class RepeatBehavior {
|
|
|
5266
5535
|
// Reverse so index 0 = first SSR item.
|
|
5267
5536
|
itemRanges.reverse();
|
|
5268
5537
|
// Hydrate each SSR item at its correct index (0-based from start).
|
|
5269
|
-
|
|
5538
|
+
const hydrationCount = Math.min(itemRanges.length, itemCount);
|
|
5539
|
+
for (let i = 0; i < hydrationCount; i++) {
|
|
5270
5540
|
const { start, end } = itemRanges[i];
|
|
5271
5541
|
const view = template.hydrate(start, end);
|
|
5272
|
-
|
|
5273
|
-
this.bindView(view,
|
|
5542
|
+
views[i] = view;
|
|
5543
|
+
this.bindView(view, items, i, this.controller);
|
|
5544
|
+
}
|
|
5545
|
+
for (let i = hydrationCount; i < itemCount; i++) {
|
|
5546
|
+
const view = template.create();
|
|
5547
|
+
views[i] = view;
|
|
5548
|
+
this.bindView(view, items, i, this.controller);
|
|
5549
|
+
view.insertBefore(this.location);
|
|
5550
|
+
}
|
|
5551
|
+
for (let i = itemCount, ii = itemRanges.length; i < ii; i++) {
|
|
5552
|
+
const { startMarker, endMarker } = itemRanges[i];
|
|
5553
|
+
removeNodeRange(startMarker, endMarker);
|
|
5274
5554
|
}
|
|
5275
5555
|
}
|
|
5276
5556
|
}
|
|
@@ -6127,12 +6407,12 @@ class HTMLBindingDirective {
|
|
|
6127
6407
|
* @param dataBinding - The binding configuration to apply.
|
|
6128
6408
|
*/
|
|
6129
6409
|
constructor(dataBinding) {
|
|
6130
|
-
this.dataBinding = dataBinding;
|
|
6131
6410
|
this.updateTarget = null;
|
|
6132
6411
|
/**
|
|
6133
6412
|
* The type of aspect to target.
|
|
6134
6413
|
*/
|
|
6135
6414
|
this.aspectType = DOMAspect.content;
|
|
6415
|
+
this.dataBinding = dataBinding;
|
|
6136
6416
|
}
|
|
6137
6417
|
/**
|
|
6138
6418
|
* Creates HTML to be used within a template.
|
|
@@ -6780,11 +7060,10 @@ class RenderBehavior {
|
|
|
6780
7060
|
if (viewNodes) {
|
|
6781
7061
|
this.view = this.template.hydrate(viewNodes.first, viewNodes.last);
|
|
6782
7062
|
this.bindView(this.view);
|
|
7063
|
+
return;
|
|
6783
7064
|
}
|
|
6784
7065
|
}
|
|
6785
|
-
|
|
6786
|
-
this.refreshView();
|
|
6787
|
-
}
|
|
7066
|
+
this.refreshView();
|
|
6788
7067
|
}
|
|
6789
7068
|
/**
|
|
6790
7069
|
* Unbinds this behavior.
|
|
@@ -6901,6 +7180,32 @@ function instructionToTemplate(def) {
|
|
|
6901
7180
|
}
|
|
6902
7181
|
return def.template;
|
|
6903
7182
|
}
|
|
7183
|
+
function resolveTemplateBindingValue(result, dataBinding, source, context) {
|
|
7184
|
+
var _a;
|
|
7185
|
+
if (isString(result)) {
|
|
7186
|
+
return instructionToTemplate(getForInstance(dataBinding.evaluate(source, context), result));
|
|
7187
|
+
}
|
|
7188
|
+
if (result instanceof Node) {
|
|
7189
|
+
return (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
|
|
7190
|
+
}
|
|
7191
|
+
return result;
|
|
7192
|
+
}
|
|
7193
|
+
function adaptTemplateBinding(binding, dataBinding) {
|
|
7194
|
+
const evaluateTemplate = binding.evaluate;
|
|
7195
|
+
const adapter = Object.create(Object.getPrototypeOf(binding));
|
|
7196
|
+
for (const propertyName of Object.getOwnPropertyNames(binding)) {
|
|
7197
|
+
if (propertyName !== "evaluate") {
|
|
7198
|
+
Object.defineProperty(adapter, propertyName, Object.getOwnPropertyDescriptor(binding, propertyName));
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
Object.defineProperty(adapter, "evaluate", {
|
|
7202
|
+
configurable: true,
|
|
7203
|
+
enumerable: true,
|
|
7204
|
+
value: (source, context) => resolveTemplateBindingValue(evaluateTemplate(source, context), dataBinding, source, context),
|
|
7205
|
+
writable: true,
|
|
7206
|
+
});
|
|
7207
|
+
return adapter;
|
|
7208
|
+
}
|
|
6904
7209
|
function getByType(type, name) {
|
|
6905
7210
|
const entries = typeToInstructionLookup.get(type);
|
|
6906
7211
|
if (entries === void 0) {
|
|
@@ -7003,19 +7308,7 @@ function render(value, template) {
|
|
|
7003
7308
|
});
|
|
7004
7309
|
}
|
|
7005
7310
|
else if (template instanceof Binding) {
|
|
7006
|
-
|
|
7007
|
-
template.evaluate = (s, c) => {
|
|
7008
|
-
var _a;
|
|
7009
|
-
let result = evaluateTemplate(s, c);
|
|
7010
|
-
if (isString(result)) {
|
|
7011
|
-
result = instructionToTemplate(getForInstance(dataBinding.evaluate(s, c), result));
|
|
7012
|
-
}
|
|
7013
|
-
else if (result instanceof Node) {
|
|
7014
|
-
result = (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
|
|
7015
|
-
}
|
|
7016
|
-
return result;
|
|
7017
|
-
};
|
|
7018
|
-
templateBinding = template;
|
|
7311
|
+
templateBinding = adaptTemplateBinding(template, dataBinding);
|
|
7019
7312
|
}
|
|
7020
7313
|
else {
|
|
7021
7314
|
templateBinding = oneTime((s, c) => template);
|