@microsoft/fast-element 2.10.4 → 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 +52 -2
- package/README.md +244 -1
- package/dist/arrays/arrays.api.json +2621 -0
- package/dist/context/context.api.json +13 -13
- package/dist/declarative/declarative.api.json +8483 -0
- package/dist/di/di.api.json +16 -16
- package/dist/dts/__test__/helpers.d.ts +6 -0
- package/dist/dts/array-observer.d.ts +2 -0
- package/dist/dts/arrays.d.ts +2 -0
- package/dist/dts/attr.d.ts +1 -0
- package/dist/dts/binding/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 +6 -6
- package/dist/dts/binding/two-way.d.ts +2 -1
- package/dist/dts/binding.d.ts +7 -0
- package/dist/dts/components/attributes.d.ts +1 -4
- package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
- package/dist/dts/components/element-controller.d.ts +80 -114
- package/dist/dts/components/element-hydration.d.ts +1 -1
- package/dist/dts/components/enable-hydration.d.ts +54 -0
- package/dist/dts/components/fast-definitions.d.ts +98 -46
- package/dist/dts/components/fast-element.d.ts +43 -16
- package/dist/dts/components/hydration-tracker.d.ts +83 -0
- package/dist/dts/components/hydration.d.ts +23 -53
- package/dist/dts/components/schema.d.ts +205 -0
- package/dist/dts/context.d.ts +13 -13
- package/dist/dts/css.d.ts +3 -0
- package/dist/dts/debug.d.ts +5 -1
- package/dist/dts/declarative/attribute-map.d.ts +58 -0
- package/dist/dts/declarative/debug.d.ts +4 -0
- package/dist/dts/declarative/index.d.ts +14 -0
- package/dist/dts/declarative/interfaces.d.ts +8 -0
- package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
- package/dist/dts/declarative/observer-map.d.ts +89 -0
- package/dist/dts/declarative/runtime.d.ts +5 -0
- package/dist/dts/declarative/syntax.d.ts +21 -0
- package/dist/dts/declarative/template-bridge.d.ts +33 -0
- package/dist/dts/declarative/template-parser.d.ts +98 -0
- package/dist/dts/declarative/template.d.ts +10 -0
- package/dist/dts/declarative/utilities.d.ts +358 -0
- package/dist/dts/di/di.d.ts +7 -7
- package/dist/dts/directives/children.d.ts +2 -0
- package/dist/dts/directives/node-observation.d.ts +2 -0
- package/dist/dts/directives/ref.d.ts +2 -0
- package/dist/dts/directives/repeat.d.ts +4 -0
- package/dist/dts/directives/slotted.d.ts +2 -0
- package/dist/dts/directives/when.d.ts +3 -0
- package/dist/dts/dom-policy.d.ts +23 -5
- package/dist/dts/dom.d.ts +4 -16
- package/dist/dts/html.d.ts +5 -0
- 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/runtime.d.ts +7 -0
- package/dist/dts/hydration/target-builder.d.ts +40 -12
- package/dist/dts/hydration.d.ts +18 -0
- package/dist/dts/index.d.ts +42 -42
- package/dist/dts/index.debug.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +2 -49
- package/dist/dts/observable.d.ts +3 -6
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.d.ts +3 -3
- package/dist/dts/observation/update-queue.d.ts +1 -1
- package/dist/dts/platform.d.ts +45 -8
- package/dist/dts/registry.d.ts +1 -0
- package/dist/dts/render.d.ts +7 -0
- package/dist/dts/schema.d.ts +1 -0
- package/dist/dts/state/exports.d.ts +1 -1
- package/dist/dts/state/state.d.ts +2 -2
- package/dist/dts/styles/css-directive.d.ts +5 -12
- package/dist/dts/styles/css.d.ts +5 -7
- package/dist/dts/styles/element-styles.d.ts +0 -10
- package/dist/dts/styles.d.ts +6 -0
- package/dist/dts/templating/compiler.d.ts +1 -1
- package/dist/dts/templating/html-binding-directive.d.ts +10 -2
- package/dist/dts/templating/html-directive.d.ts +19 -1
- package/dist/dts/templating/hydration-view.d.ts +130 -0
- package/dist/dts/templating/render.d.ts +1 -1
- package/dist/dts/templating/repeat.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +15 -7
- package/dist/dts/templating/view.d.ts +25 -102
- package/dist/dts/templating.d.ts +10 -0
- package/dist/dts/testing/exports.d.ts +2 -2
- package/dist/dts/testing/fakes.d.ts +4 -4
- package/dist/dts/updates.d.ts +1 -0
- package/dist/dts/volatile.d.ts +2 -0
- package/dist/esm/__test__/helpers.js +22 -0
- package/dist/esm/__test__/setup-node.js +18 -0
- package/dist/esm/array-observer.js +1 -0
- package/dist/esm/arrays.js +1 -0
- package/dist/esm/attr.js +1 -0
- package/dist/esm/binding/normalize.js +1 -1
- package/dist/esm/binding/signal.js +4 -4
- package/dist/esm/binding/two-way.js +3 -3
- package/dist/esm/binding.js +4 -0
- package/dist/esm/components/attributes.js +18 -11
- package/dist/esm/components/definition-schema-transforms.js +23 -0
- package/dist/esm/components/element-controller.js +206 -270
- package/dist/esm/components/element-hydration.js +1 -1
- package/dist/esm/components/enable-hydration.js +124 -0
- package/dist/esm/components/fast-definitions.js +219 -56
- package/dist/esm/components/fast-element.js +18 -27
- package/dist/esm/components/hydration-tracker.js +122 -0
- package/dist/esm/components/hydration.js +137 -140
- package/dist/esm/components/schema.js +253 -0
- package/dist/esm/context.js +6 -6
- package/dist/esm/css.js +3 -0
- package/dist/esm/debug.js +27 -26
- package/dist/esm/declarative/attribute-map.js +122 -0
- package/dist/esm/declarative/debug.js +4 -0
- package/dist/esm/declarative/index.js +4 -0
- package/dist/esm/declarative/interfaces.js +9 -0
- package/dist/esm/declarative/observer-map-utilities.js +565 -0
- package/dist/esm/declarative/observer-map.js +216 -0
- package/dist/esm/declarative/runtime.js +14 -0
- package/dist/esm/declarative/syntax.js +36 -0
- package/dist/esm/declarative/template-bridge.js +160 -0
- package/dist/esm/declarative/template-parser.js +306 -0
- package/dist/esm/declarative/template.js +143 -0
- package/dist/esm/declarative/utilities.js +1069 -0
- package/dist/esm/di/di.js +8 -9
- package/dist/esm/directives/children.js +1 -0
- package/dist/esm/directives/node-observation.js +1 -0
- package/dist/esm/directives/ref.js +1 -0
- package/dist/esm/directives/repeat.js +1 -0
- package/dist/esm/directives/slotted.js +1 -0
- package/dist/esm/directives/when.js +1 -0
- package/dist/esm/dom-policy.js +35 -6
- package/dist/esm/dom.js +1 -1
- package/dist/esm/html.js +2 -0
- 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/runtime.js +33 -0
- package/dist/esm/hydration/target-builder.js +144 -91
- package/dist/esm/hydration.js +6 -0
- package/dist/esm/index.debug.js +2 -1
- package/dist/esm/index.js +38 -29
- package/dist/esm/index.rollup.debug.js +3 -2
- package/dist/esm/index.rollup.js +1 -1
- package/dist/esm/interfaces.js +2 -45
- package/dist/esm/metadata.js +2 -8
- package/dist/esm/observable.js +1 -4
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/notifier.js +2 -4
- package/dist/esm/observation/observable.js +5 -5
- package/dist/esm/observation/update-queue.js +47 -58
- package/dist/esm/platform.js +31 -30
- package/dist/esm/registry.js +1 -0
- package/dist/esm/render.js +1 -0
- package/dist/esm/schema.js +1 -0
- package/dist/esm/state/exports.js +1 -1
- package/dist/esm/styles/css-directive.js +1 -2
- package/dist/esm/styles/css.js +15 -56
- package/dist/esm/styles/element-styles.js +69 -15
- package/dist/esm/styles.js +2 -0
- package/dist/esm/templating/html-binding-directive.js +11 -9
- package/dist/esm/templating/hydration-view.js +228 -0
- package/dist/esm/templating/render.js +39 -18
- package/dist/esm/templating/repeat.js +69 -33
- package/dist/esm/templating/template.js +7 -7
- package/dist/esm/templating/view.js +25 -234
- package/dist/esm/templating.js +7 -0
- package/dist/esm/testing/exports.js +2 -2
- package/dist/esm/testing/fixture.js +2 -2
- package/dist/esm/testing/timeout.js +2 -2
- package/dist/esm/updates.js +1 -0
- package/dist/esm/volatile.js +1 -0
- package/dist/fast-element.api.json +14389 -11138
- package/dist/fast-element.d.ts +3651 -809
- package/dist/fast-element.debug.js +5666 -4722
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +5394 -4381
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +923 -472
- package/dist/hydration/hydration.api.json +6460 -0
- package/dist/styles/styles.api.json +2672 -0
- package/package.json +165 -45
- 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/DESIGN.md +0 -510
- package/api-extractor.context.json +0 -14
- package/api-extractor.di.json +0 -14
- package/biome.json +0 -4
- package/dist/dts/components/install-hydration.d.ts +0 -1
- package/dist/dts/pending-task.d.ts +0 -32
- package/dist/dts/styles/css-binding-directive.d.ts +0 -60
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
- package/dist/esm/components/install-hydration.js +0 -3
- package/dist/esm/pending-task.js +0 -28
- package/dist/esm/polyfills.js +0 -60
- package/dist/esm/styles/css-binding-directive.js +0 -76
- package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
- package/docs/ACKNOWLEDGEMENTS.md +0 -12
- package/docs/api-report.api.md +0 -1122
- package/docs/context/api-report.api.md +0 -69
- package/docs/di/api-report.api.md +0 -315
- package/docs/fast-element-2-changes.md +0 -15
- package/playwright.config.ts +0 -26
- package/scripts/run-api-extractor.js +0 -51
- package/test/index.html +0 -11
- package/test/main.ts +0 -104
- package/test/vite.config.ts +0 -19
- package/tsconfig.api-extractor.json +0 -6
- /package/dist/dts/{polyfills.d.ts → __test__/setup-node.d.ts} +0 -0
package/dist/esm/di/di.js
CHANGED
|
@@ -11,7 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
* Big thanks to https://github.com/fkleuver and the https://github.com/aurelia/aurelia project
|
|
12
12
|
* for the bulk of this code and many of the associated tests.
|
|
13
13
|
*/
|
|
14
|
-
import { Context,
|
|
14
|
+
import { Context, } from "../context.js";
|
|
15
15
|
import { Message } from "../interfaces.js";
|
|
16
16
|
import { Metadata } from "../metadata.js";
|
|
17
17
|
import { emptyArray, FAST } from "../platform.js";
|
|
@@ -181,7 +181,7 @@ function createContext(nameConfigOrCallback, configuror) {
|
|
|
181
181
|
return configure(new ResolverBuilder(container, key !== null && key !== void 0 ? key : Interface));
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
|
-
Interface.toString = function
|
|
184
|
+
Interface.toString = function interfaceToString() {
|
|
185
185
|
return `DIContext<${Interface.name}>`;
|
|
186
186
|
};
|
|
187
187
|
return Interface;
|
|
@@ -800,7 +800,8 @@ export class ResolverImpl {
|
|
|
800
800
|
}
|
|
801
801
|
}
|
|
802
802
|
getFactory(container) {
|
|
803
|
-
var _a, _b
|
|
803
|
+
var _a, _b;
|
|
804
|
+
var _c;
|
|
804
805
|
switch (this.strategy) {
|
|
805
806
|
case ResolverStrategy.singleton:
|
|
806
807
|
case ResolverStrategy.transient:
|
|
@@ -1132,9 +1133,7 @@ export class ContainerImpl {
|
|
|
1132
1133
|
}
|
|
1133
1134
|
getAll(key, searchAncestors = false) {
|
|
1134
1135
|
validateKey(key);
|
|
1135
|
-
|
|
1136
|
-
const requestor = this;
|
|
1137
|
-
let current = requestor;
|
|
1136
|
+
let current = this;
|
|
1138
1137
|
let resolver;
|
|
1139
1138
|
if (searchAncestors) {
|
|
1140
1139
|
let resolutions = emptyArray;
|
|
@@ -1143,7 +1142,7 @@ export class ContainerImpl {
|
|
|
1143
1142
|
if (resolver != null) {
|
|
1144
1143
|
resolutions = resolutions.concat(
|
|
1145
1144
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
1146
|
-
buildAllResponse(resolver, current,
|
|
1145
|
+
buildAllResponse(resolver, current, this));
|
|
1147
1146
|
}
|
|
1148
1147
|
current = current.parent;
|
|
1149
1148
|
}
|
|
@@ -1159,7 +1158,7 @@ export class ContainerImpl {
|
|
|
1159
1158
|
}
|
|
1160
1159
|
}
|
|
1161
1160
|
else {
|
|
1162
|
-
return buildAllResponse(resolver, current,
|
|
1161
|
+
return buildAllResponse(resolver, current, this);
|
|
1163
1162
|
}
|
|
1164
1163
|
}
|
|
1165
1164
|
}
|
|
@@ -1199,7 +1198,7 @@ export class ContainerImpl {
|
|
|
1199
1198
|
if (!(registrationResolver instanceof Object) ||
|
|
1200
1199
|
registrationResolver.resolve == null) {
|
|
1201
1200
|
const newResolver = handler.resolvers.get(keyAsValue);
|
|
1202
|
-
if (newResolver
|
|
1201
|
+
if (newResolver !== void 0) {
|
|
1203
1202
|
return newResolver;
|
|
1204
1203
|
}
|
|
1205
1204
|
throw FAST.error(Message.invalidResolver);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChildrenDirective, children, } from "../templating/children.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { elements, NodeObservationDirective, } from "../templating/node-observation.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RefDirective, ref } from "../templating/ref.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RepeatBehavior, RepeatDirective, repeat, } from "../templating/repeat.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SlottedDirective, slotted, } from "../templating/slotted.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { when } from "../templating/when.js";
|
package/dist/esm/dom-policy.js
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { DOMAspect } from "./dom.js";
|
|
2
2
|
import { isString, Message } from "./interfaces.js";
|
|
3
3
|
import { FAST } from "./platform.js";
|
|
4
|
+
const surroundingWhitespaceAndControlChars = /^[\u0000-\u0020\u007F]+|[\u0000-\u0020\u007F]+$/g;
|
|
5
|
+
const whitespaceAndControlChars = /[\u0000-\u0020\u007F]+/g;
|
|
6
|
+
const unsafeURLProtocol = /^(?:javascript|vbscript|data):/;
|
|
7
|
+
function trimURL(value) {
|
|
8
|
+
return value.replace(surroundingWhitespaceAndControlChars, "");
|
|
9
|
+
}
|
|
10
|
+
function decodeURL(value) {
|
|
11
|
+
try {
|
|
12
|
+
return decodeURIComponent(value);
|
|
13
|
+
}
|
|
14
|
+
catch (_a) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function hasUnsafeURLProtocol(value) {
|
|
19
|
+
let normalized = trimURL(value);
|
|
20
|
+
for (let i = 0; i < 3; ++i) {
|
|
21
|
+
const decoded = decodeURL(normalized);
|
|
22
|
+
if (decoded === normalized) {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
normalized = trimURL(decoded);
|
|
26
|
+
}
|
|
27
|
+
normalized = normalized.replace(whitespaceAndControlChars, "").toLowerCase();
|
|
28
|
+
return unsafeURLProtocol.test(normalized);
|
|
29
|
+
}
|
|
30
|
+
function sanitizeURL(value) {
|
|
31
|
+
const trimmed = trimURL(value);
|
|
32
|
+
return hasUnsafeURLProtocol(trimmed) ? "" : trimmed;
|
|
33
|
+
}
|
|
4
34
|
function safeURL(tagName, aspect, aspectName, sink) {
|
|
5
35
|
return (target, name, value, ...rest) => {
|
|
6
36
|
if (isString(value)) {
|
|
7
|
-
value = value
|
|
37
|
+
value = sanitizeURL(value);
|
|
8
38
|
}
|
|
9
39
|
sink(target, name, value, ...rest);
|
|
10
40
|
};
|
|
@@ -266,7 +296,7 @@ function createElementGuards(config, defaults) {
|
|
|
266
296
|
break;
|
|
267
297
|
case undefined:
|
|
268
298
|
// keep the default
|
|
269
|
-
result[tag] = createDOMAspectGuards(
|
|
299
|
+
result[tag] = createDOMAspectGuards(defaultValue, {});
|
|
270
300
|
break;
|
|
271
301
|
default:
|
|
272
302
|
// override the default aspects
|
|
@@ -295,7 +325,7 @@ function createDOMGuards(config, defaults) {
|
|
|
295
325
|
function createTrustedType() {
|
|
296
326
|
const createHTML = html => html;
|
|
297
327
|
return globalThis.trustedTypes
|
|
298
|
-
? globalThis.trustedTypes.createPolicy("fast-
|
|
328
|
+
? globalThis.trustedTypes.createPolicy("fast-element", { createHTML })
|
|
299
329
|
: { createHTML };
|
|
300
330
|
}
|
|
301
331
|
function tryGuard(aspectGuards, tagName, aspect, aspectName, sink) {
|
|
@@ -311,10 +341,10 @@ function tryGuard(aspectGuards, tagName, aspect, aspectName, sink) {
|
|
|
311
341
|
* A helper for creating DOM policies.
|
|
312
342
|
* @public
|
|
313
343
|
*/
|
|
314
|
-
const DOMPolicy = Object.freeze({
|
|
344
|
+
export const DOMPolicy = Object.freeze({
|
|
315
345
|
/**
|
|
316
346
|
* Creates a new DOM Policy object.
|
|
317
|
-
* @param options The options to use in creating the policy.
|
|
347
|
+
* @param options - The options to use in creating the policy.
|
|
318
348
|
* @returns The newly created DOMPolicy.
|
|
319
349
|
*/
|
|
320
350
|
create(options = {}) {
|
|
@@ -342,4 +372,3 @@ const DOMPolicy = Object.freeze({
|
|
|
342
372
|
});
|
|
343
373
|
},
|
|
344
374
|
});
|
|
345
|
-
export { DOMPolicy };
|
package/dist/esm/dom.js
CHANGED
|
@@ -36,7 +36,7 @@ export const DOMAspect = Object.freeze({
|
|
|
36
36
|
});
|
|
37
37
|
const createHTML = html => html;
|
|
38
38
|
const fastTrustedType = globalThis.trustedTypes
|
|
39
|
-
? globalThis.trustedTypes.createPolicy("fast-
|
|
39
|
+
? globalThis.trustedTypes.createPolicy("fast-element", { createHTML })
|
|
40
40
|
: { createHTML };
|
|
41
41
|
let defaultPolicy = Object.freeze({
|
|
42
42
|
createHTML(value) {
|
package/dist/esm/html.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { formatDefaultMismatchMessage, unknownHostName } from "./messages.js";
|
|
2
|
+
function formatMinimalMessage(hostName, detail) {
|
|
3
|
+
const host = (hostName !== null && hostName !== void 0 ? hostName : unknownHostName).toLowerCase();
|
|
4
|
+
return formatDefaultMismatchMessage(host, detail);
|
|
5
|
+
}
|
|
6
|
+
const defaultDiagnostic = {
|
|
7
|
+
formatBindingMismatch(_factory, _firstChild, _lastChild, hostName) {
|
|
8
|
+
return {
|
|
9
|
+
message: formatMinimalMessage(hostName, undefined),
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
formatStructuralError(_node, hostName, expectedDescription) {
|
|
13
|
+
return {
|
|
14
|
+
message: formatMinimalMessage(hostName, expectedDescription),
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
let activeDiagnostic = defaultDiagnostic;
|
|
19
|
+
/**
|
|
20
|
+
* Installs a {@link HydrationDiagnostic} as the active formatter for
|
|
21
|
+
* hydration mismatch errors. Called by `enableHydration()` when an opt-in
|
|
22
|
+
* debugger configuration is supplied; not exposed as `@public` because
|
|
23
|
+
* library consumers should always go through `enableHydration` to install
|
|
24
|
+
* a debugger.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export function installHydrationDiagnostic(diagnostic) {
|
|
28
|
+
activeDiagnostic = diagnostic;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the currently active {@link HydrationDiagnostic} — either the
|
|
32
|
+
* minimal default or one installed by an opt-in debugger.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export function getHydrationDiagnostic() {
|
|
36
|
+
return activeDiagnostic;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reads the host element's tag name from any node inside a hydration view.
|
|
40
|
+
* Returns `undefined` when the node is not inside a shadow root.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export function getHostName(node) {
|
|
44
|
+
var _a;
|
|
45
|
+
if (!node) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const root = node.getRootNode();
|
|
49
|
+
return (_a = root.host) === null || _a === void 0 ? void 0 : _a.nodeName;
|
|
50
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Hydratable } from "../components/hydration.js";
|
|
2
|
+
import { ViewTemplate } from "../templating/template.js";
|
|
3
|
+
import { HydrationView } from "../templating/hydration-view.js";
|
|
4
|
+
let installed = false;
|
|
5
|
+
/**
|
|
6
|
+
* Installs the hydration runtime on `ViewTemplate.prototype`,
|
|
7
|
+
* making all templates hydratable. Call this before any hydration
|
|
8
|
+
* occurs. Safe to call multiple times — subsequent calls are no-ops.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function ensureHydrationRuntime() {
|
|
12
|
+
if (installed) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const prototype = ViewTemplate.prototype;
|
|
16
|
+
if (prototype[Hydratable] !== Hydratable) {
|
|
17
|
+
Object.defineProperties(prototype, {
|
|
18
|
+
[Hydratable]: {
|
|
19
|
+
value: Hydratable,
|
|
20
|
+
enumerable: false,
|
|
21
|
+
configurable: false,
|
|
22
|
+
},
|
|
23
|
+
hydrate: {
|
|
24
|
+
value(firstChild, lastChild, hostBindingTarget) {
|
|
25
|
+
return new HydrationView(firstChild, lastChild, this, hostBindingTarget);
|
|
26
|
+
},
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: false,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
installed = true;
|
|
33
|
+
}
|