@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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { DOMAspect } from "../dom.js";
|
|
2
|
+
import { aspectLabelAttribute, aspectLabelBooleanAttribute, aspectLabelContent, aspectLabelEvent, aspectLabelProperty, aspectLabelTokenList, aspectLabelUnknown, formatAspect, formatExpectedTarget, formatRichMismatchMessage, unknownHostName, } from "./messages.js";
|
|
3
|
+
const aspectLabelsByCode = Object.freeze({
|
|
4
|
+
[DOMAspect.attribute]: aspectLabelAttribute,
|
|
5
|
+
[DOMAspect.booleanAttribute]: aspectLabelBooleanAttribute,
|
|
6
|
+
[DOMAspect.property]: aspectLabelProperty,
|
|
7
|
+
[DOMAspect.content]: aspectLabelContent,
|
|
8
|
+
[DOMAspect.tokenList]: aspectLabelTokenList,
|
|
9
|
+
[DOMAspect.event]: aspectLabelEvent,
|
|
10
|
+
});
|
|
11
|
+
const defaultSnippetLength = 500;
|
|
12
|
+
function describeAspect(aspectType, sourceAspect) {
|
|
13
|
+
var _a;
|
|
14
|
+
const base = aspectType !== undefined
|
|
15
|
+
? ((_a = aspectLabelsByCode[aspectType]) !== null && _a !== void 0 ? _a : aspectLabelUnknown)
|
|
16
|
+
: aspectLabelUnknown;
|
|
17
|
+
return formatAspect(base, sourceAspect);
|
|
18
|
+
}
|
|
19
|
+
function describeExpectedTarget(factory) {
|
|
20
|
+
var _a;
|
|
21
|
+
const aspectType = factory.aspectType;
|
|
22
|
+
const sourceAspect = factory.sourceAspect;
|
|
23
|
+
return {
|
|
24
|
+
tagName: (_a = factory.targetTagName) !== null && _a !== void 0 ? _a : null,
|
|
25
|
+
aspect: describeAspect(aspectType, sourceAspect),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function stripEmptyComments(root) {
|
|
29
|
+
var _a;
|
|
30
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);
|
|
31
|
+
const empties = [];
|
|
32
|
+
let current;
|
|
33
|
+
while ((current = walker.nextNode()) !== null) {
|
|
34
|
+
if (current.data === "") {
|
|
35
|
+
empties.push(current);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const comment of empties) {
|
|
39
|
+
(_a = comment.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(comment);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function truncate(value, maxLength) {
|
|
43
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;
|
|
44
|
+
}
|
|
45
|
+
function serializeNodeForError(node, maxLength = defaultSnippetLength) {
|
|
46
|
+
const wrapper = document.createElement("div");
|
|
47
|
+
wrapper.appendChild(node.cloneNode(true));
|
|
48
|
+
stripEmptyComments(wrapper);
|
|
49
|
+
return truncate(wrapper.innerHTML.trim(), maxLength);
|
|
50
|
+
}
|
|
51
|
+
function serializeRangeForError(first, last, maxLength = defaultSnippetLength) {
|
|
52
|
+
const wrapper = document.createElement("div");
|
|
53
|
+
let current = first;
|
|
54
|
+
while (current !== null) {
|
|
55
|
+
wrapper.appendChild(current.cloneNode(true));
|
|
56
|
+
if (current === last) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
current = current.nextSibling;
|
|
60
|
+
}
|
|
61
|
+
stripEmptyComments(wrapper);
|
|
62
|
+
return truncate(wrapper.innerHTML.trim(), maxLength);
|
|
63
|
+
}
|
|
64
|
+
function formatMismatchMessage(hostName, expected, received) {
|
|
65
|
+
const host = (hostName !== null && hostName !== void 0 ? hostName : unknownHostName).toLowerCase();
|
|
66
|
+
const expectedText = typeof expected === "string"
|
|
67
|
+
? expected
|
|
68
|
+
: formatExpectedTarget(expected.tagName, expected.aspect);
|
|
69
|
+
return formatRichMismatchMessage(host, expectedText, received.html);
|
|
70
|
+
}
|
|
71
|
+
const richDiagnostic = {
|
|
72
|
+
formatBindingMismatch(factory, firstChild, lastChild, hostName) {
|
|
73
|
+
const expected = describeExpectedTarget(factory);
|
|
74
|
+
const received = {
|
|
75
|
+
html: serializeRangeForError(firstChild, lastChild),
|
|
76
|
+
};
|
|
77
|
+
const result = {
|
|
78
|
+
message: formatMismatchMessage(hostName, expected, received),
|
|
79
|
+
expected,
|
|
80
|
+
received,
|
|
81
|
+
};
|
|
82
|
+
return result;
|
|
83
|
+
},
|
|
84
|
+
formatStructuralError(node, hostName, expectedDescription) {
|
|
85
|
+
const received = {
|
|
86
|
+
html: serializeNodeForError(node),
|
|
87
|
+
};
|
|
88
|
+
const result = {
|
|
89
|
+
message: formatMismatchMessage(hostName, expectedDescription, received),
|
|
90
|
+
expected: expectedDescription,
|
|
91
|
+
received,
|
|
92
|
+
};
|
|
93
|
+
return result;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Returns a {@link HydrationDebugger} that, when supplied to
|
|
98
|
+
* `enableHydration({ debugger })`, installs the rich hydration mismatch
|
|
99
|
+
* formatter: a single-line "Expected … / Received …" message plus an HTML
|
|
100
|
+
* snippet of the SSR DOM and structured `expected`/`received` fields on
|
|
101
|
+
* the thrown error (both `HydrationBindingError` and
|
|
102
|
+
* `HydrationTargetElementError`).
|
|
103
|
+
*
|
|
104
|
+
* Without the debugger, hydration errors emit only a minimal one-line
|
|
105
|
+
* message pointing at this function — keeping the runtime hydration cost
|
|
106
|
+
* small for production bundles that do not need rich diagnostics.
|
|
107
|
+
*
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
export function hydrationDebugger() {
|
|
111
|
+
return { diagnostic: richDiagnostic };
|
|
112
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized hydration mismatch message strings used by both the default
|
|
3
|
+
* minimal `HydrationDiagnostic` and the opt-in `hydrationDebugger` rich
|
|
4
|
+
* formatter, and by the structural-error throw sites in
|
|
5
|
+
* `target-builder.ts`.
|
|
6
|
+
*
|
|
7
|
+
* Static text is exported as a plain `const`; interpolated text is exported
|
|
8
|
+
* as a small builder function. Plain `export const` declarations tree-shake
|
|
9
|
+
* better than frozen-object property bags, so unused strings drop out of
|
|
10
|
+
* bundles cleanly.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Fallback host tag name used when a hydration mismatch is detected on a
|
|
14
|
+
* node that is not inside a shadow root.
|
|
15
|
+
*/
|
|
16
|
+
export const unknownHostName = "unknown";
|
|
17
|
+
// -- Aspect labels (consumed by the opt-in hydrationDebugger) ----------------
|
|
18
|
+
export const aspectLabelAttribute = "attribute";
|
|
19
|
+
export const aspectLabelBooleanAttribute = "boolean attribute";
|
|
20
|
+
export const aspectLabelProperty = "property";
|
|
21
|
+
export const aspectLabelContent = "content";
|
|
22
|
+
export const aspectLabelTokenList = "token list";
|
|
23
|
+
export const aspectLabelEvent = "event";
|
|
24
|
+
/** Fallback used when the aspectType is missing or unknown. */
|
|
25
|
+
export const aspectLabelUnknown = "binding";
|
|
26
|
+
/**
|
|
27
|
+
* Combines an aspect label with the original source aspect identifier from
|
|
28
|
+
* markup (e.g. `"property className"`). Returns the bare label when no
|
|
29
|
+
* source aspect was captured.
|
|
30
|
+
*/
|
|
31
|
+
export function formatAspect(label, sourceAspect) {
|
|
32
|
+
return sourceAspect ? `${label} \`${sourceAspect}\`` : label;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Formats the "Expected" half of the rich hydration mismatch message, e.g.
|
|
36
|
+
* `"<span> with content binding"` or `"content binding"` when no tag is
|
|
37
|
+
* associated with the binding factory.
|
|
38
|
+
*/
|
|
39
|
+
export function formatExpectedTarget(tagName, aspect) {
|
|
40
|
+
return tagName
|
|
41
|
+
? `<${tagName.toLowerCase()}> with ${aspect} binding`
|
|
42
|
+
: `${aspect} binding`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Default minimal hydration mismatch message used when the
|
|
46
|
+
* `hydrationDebugger` opt-in is not installed. The optional `detail` string
|
|
47
|
+
* carries the structural expectation surfaced by `target-builder.ts`.
|
|
48
|
+
*/
|
|
49
|
+
export function formatDefaultMismatchMessage(hostName, detail) {
|
|
50
|
+
const suffix = detail ? `: ${detail}` : "";
|
|
51
|
+
return (`Hydration mismatch in <${hostName}>${suffix}. Install ` +
|
|
52
|
+
`hydrationDebugger() from "@microsoft/fast-element/hydration.js" and ` +
|
|
53
|
+
`pass it as enableHydration({ debugger: hydrationDebugger() }) for an ` +
|
|
54
|
+
`"Expected / Received" report including the SSR HTML snippet.`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Rich `Expected … / Received …` hydration mismatch message format produced
|
|
58
|
+
* by the `hydrationDebugger` formatter.
|
|
59
|
+
*/
|
|
60
|
+
export function formatRichMismatchMessage(hostName, expectedText, receivedHtml) {
|
|
61
|
+
return (`Hydration mismatch in <${hostName}>.\n` +
|
|
62
|
+
` Expected: ${expectedText}\n` +
|
|
63
|
+
` Received: ${receivedHtml}`);
|
|
64
|
+
}
|
|
65
|
+
// -- Structural expectations (used by target-builder.ts throw sites) ---------
|
|
66
|
+
export const expectedContentAfterStartMarker = "content following `<!--fe:b-->` content binding marker";
|
|
67
|
+
export const expectedContentEndMarker = "matching `<!--fe:/b-->` content binding close marker";
|
|
68
|
+
export const expectedElementBoundaryEndMarker = "matching `<!--fe:/e-->` element boundary close marker";
|
|
69
|
+
/**
|
|
70
|
+
* Builds the "no more attribute bindings" structural expectation message
|
|
71
|
+
* thrown when an element's `data-fe` count claims more attribute bindings
|
|
72
|
+
* than the compiled template defines.
|
|
73
|
+
*/
|
|
74
|
+
export function formatNoMoreAttributeBindings(factoryCount) {
|
|
75
|
+
return `no more attribute bindings (template defines ${factoryCount})`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Builds the "no more content bindings" structural expectation message
|
|
79
|
+
* thrown when the SSR DOM contains more content binding markers than the
|
|
80
|
+
* compiled template defines.
|
|
81
|
+
*/
|
|
82
|
+
export function formatNoMoreContentBindings(factoryCount) {
|
|
83
|
+
return `no more content bindings (template defines ${factoryCount})`;
|
|
84
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { HydrationMarkup } from "../components/hydration.js";
|
|
2
|
+
import { getHostName, getHydrationDiagnostic, } from "./diagnostics.js";
|
|
3
|
+
import { expectedContentAfterStartMarker, expectedContentEndMarker, expectedElementBoundaryEndMarker, formatNoMoreAttributeBindings, formatNoMoreContentBindings, } from "./messages.js";
|
|
2
4
|
export class HydrationTargetElementError extends Error {
|
|
3
5
|
constructor(
|
|
4
6
|
/**
|
|
@@ -12,10 +14,24 @@ export class HydrationTargetElementError extends Error {
|
|
|
12
14
|
/**
|
|
13
15
|
* The node to target factory.
|
|
14
16
|
*/
|
|
15
|
-
node
|
|
17
|
+
node,
|
|
18
|
+
/**
|
|
19
|
+
* Structured description of the binding the hydration walk was
|
|
20
|
+
* attempting to apply when the mismatch was detected. Free-form
|
|
21
|
+
* string for structural errors that do not correspond to a single
|
|
22
|
+
* binding factory.
|
|
23
|
+
*/
|
|
24
|
+
expected,
|
|
25
|
+
/**
|
|
26
|
+
* Structured description of the server-rendered DOM that was
|
|
27
|
+
* encountered at the mismatch point.
|
|
28
|
+
*/
|
|
29
|
+
received) {
|
|
16
30
|
super(message);
|
|
17
31
|
this.factories = factories;
|
|
18
32
|
this.node = node;
|
|
33
|
+
this.expected = expected;
|
|
34
|
+
this.received = received;
|
|
19
35
|
}
|
|
20
36
|
}
|
|
21
37
|
function isComment(node) {
|
|
@@ -64,7 +80,6 @@ export function createRangeForNodes(first, last) {
|
|
|
64
80
|
* @returns - A {@link ViewBehaviorTargets } object for the factories in the view.
|
|
65
81
|
*/
|
|
66
82
|
export function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
67
|
-
var _a, _b;
|
|
68
83
|
const range = createRangeForNodes(firstNode, lastNode);
|
|
69
84
|
const treeRoot = range.commonAncestorContainer;
|
|
70
85
|
const walker = document.createTreeWalker(treeRoot, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_COMMENT + NodeFilter.SHOW_TEXT, {
|
|
@@ -77,36 +92,63 @@ export function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
|
77
92
|
const targets = {};
|
|
78
93
|
const boundaries = {};
|
|
79
94
|
// Sequential factory pointer — skip host bindings at the start
|
|
80
|
-
|
|
95
|
+
const hydrationIndexOffset = getHydrationIndexOffset(factories);
|
|
96
|
+
let factoryPointer = hydrationIndexOffset;
|
|
81
97
|
let node = (walker.currentNode = firstNode);
|
|
82
98
|
while (node !== null) {
|
|
83
99
|
switch (node.nodeType) {
|
|
84
100
|
case Node.ELEMENT_NODE: {
|
|
85
|
-
const
|
|
101
|
+
const element = node;
|
|
102
|
+
const legacyIndices = HydrationMarkup.parseLegacyAttributeBindingIndices(element);
|
|
103
|
+
if (legacyIndices !== null) {
|
|
104
|
+
for (const index of legacyIndices) {
|
|
105
|
+
const factoryIndex = index + hydrationIndexOffset;
|
|
106
|
+
const factory = factories[factoryIndex];
|
|
107
|
+
if (!factory) {
|
|
108
|
+
const expected = formatNoMoreAttributeBindings(factories.length);
|
|
109
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
110
|
+
throw new HydrationTargetElementError(result.message, factories, element, result.expected, result.received);
|
|
111
|
+
}
|
|
112
|
+
targetFactory(factory, node, targets);
|
|
113
|
+
factoryPointer = Math.max(factoryPointer, factoryIndex + 1);
|
|
114
|
+
}
|
|
115
|
+
HydrationMarkup.removeLegacyAttributeBindingMarkers(element);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
const count = HydrationMarkup.parseAttributeBindingCount(element);
|
|
86
119
|
if (count !== null) {
|
|
87
120
|
for (let i = 0; i < count; i++) {
|
|
88
121
|
const factory = factories[factoryPointer++];
|
|
89
122
|
if (!factory) {
|
|
90
|
-
|
|
123
|
+
const expected = formatNoMoreAttributeBindings(factories.length);
|
|
124
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
125
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
91
126
|
}
|
|
92
127
|
targetFactory(factory, node, targets);
|
|
93
128
|
}
|
|
94
|
-
|
|
129
|
+
element.removeAttribute(HydrationMarkup.attributeMarkerName);
|
|
95
130
|
}
|
|
96
131
|
break;
|
|
97
132
|
}
|
|
98
133
|
case Node.COMMENT_NODE: {
|
|
99
134
|
const data = node.data;
|
|
100
|
-
if (
|
|
135
|
+
if (HydrationMarkup.isElementBoundaryStartMarker(node)) {
|
|
101
136
|
// Element boundary — clear start marker and skip subtree
|
|
102
137
|
node.data = "";
|
|
103
138
|
skipToElementBoundaryEnd(walker, factories, node);
|
|
104
139
|
}
|
|
105
|
-
else if (data
|
|
140
|
+
else if (HydrationMarkup.isContentBindingStartMarker(data)) {
|
|
106
141
|
// Content binding — consume next factory
|
|
107
|
-
const
|
|
142
|
+
const legacyIndex = HydrationMarkup.parseLegacyContentBindingStartIndex(data);
|
|
143
|
+
const factoryIndex = legacyIndex === null
|
|
144
|
+
? factoryPointer++
|
|
145
|
+
: legacyIndex + hydrationIndexOffset;
|
|
146
|
+
const factory = factories[factoryIndex];
|
|
147
|
+
factoryPointer = Math.max(factoryPointer, factoryIndex + 1);
|
|
108
148
|
if (!factory) {
|
|
109
|
-
|
|
149
|
+
const expected = formatNoMoreContentBindings(factories.length);
|
|
150
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
151
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
110
152
|
}
|
|
111
153
|
targetContentBinding(node, walker, factory, factories, targets, boundaries);
|
|
112
154
|
}
|
|
@@ -119,22 +161,23 @@ export function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
|
119
161
|
return { targets, boundaries };
|
|
120
162
|
}
|
|
121
163
|
function targetContentBinding(node, walker, factory, factories, targets, boundaries) {
|
|
122
|
-
var _a, _b, _c, _d;
|
|
123
164
|
const nodes = [];
|
|
124
165
|
let current = walker.nextSibling();
|
|
125
166
|
node.data = "";
|
|
126
167
|
if (current === null) {
|
|
127
|
-
|
|
168
|
+
const expected = expectedContentAfterStartMarker;
|
|
169
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
170
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
128
171
|
}
|
|
129
172
|
const first = current;
|
|
130
173
|
// Balanced depth counting for nested content markers
|
|
131
174
|
let depth = 0;
|
|
132
175
|
while (current !== null) {
|
|
133
176
|
if (isComment(current)) {
|
|
134
|
-
if (current.data
|
|
177
|
+
if (HydrationMarkup.isContentBindingStartMarker(current.data)) {
|
|
135
178
|
depth++;
|
|
136
179
|
}
|
|
137
|
-
else if (current.data
|
|
180
|
+
else if (HydrationMarkup.isContentBindingEndMarker(current.data)) {
|
|
138
181
|
if (depth === 0)
|
|
139
182
|
break;
|
|
140
183
|
depth--;
|
|
@@ -144,7 +187,9 @@ function targetContentBinding(node, walker, factory, factories, targets, boundar
|
|
|
144
187
|
current = walker.nextSibling();
|
|
145
188
|
}
|
|
146
189
|
if (current === null) {
|
|
147
|
-
|
|
190
|
+
const expected = expectedContentEndMarker;
|
|
191
|
+
const result = getHydrationDiagnostic().formatStructuralError(node, getHostName(node), expected);
|
|
192
|
+
throw new HydrationTargetElementError(result.message, factories, node, result.expected, result.received);
|
|
148
193
|
}
|
|
149
194
|
current.data = "";
|
|
150
195
|
if (nodes.length === 1 && isText(nodes[0])) {
|
|
@@ -170,16 +215,15 @@ function targetContentBinding(node, walker, factory, factories, targets, boundar
|
|
|
170
215
|
* depth counting to handle nested element boundaries correctly.
|
|
171
216
|
*/
|
|
172
217
|
function skipToElementBoundaryEnd(walker, factories, startNode) {
|
|
173
|
-
var _a, _b;
|
|
174
218
|
let depth = 0;
|
|
175
219
|
let current = walker.nextSibling();
|
|
176
220
|
while (current !== null) {
|
|
177
221
|
if (isComment(current)) {
|
|
178
|
-
if (current
|
|
222
|
+
if (HydrationMarkup.isElementBoundaryStartMarker(current)) {
|
|
179
223
|
current.data = "";
|
|
180
224
|
depth++;
|
|
181
225
|
}
|
|
182
|
-
else if (current
|
|
226
|
+
else if (HydrationMarkup.isElementBoundaryEndMarker(current)) {
|
|
183
227
|
if (depth === 0) {
|
|
184
228
|
current.data = "";
|
|
185
229
|
return;
|
|
@@ -190,7 +234,9 @@ function skipToElementBoundaryEnd(walker, factories, startNode) {
|
|
|
190
234
|
}
|
|
191
235
|
current = walker.nextSibling();
|
|
192
236
|
}
|
|
193
|
-
|
|
237
|
+
const expected = expectedElementBoundaryEndMarker;
|
|
238
|
+
const result = getHydrationDiagnostic().formatStructuralError(startNode, getHostName(startNode), expected);
|
|
239
|
+
throw new HydrationTargetElementError(result.message, factories, startNode, result.expected, result.received);
|
|
194
240
|
}
|
|
195
241
|
/**
|
|
196
242
|
* Counts how many factories at the start of the array are host bindings (targetNodeId='h').
|
package/dist/esm/hydration.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export { deferHydrationAttribute, enableHydration, } from "./components/enable-hydration.js";
|
|
1
|
+
export { deferHydrationAttribute, enableHydration, StopHydration, } from "./components/enable-hydration.js";
|
|
2
2
|
export { isHydratable } from "./components/hydration.js";
|
|
3
3
|
export { HydrationTracker } from "./components/hydration-tracker.js";
|
|
4
|
+
export { DOMPolicy, } from "./dom-policy.js";
|
|
5
|
+
export { hydrationDebugger } from "./hydration/hydration-debugger.js";
|
|
4
6
|
export { HydrationBindingError, HydrationStage, } from "./templating/hydration-view.js";
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core APIs for building standards-based Web Components with FAST Element.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
1
5
|
// Kernel
|
|
2
6
|
// Components
|
|
3
7
|
export { AttributeConfiguration, AttributeDefinition, attr, booleanConverter, nullableBooleanConverter, nullableNumberConverter, } from "./attr.js";
|
|
@@ -10,7 +14,7 @@ export { Signal, signal } from "./binding/signal.js";
|
|
|
10
14
|
export { TwoWaySettings, twoWay, } from "./binding/two-way.js";
|
|
11
15
|
export { ElementController, Stages, } from "./components/element-controller.js";
|
|
12
16
|
export { FASTElementDefinition, fastElementRegistry, } from "./components/fast-definitions.js";
|
|
13
|
-
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
17
|
+
export { customElement, FASTElement, } from "./components/fast-element.js";
|
|
14
18
|
export { enableDebug } from "./debug.js";
|
|
15
19
|
// Directives
|
|
16
20
|
export { ChildrenDirective, children, } from "./directives/children.js";
|
|
@@ -19,7 +23,7 @@ export { RefDirective, ref } from "./directives/ref.js";
|
|
|
19
23
|
export { RepeatBehavior, RepeatDirective, repeat, } from "./directives/repeat.js";
|
|
20
24
|
export { SlottedDirective, slotted, } from "./directives/slotted.js";
|
|
21
25
|
export { when } from "./directives/when.js";
|
|
22
|
-
export
|
|
26
|
+
export { DOM, DOMAspect } from "./dom.js";
|
|
23
27
|
export { DOMPolicy, } from "./dom-policy.js";
|
|
24
28
|
export { ArrayObserver, lengthOf, Sort, Splice, SpliceStrategy, SpliceStrategySupport, sortedCount, } from "./observation/arrays.js";
|
|
25
29
|
// Observation
|
package/dist/esm/interfaces.js
CHANGED
|
@@ -18,6 +18,7 @@ export 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";
|
package/dist/esm/metadata.js
CHANGED
|
@@ -34,19 +34,13 @@ export const Metadata = Object.freeze({
|
|
|
34
34
|
* @param Type - The type to get the metadata for.
|
|
35
35
|
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
36
36
|
*/
|
|
37
|
-
getDesignParamTypes: (Type) => {
|
|
38
|
-
var _a;
|
|
39
|
-
return ((_a = Reflect.getOwnMetadata(designParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
|
|
40
|
-
},
|
|
37
|
+
getDesignParamTypes: (Type) => { var _a; return ((_a = Reflect.getOwnMetadata(designParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray); },
|
|
41
38
|
/**
|
|
42
39
|
* Gets the "annotation:paramtypes" metadata for the specified type.
|
|
43
40
|
* @param Type - The type to get the metadata for.
|
|
44
41
|
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
45
42
|
*/
|
|
46
|
-
getAnnotationParamTypes: (Type) => {
|
|
47
|
-
var _a;
|
|
48
|
-
return ((_a = Reflect.getOwnMetadata(annotationParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
|
|
49
|
-
},
|
|
43
|
+
getAnnotationParamTypes: (Type) => { var _a; return ((_a = Reflect.getOwnMetadata(annotationParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray); },
|
|
50
44
|
/**
|
|
51
45
|
* Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
|
|
52
46
|
* an empty, mutable metadata array is created and added.
|
|
@@ -138,12 +138,10 @@ export class PropertyChangeNotifier {
|
|
|
138
138
|
var _a, _b;
|
|
139
139
|
let subscribers;
|
|
140
140
|
if (propertyToWatch) {
|
|
141
|
-
subscribers =
|
|
142
|
-
(_a = this.subscribers[propertyToWatch]) !== null && _a !== void 0 ? _a : (this.subscribers[propertyToWatch] = new SubscriberSet(this.subject));
|
|
141
|
+
subscribers = (_a = this.subscribers[propertyToWatch]) !== null && _a !== void 0 ? _a : (this.subscribers[propertyToWatch] = new SubscriberSet(this.subject));
|
|
143
142
|
}
|
|
144
143
|
else {
|
|
145
|
-
subscribers =
|
|
146
|
-
(_b = this.subjectSubscribers) !== null && _b !== void 0 ? _b : (this.subjectSubscribers = new SubscriberSet(this.subject));
|
|
144
|
+
subscribers = (_b = this.subjectSubscribers) !== null && _b !== void 0 ? _b : (this.subjectSubscribers = new SubscriberSet(this.subject));
|
|
147
145
|
}
|
|
148
146
|
subscribers.subscribe(subscriber);
|
|
149
147
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FASTElementDefinition, fastElementRegistry, } from "./components/fast-definitions.js";
|
|
@@ -158,12 +158,12 @@ export class HTMLBindingDirective {
|
|
|
158
158
|
* @param dataBinding - The binding configuration to apply.
|
|
159
159
|
*/
|
|
160
160
|
constructor(dataBinding) {
|
|
161
|
-
this.dataBinding = dataBinding;
|
|
162
161
|
this.updateTarget = null;
|
|
163
162
|
/**
|
|
164
163
|
* The type of aspect to target.
|
|
165
164
|
*/
|
|
166
165
|
this.aspectType = DOMAspect.content;
|
|
166
|
+
this.dataBinding = dataBinding;
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
169
|
* Creates HTML to be used within a template.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import { Hydratable } from "../components/hydration.js";
|
|
3
|
+
import { getHostName, getHydrationDiagnostic, } from "../hydration/diagnostics.js";
|
|
3
4
|
import { buildViewBindingTargets, createRangeForNodes, HydrationTargetElementError, targetFactory, } from "../hydration/target-builder.js";
|
|
4
5
|
import { SourceLifetime } from "../observation/observable.js";
|
|
5
6
|
import { makeSerializationNoop } from "../platform.js";
|
|
@@ -30,11 +31,23 @@ export class HydrationBindingError extends Error {
|
|
|
30
31
|
* String representation of the HTML in the template that
|
|
31
32
|
* threw the binding error.
|
|
32
33
|
*/
|
|
33
|
-
templateString
|
|
34
|
+
templateString,
|
|
35
|
+
/**
|
|
36
|
+
* Structured description of the binding the hydration walk was
|
|
37
|
+
* attempting to apply when the mismatch was detected.
|
|
38
|
+
*/
|
|
39
|
+
expected,
|
|
40
|
+
/**
|
|
41
|
+
* Structured description of the server-rendered DOM that was
|
|
42
|
+
* encountered at the mismatch point.
|
|
43
|
+
*/
|
|
44
|
+
received) {
|
|
34
45
|
super(message);
|
|
35
46
|
this.factory = factory;
|
|
36
47
|
this.fragment = fragment;
|
|
37
48
|
this.templateString = templateString;
|
|
49
|
+
this.expected = expected;
|
|
50
|
+
this.received = received;
|
|
38
51
|
}
|
|
39
52
|
}
|
|
40
53
|
export class HydrationView extends DefaultExecutionContext {
|
|
@@ -120,13 +133,12 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
120
133
|
fragment.appendChild(end);
|
|
121
134
|
}
|
|
122
135
|
bind(source, context = this) {
|
|
123
|
-
|
|
136
|
+
if (this.source === source && this.context === context) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
124
139
|
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
125
140
|
this._hydrationStage = HydrationStage.hydrating;
|
|
126
141
|
}
|
|
127
|
-
if (this.source === source) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
142
|
let behaviors = this.behaviors;
|
|
131
143
|
if (behaviors === null) {
|
|
132
144
|
this.source = source;
|
|
@@ -164,28 +176,9 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
164
176
|
if (typeof templateString !== "string") {
|
|
165
177
|
templateString = templateString.innerHTML;
|
|
166
178
|
}
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const factoryInfo = factory;
|
|
171
|
-
// Build detailed error message
|
|
172
|
-
const details = [
|
|
173
|
-
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
174
|
-
`\nMismatch Details:`,
|
|
175
|
-
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
176
|
-
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
177
|
-
];
|
|
178
|
-
if (factory.targetTagName) {
|
|
179
|
-
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
180
|
-
}
|
|
181
|
-
if (factoryInfo.sourceAspect) {
|
|
182
|
-
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
183
|
-
}
|
|
184
|
-
if (factoryInfo.aspectType !== undefined) {
|
|
185
|
-
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
186
|
-
}
|
|
187
|
-
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 ? "..." : ""}`);
|
|
188
|
-
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
179
|
+
const fragment = createRangeForNodes(this.firstChild, this.lastChild).cloneContents();
|
|
180
|
+
const result = getHydrationDiagnostic().formatBindingMismatch(factory, this.firstChild, this.lastChild, getHostName(this.firstChild));
|
|
181
|
+
throw new HydrationBindingError(result.message, factory, fragment, templateString, result.expected, result.received);
|
|
189
182
|
}
|
|
190
183
|
}
|
|
191
184
|
}
|
|
@@ -4,11 +4,12 @@ import { oneTime } from "../binding/one-time.js";
|
|
|
4
4
|
import { oneWay } from "../binding/one-way.js";
|
|
5
5
|
import { FASTElementDefinition } from "../components/fast-definitions.js";
|
|
6
6
|
import { isHydratable } from "../components/hydration.js";
|
|
7
|
-
import { isFunction, isString } from "../interfaces.js";
|
|
7
|
+
import { isFunction, isString, Message } from "../interfaces.js";
|
|
8
|
+
import { FAST } from "../platform.js";
|
|
8
9
|
import { HTMLDirective, } from "./html-directive.js";
|
|
10
|
+
import { HydrationStage } from "./hydration-view.js";
|
|
9
11
|
import { Markup } from "./markup.js";
|
|
10
12
|
import { html, ViewTemplate, } from "./template.js";
|
|
11
|
-
import { HydrationStage } from "./hydration-view.js";
|
|
12
13
|
/**
|
|
13
14
|
* A Behavior that enables advanced rendering.
|
|
14
15
|
* @public
|
|
@@ -45,11 +46,10 @@ export class RenderBehavior {
|
|
|
45
46
|
if (viewNodes) {
|
|
46
47
|
this.view = this.template.hydrate(viewNodes.first, viewNodes.last);
|
|
47
48
|
this.bindView(this.view);
|
|
49
|
+
return;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
|
|
51
|
-
this.refreshView();
|
|
52
|
-
}
|
|
52
|
+
this.refreshView();
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Unbinds this behavior.
|
|
@@ -172,6 +172,32 @@ function instructionToTemplate(def) {
|
|
|
172
172
|
}
|
|
173
173
|
return def.template;
|
|
174
174
|
}
|
|
175
|
+
function resolveTemplateBindingValue(result, dataBinding, source, context) {
|
|
176
|
+
var _a;
|
|
177
|
+
if (isString(result)) {
|
|
178
|
+
return instructionToTemplate(getForInstance(dataBinding.evaluate(source, context), result));
|
|
179
|
+
}
|
|
180
|
+
if (result instanceof Node) {
|
|
181
|
+
return (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
function adaptTemplateBinding(binding, dataBinding) {
|
|
186
|
+
const evaluateTemplate = binding.evaluate;
|
|
187
|
+
const adapter = Object.create(Object.getPrototypeOf(binding));
|
|
188
|
+
for (const propertyName of Object.getOwnPropertyNames(binding)) {
|
|
189
|
+
if (propertyName !== "evaluate") {
|
|
190
|
+
Object.defineProperty(adapter, propertyName, Object.getOwnPropertyDescriptor(binding, propertyName));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
Object.defineProperty(adapter, "evaluate", {
|
|
194
|
+
configurable: true,
|
|
195
|
+
enumerable: true,
|
|
196
|
+
value: (source, context) => resolveTemplateBindingValue(evaluateTemplate(source, context), dataBinding, source, context),
|
|
197
|
+
writable: true,
|
|
198
|
+
});
|
|
199
|
+
return adapter;
|
|
200
|
+
}
|
|
175
201
|
function createElementTemplate(tagName, options) {
|
|
176
202
|
const markup = [];
|
|
177
203
|
const values = [];
|
|
@@ -251,6 +277,13 @@ function register(optionsOrInstruction) {
|
|
|
251
277
|
const instruction = instanceOf(optionsOrInstruction)
|
|
252
278
|
? optionsOrInstruction
|
|
253
279
|
: create(optionsOrInstruction);
|
|
280
|
+
if (lookup[instruction.name] !== void 0) {
|
|
281
|
+
const typeName = instruction.type.name || "(anonymous)";
|
|
282
|
+
FAST.warn(Message.duplicateRenderInstruction, {
|
|
283
|
+
type: typeName,
|
|
284
|
+
name: instruction.name,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
254
287
|
return (lookup[instruction.name] = instruction);
|
|
255
288
|
}
|
|
256
289
|
function getByType(type, name) {
|
|
@@ -425,19 +458,7 @@ export function render(value, template) {
|
|
|
425
458
|
});
|
|
426
459
|
}
|
|
427
460
|
else if (template instanceof Binding) {
|
|
428
|
-
|
|
429
|
-
template.evaluate = (s, c) => {
|
|
430
|
-
var _a;
|
|
431
|
-
let result = evaluateTemplate(s, c);
|
|
432
|
-
if (isString(result)) {
|
|
433
|
-
result = instructionToTemplate(getForInstance(dataBinding.evaluate(s, c), result));
|
|
434
|
-
}
|
|
435
|
-
else if (result instanceof Node) {
|
|
436
|
-
result = (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
|
|
437
|
-
}
|
|
438
|
-
return result;
|
|
439
|
-
};
|
|
440
|
-
templateBinding = template;
|
|
461
|
+
templateBinding = adaptTemplateBinding(template, dataBinding);
|
|
441
462
|
}
|
|
442
463
|
else {
|
|
443
464
|
templateBinding = oneTime((s, c) => template);
|