@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.
Files changed (211) hide show
  1. package/CHANGELOG.md +52 -2
  2. package/README.md +244 -1
  3. package/dist/arrays/arrays.api.json +2621 -0
  4. package/dist/context/context.api.json +13 -13
  5. package/dist/declarative/declarative.api.json +8483 -0
  6. package/dist/di/di.api.json +16 -16
  7. package/dist/dts/__test__/helpers.d.ts +6 -0
  8. package/dist/dts/array-observer.d.ts +2 -0
  9. package/dist/dts/arrays.d.ts +2 -0
  10. package/dist/dts/attr.d.ts +1 -0
  11. package/dist/dts/binding/binding.d.ts +15 -5
  12. package/dist/dts/binding/one-time.d.ts +1 -1
  13. package/dist/dts/binding/one-way.d.ts +1 -1
  14. package/dist/dts/binding/signal.d.ts +6 -6
  15. package/dist/dts/binding/two-way.d.ts +2 -1
  16. package/dist/dts/binding.d.ts +7 -0
  17. package/dist/dts/components/attributes.d.ts +1 -4
  18. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  19. package/dist/dts/components/element-controller.d.ts +80 -114
  20. package/dist/dts/components/element-hydration.d.ts +1 -1
  21. package/dist/dts/components/enable-hydration.d.ts +54 -0
  22. package/dist/dts/components/fast-definitions.d.ts +98 -46
  23. package/dist/dts/components/fast-element.d.ts +43 -16
  24. package/dist/dts/components/hydration-tracker.d.ts +83 -0
  25. package/dist/dts/components/hydration.d.ts +23 -53
  26. package/dist/dts/components/schema.d.ts +205 -0
  27. package/dist/dts/context.d.ts +13 -13
  28. package/dist/dts/css.d.ts +3 -0
  29. package/dist/dts/debug.d.ts +5 -1
  30. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  31. package/dist/dts/declarative/debug.d.ts +4 -0
  32. package/dist/dts/declarative/index.d.ts +14 -0
  33. package/dist/dts/declarative/interfaces.d.ts +8 -0
  34. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  35. package/dist/dts/declarative/observer-map.d.ts +89 -0
  36. package/dist/dts/declarative/runtime.d.ts +5 -0
  37. package/dist/dts/declarative/syntax.d.ts +21 -0
  38. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  39. package/dist/dts/declarative/template-parser.d.ts +98 -0
  40. package/dist/dts/declarative/template.d.ts +10 -0
  41. package/dist/dts/declarative/utilities.d.ts +358 -0
  42. package/dist/dts/di/di.d.ts +7 -7
  43. package/dist/dts/directives/children.d.ts +2 -0
  44. package/dist/dts/directives/node-observation.d.ts +2 -0
  45. package/dist/dts/directives/ref.d.ts +2 -0
  46. package/dist/dts/directives/repeat.d.ts +4 -0
  47. package/dist/dts/directives/slotted.d.ts +2 -0
  48. package/dist/dts/directives/when.d.ts +3 -0
  49. package/dist/dts/dom-policy.d.ts +23 -5
  50. package/dist/dts/dom.d.ts +4 -16
  51. package/dist/dts/html.d.ts +5 -0
  52. package/dist/dts/hydration/diagnostics.d.ts +93 -0
  53. package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
  54. package/dist/dts/hydration/messages.d.ts +62 -0
  55. package/dist/dts/hydration/runtime.d.ts +7 -0
  56. package/dist/dts/hydration/target-builder.d.ts +40 -12
  57. package/dist/dts/hydration.d.ts +18 -0
  58. package/dist/dts/index.d.ts +42 -42
  59. package/dist/dts/index.debug.d.ts +0 -1
  60. package/dist/dts/index.rollup.debug.d.ts +0 -1
  61. package/dist/dts/interfaces.d.ts +2 -49
  62. package/dist/dts/observable.d.ts +3 -6
  63. package/dist/dts/observation/arrays.d.ts +1 -1
  64. package/dist/dts/observation/observable.d.ts +3 -3
  65. package/dist/dts/observation/update-queue.d.ts +1 -1
  66. package/dist/dts/platform.d.ts +45 -8
  67. package/dist/dts/registry.d.ts +1 -0
  68. package/dist/dts/render.d.ts +7 -0
  69. package/dist/dts/schema.d.ts +1 -0
  70. package/dist/dts/state/exports.d.ts +1 -1
  71. package/dist/dts/state/state.d.ts +2 -2
  72. package/dist/dts/styles/css-directive.d.ts +5 -12
  73. package/dist/dts/styles/css.d.ts +5 -7
  74. package/dist/dts/styles/element-styles.d.ts +0 -10
  75. package/dist/dts/styles.d.ts +6 -0
  76. package/dist/dts/templating/compiler.d.ts +1 -1
  77. package/dist/dts/templating/html-binding-directive.d.ts +10 -2
  78. package/dist/dts/templating/html-directive.d.ts +19 -1
  79. package/dist/dts/templating/hydration-view.d.ts +130 -0
  80. package/dist/dts/templating/render.d.ts +1 -1
  81. package/dist/dts/templating/repeat.d.ts +1 -1
  82. package/dist/dts/templating/template.d.ts +15 -7
  83. package/dist/dts/templating/view.d.ts +25 -102
  84. package/dist/dts/templating.d.ts +10 -0
  85. package/dist/dts/testing/exports.d.ts +2 -2
  86. package/dist/dts/testing/fakes.d.ts +4 -4
  87. package/dist/dts/updates.d.ts +1 -0
  88. package/dist/dts/volatile.d.ts +2 -0
  89. package/dist/esm/__test__/helpers.js +22 -0
  90. package/dist/esm/__test__/setup-node.js +18 -0
  91. package/dist/esm/array-observer.js +1 -0
  92. package/dist/esm/arrays.js +1 -0
  93. package/dist/esm/attr.js +1 -0
  94. package/dist/esm/binding/normalize.js +1 -1
  95. package/dist/esm/binding/signal.js +4 -4
  96. package/dist/esm/binding/two-way.js +3 -3
  97. package/dist/esm/binding.js +4 -0
  98. package/dist/esm/components/attributes.js +18 -11
  99. package/dist/esm/components/definition-schema-transforms.js +23 -0
  100. package/dist/esm/components/element-controller.js +206 -270
  101. package/dist/esm/components/element-hydration.js +1 -1
  102. package/dist/esm/components/enable-hydration.js +124 -0
  103. package/dist/esm/components/fast-definitions.js +219 -56
  104. package/dist/esm/components/fast-element.js +18 -27
  105. package/dist/esm/components/hydration-tracker.js +122 -0
  106. package/dist/esm/components/hydration.js +137 -140
  107. package/dist/esm/components/schema.js +253 -0
  108. package/dist/esm/context.js +6 -6
  109. package/dist/esm/css.js +3 -0
  110. package/dist/esm/debug.js +27 -26
  111. package/dist/esm/declarative/attribute-map.js +122 -0
  112. package/dist/esm/declarative/debug.js +4 -0
  113. package/dist/esm/declarative/index.js +4 -0
  114. package/dist/esm/declarative/interfaces.js +9 -0
  115. package/dist/esm/declarative/observer-map-utilities.js +565 -0
  116. package/dist/esm/declarative/observer-map.js +216 -0
  117. package/dist/esm/declarative/runtime.js +14 -0
  118. package/dist/esm/declarative/syntax.js +36 -0
  119. package/dist/esm/declarative/template-bridge.js +160 -0
  120. package/dist/esm/declarative/template-parser.js +306 -0
  121. package/dist/esm/declarative/template.js +143 -0
  122. package/dist/esm/declarative/utilities.js +1069 -0
  123. package/dist/esm/di/di.js +8 -9
  124. package/dist/esm/directives/children.js +1 -0
  125. package/dist/esm/directives/node-observation.js +1 -0
  126. package/dist/esm/directives/ref.js +1 -0
  127. package/dist/esm/directives/repeat.js +1 -0
  128. package/dist/esm/directives/slotted.js +1 -0
  129. package/dist/esm/directives/when.js +1 -0
  130. package/dist/esm/dom-policy.js +35 -6
  131. package/dist/esm/dom.js +1 -1
  132. package/dist/esm/html.js +2 -0
  133. package/dist/esm/hydration/diagnostics.js +50 -0
  134. package/dist/esm/hydration/hydration-debugger.js +112 -0
  135. package/dist/esm/hydration/messages.js +84 -0
  136. package/dist/esm/hydration/runtime.js +33 -0
  137. package/dist/esm/hydration/target-builder.js +144 -91
  138. package/dist/esm/hydration.js +6 -0
  139. package/dist/esm/index.debug.js +2 -1
  140. package/dist/esm/index.js +38 -29
  141. package/dist/esm/index.rollup.debug.js +3 -2
  142. package/dist/esm/index.rollup.js +1 -1
  143. package/dist/esm/interfaces.js +2 -45
  144. package/dist/esm/metadata.js +2 -8
  145. package/dist/esm/observable.js +1 -4
  146. package/dist/esm/observation/arrays.js +1 -1
  147. package/dist/esm/observation/notifier.js +2 -4
  148. package/dist/esm/observation/observable.js +5 -5
  149. package/dist/esm/observation/update-queue.js +47 -58
  150. package/dist/esm/platform.js +31 -30
  151. package/dist/esm/registry.js +1 -0
  152. package/dist/esm/render.js +1 -0
  153. package/dist/esm/schema.js +1 -0
  154. package/dist/esm/state/exports.js +1 -1
  155. package/dist/esm/styles/css-directive.js +1 -2
  156. package/dist/esm/styles/css.js +15 -56
  157. package/dist/esm/styles/element-styles.js +69 -15
  158. package/dist/esm/styles.js +2 -0
  159. package/dist/esm/templating/html-binding-directive.js +11 -9
  160. package/dist/esm/templating/hydration-view.js +228 -0
  161. package/dist/esm/templating/render.js +39 -18
  162. package/dist/esm/templating/repeat.js +69 -33
  163. package/dist/esm/templating/template.js +7 -7
  164. package/dist/esm/templating/view.js +25 -234
  165. package/dist/esm/templating.js +7 -0
  166. package/dist/esm/testing/exports.js +2 -2
  167. package/dist/esm/testing/fixture.js +2 -2
  168. package/dist/esm/testing/timeout.js +2 -2
  169. package/dist/esm/updates.js +1 -0
  170. package/dist/esm/volatile.js +1 -0
  171. package/dist/fast-element.api.json +14389 -11138
  172. package/dist/fast-element.d.ts +3651 -809
  173. package/dist/fast-element.debug.js +5666 -4722
  174. package/dist/fast-element.debug.min.js +2 -2
  175. package/dist/fast-element.js +5394 -4381
  176. package/dist/fast-element.min.js +2 -2
  177. package/dist/fast-element.untrimmed.d.ts +923 -472
  178. package/dist/hydration/hydration.api.json +6460 -0
  179. package/dist/styles/styles.api.json +2672 -0
  180. package/package.json +165 -45
  181. package/ARCHITECTURE_FASTELEMENT.md +0 -63
  182. package/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +0 -36
  183. package/ARCHITECTURE_INTRO.md +0 -10
  184. package/ARCHITECTURE_OVERVIEW.md +0 -52
  185. package/ARCHITECTURE_UPDATES.md +0 -11
  186. package/CHANGELOG.json +0 -2275
  187. package/DESIGN.md +0 -510
  188. package/api-extractor.context.json +0 -14
  189. package/api-extractor.di.json +0 -14
  190. package/biome.json +0 -4
  191. package/dist/dts/components/install-hydration.d.ts +0 -1
  192. package/dist/dts/pending-task.d.ts +0 -32
  193. package/dist/dts/styles/css-binding-directive.d.ts +0 -60
  194. package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
  195. package/dist/esm/components/install-hydration.js +0 -3
  196. package/dist/esm/pending-task.js +0 -28
  197. package/dist/esm/polyfills.js +0 -60
  198. package/dist/esm/styles/css-binding-directive.js +0 -76
  199. package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
  200. package/docs/ACKNOWLEDGEMENTS.md +0 -12
  201. package/docs/api-report.api.md +0 -1122
  202. package/docs/context/api-report.api.md +0 -69
  203. package/docs/di/api-report.api.md +0 -315
  204. package/docs/fast-element-2-changes.md +0 -15
  205. package/playwright.config.ts +0 -26
  206. package/scripts/run-api-extractor.js +0 -51
  207. package/test/index.html +0 -11
  208. package/test/main.ts +0 -104
  209. package/test/vite.config.ts +0 -19
  210. package/tsconfig.api-extractor.json +0 -6
  211. /package/dist/dts/{polyfills.d.ts → __test__/setup-node.d.ts} +0 -0
@@ -1,27 +1,36 @@
1
+ import { Message } from "../interfaces.js";
1
2
  import { FAST } from "../platform.js";
2
3
  /**
3
- * Regex patterns for parsing hydration markers embedded as HTML comments by the SSR renderer.
4
- * Each marker type encodes factory indices so the client can map markers back to ViewBehaviorFactories.
4
+ * Data-free sequential hydration markers.
5
+ *
6
+ * All markers use the `fe:` prefix to namespace them to FAST Element. The closing
7
+ * marker uses `/` following HTML/XML convention. Markers carry zero
8
+ * embedded data — the hydration walker derives factory-to-node mappings
9
+ * by maintaining a sequential pointer through the factories array.
5
10
  *
6
11
  * Content binding markers bracket text/template content:
7
- * <!-- fe-b$$start$$<factoryIndex>$$<uniqueId>$$fe-b -->
8
- * ...content...
9
- * <!-- fe-b$$end$$<factoryIndex>$$<uniqueId>$$fe-b -->
12
+ * <!--fe:b--> ...content... <!--fe:/b-->
13
+ *
14
+ * Repeat item markers bracket each repeated item:
15
+ * <!--fe:r--> ...item... <!--fe:/r-->
16
+ *
17
+ * Element boundary markers demarcate nested custom elements:
18
+ * <!--fe:e--> ...shadow content... <!--fe:/e-->
10
19
  *
11
- * Repeat markers bracket each repeated item:
12
- * <!-- fe-repeat$$start$$<itemIndex>$$fe-repeat -->
13
- * <!-- fe-repeat$$end$$<itemIndex>$$fe-repeat -->
20
+ * Attribute bindings use a single `data-fe` attribute whose value is
21
+ * the count of attribute binding factories targeting the element:
22
+ * <div data-fe="3"> (3 attribute bindings)
14
23
  *
15
- * Element boundary markers demarcate nested custom elements so parent walkers can skip them:
16
- * <!-- fe-eb$$start$$<elementId>$$fe-eb -->
17
- * <!-- fe-eb$$end$$<elementId>$$fe-eb -->
24
+ * WebUI versions that predate the data-free marker format still emit indexed
25
+ * markers. The parser below accepts those legacy markers so existing WebUI SSR
26
+ * output can hydrate against the newer FAST runtime.
18
27
  */
19
- const bindingStartMarker = /fe-b\$\$start\$\$(\d+)\$\$(.+)\$\$fe-b/;
20
- const bindingEndMarker = /fe-b\$\$end\$\$(\d+)\$\$(.+)\$\$fe-b/;
21
- const repeatViewStartMarker = /fe-repeat\$\$start\$\$(\d+)\$\$fe-repeat/;
22
- const repeatViewEndMarker = /fe-repeat\$\$end\$\$(\d+)\$\$fe-repeat/;
23
- const elementBoundaryStartMarker = /^(?:.{0,1000})fe-eb\$\$start\$\$(.+?)\$\$fe-eb/;
24
- const elementBoundaryEndMarker = /fe-eb\$\$end\$\$(.{0,1000})\$\$fe-eb(?:.{0,1000})$/;
28
+ const legacyBindingStartMarker = /fe-b\$\$start\$\$(\d+)\$\$(.+)\$\$fe-b/;
29
+ const legacyBindingEndMarker = /fe-b\$\$end\$\$(\d+)\$\$(.+)\$\$fe-b/;
30
+ const legacyRepeatViewStartMarker = /fe-repeat\$\$start\$\$(\d+)\$\$fe-repeat/;
31
+ const legacyRepeatViewEndMarker = /fe-repeat\$\$end\$\$(\d+)\$\$fe-repeat/;
32
+ const legacyElementBoundaryStartMarker = /^(?:.{0,1000})fe-eb\$\$start\$\$(.+?)\$\$fe-eb/;
33
+ const legacyElementBoundaryEndMarker = /fe-eb\$\$end\$\$(.{0,1000})\$\$fe-eb(?:.{0,1000})$/;
25
34
  function isComment(node) {
26
35
  return node && node.nodeType === Node.COMMENT_NODE;
27
36
  }
@@ -30,150 +39,143 @@ function isComment(node) {
30
39
  * @internal
31
40
  */
32
41
  export const HydrationMarkup = Object.freeze({
33
- attributeMarkerName: "data-fe-b",
34
- compactAttributeMarkerName: "data-fe-c",
35
- attributeBindingSeparator: " ",
36
- contentBindingStartMarker(index, uniqueId) {
37
- return `fe-b$$start$$${index}$$${uniqueId}$$fe-b`;
42
+ // Single attribute marker format (count only)
43
+ attributeMarkerName: "data-fe",
44
+ legacyAttributeMarkerName: "data-fe-b",
45
+ legacyCompactAttributeMarkerName: "data-fe-c",
46
+ // Content binding markers (no arguments)
47
+ contentBindingStartMarker() {
48
+ return "fe:b";
38
49
  },
39
- contentBindingEndMarker(index, uniqueId) {
40
- return `fe-b$$end$$${index}$$${uniqueId}$$fe-b`;
50
+ contentBindingEndMarker() {
51
+ return "fe:/b";
41
52
  },
42
- repeatStartMarker(index) {
43
- return `fe-repeat$$start$$${index}$$fe-repeat`;
53
+ // Repeat item markers (no arguments)
54
+ repeatStartMarker() {
55
+ return "fe:r";
44
56
  },
45
- repeatEndMarker(index) {
46
- return `fe-repeat$$end$$${index}$$fe-repeat`;
57
+ repeatEndMarker() {
58
+ return "fe:/r";
47
59
  },
48
- isContentBindingStartMarker(content) {
49
- return bindingStartMarker.test(content);
60
+ // Element boundary markers (no arguments)
61
+ elementBoundaryStartMarker() {
62
+ return "fe:e";
50
63
  },
51
- isContentBindingEndMarker(content) {
52
- return bindingEndMarker.test(content);
64
+ elementBoundaryEndMarker() {
65
+ return "fe:/e";
53
66
  },
54
- isRepeatViewStartMarker(content) {
55
- return repeatViewStartMarker.test(content);
67
+ // Detection — simple string equality
68
+ isContentBindingStartMarker(data) {
69
+ return data === "fe:b" || legacyBindingStartMarker.test(data);
56
70
  },
57
- isRepeatViewEndMarker(content) {
58
- return repeatViewEndMarker.test(content);
71
+ isContentBindingEndMarker(data) {
72
+ return data === "fe:/b" || legacyBindingEndMarker.test(data);
73
+ },
74
+ isRepeatViewStartMarker(data) {
75
+ return data === "fe:r" || legacyRepeatViewStartMarker.test(data);
76
+ },
77
+ isRepeatViewEndMarker(data) {
78
+ return data === "fe:/r" || legacyRepeatViewEndMarker.test(data);
59
79
  },
60
80
  isElementBoundaryStartMarker(node) {
61
- return isComment(node) && elementBoundaryStartMarker.test(node.data.trim());
81
+ return (isComment(node) &&
82
+ (node.data === "fe:e" || legacyElementBoundaryStartMarker.test(node.data)));
62
83
  },
63
84
  isElementBoundaryEndMarker(node) {
64
- return isComment(node) && elementBoundaryEndMarker.test(node.data);
85
+ return (isComment(node) &&
86
+ (node.data === "fe:/e" || legacyElementBoundaryEndMarker.test(node.data)));
65
87
  },
66
88
  /**
67
- * Returns the indexes of the ViewBehaviorFactories affecting
68
- * attributes for the element, or null if no factories were found.
89
+ * Returns the count of attribute bindings on the element, or null
90
+ * if no attribute binding marker is present.
69
91
  *
70
- * This method parses the space-separated format: `data-fe-b="0 1 2"`.
92
+ * Parses the `data-fe="N"` attribute format where N is the count
93
+ * of attribute binding factories targeting this element.
71
94
  */
72
- parseAttributeBinding(node) {
95
+ parseAttributeBindingCount(node) {
73
96
  const attr = node.getAttribute(this.attributeMarkerName);
74
- return attr === null
75
- ? attr
76
- : attr.split(this.attributeBindingSeparator).map(i => parseInt(i));
77
- },
78
- /**
79
- * Returns the indexes of the ViewBehaviorFactories affecting
80
- * attributes for the element, or null if no factories were found.
81
- *
82
- * This method parses the enumerated format: `data-fe-b-0`, `data-fe-b-1`, `data-fe-b-2`.
83
- * This is an alternative format that uses separate attributes for each binding index.
84
- */
85
- parseEnumeratedAttributeBinding(node) {
86
- const attrs = [];
87
- const prefixLength = this.attributeMarkerName.length + 1;
88
- const prefix = `${this.attributeMarkerName}-`;
89
- for (const attr of node.getAttributeNames()) {
90
- if (attr.startsWith(prefix)) {
91
- const count = Number(attr.slice(prefixLength));
92
- if (!Number.isNaN(count)) {
93
- attrs.push(count);
97
+ if (attr === null) {
98
+ return null;
99
+ }
100
+ const trimmed = attr.trim();
101
+ if (!/^\d+$/.test(trimmed)) {
102
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
103
+ value: attr,
104
+ });
105
+ }
106
+ const count = parseInt(trimmed, 10);
107
+ if (count < 1) {
108
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
109
+ value: attr,
110
+ });
111
+ }
112
+ return count;
113
+ },
114
+ parseLegacyAttributeBindingIndices(node) {
115
+ const indices = [];
116
+ const attr = node.getAttribute(this.legacyAttributeMarkerName);
117
+ if (attr !== null) {
118
+ for (const value of attr.trim().split(/\s+/)) {
119
+ if (value === "") {
120
+ continue;
94
121
  }
95
- else {
96
- throw FAST.error(1601 /* invalidAttributeMarkerName */, {
97
- name: attr,
98
- expectedFormat: `${prefix}<number>`,
122
+ const index = Number(value);
123
+ if (!Number.isInteger(index) || index < 0) {
124
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
125
+ value: attr,
99
126
  });
100
127
  }
128
+ indices.push(index);
101
129
  }
102
130
  }
103
- return attrs.length === 0 ? null : attrs;
104
- },
105
- /**
106
- * Returns the indexes of the ViewBehaviorFactories affecting
107
- * attributes for the element, or null if no factories were found.
108
- *
109
- * This method parses the compact format: `data-fe-c-{index}-{count}`.
110
- */
111
- parseCompactAttributeBinding(node) {
112
- const prefix = `${this.compactAttributeMarkerName}-`;
113
- const attrName = node.getAttributeNames().find(name => name.startsWith(prefix));
114
- if (!attrName) {
115
- return null;
116
- }
117
- const suffix = attrName.slice(prefix.length);
118
- const parts = suffix.split("-");
119
- const startIndex = parseInt(parts[0], 10);
120
- const count = parseInt(parts[1], 10);
121
- if (parts.length !== 2 ||
122
- Number.isNaN(startIndex) ||
123
- Number.isNaN(count) ||
124
- startIndex < 0 ||
125
- count < 1) {
126
- throw FAST.error(1604 /* invalidCompactAttributeMarkerName */, {
127
- name: attrName,
128
- expectedFormat: `${this.compactAttributeMarkerName}-{index}-{count}`,
129
- });
131
+ const enumeratedPrefix = `${this.legacyAttributeMarkerName}-`;
132
+ const compactPrefix = `${this.legacyCompactAttributeMarkerName}-`;
133
+ for (const name of node.getAttributeNames()) {
134
+ if (name.startsWith(enumeratedPrefix)) {
135
+ const index = Number(name.slice(enumeratedPrefix.length));
136
+ if (!Number.isInteger(index) || index < 0) {
137
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
138
+ value: name,
139
+ });
140
+ }
141
+ indices.push(index);
142
+ }
143
+ else if (name.startsWith(compactPrefix)) {
144
+ const [start, count] = name
145
+ .slice(compactPrefix.length)
146
+ .split("-")
147
+ .map(value => Number(value));
148
+ if (!Number.isInteger(start) ||
149
+ !Number.isInteger(count) ||
150
+ start < 0 ||
151
+ count < 1) {
152
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
153
+ value: name,
154
+ });
155
+ }
156
+ for (let i = 0; i < count; i++) {
157
+ indices.push(start + i);
158
+ }
159
+ }
130
160
  }
131
- const indexes = [];
132
- for (let i = 0; i < count; i++) {
133
- indexes.push(startIndex + i);
161
+ return indices.length === 0 ? null : indices;
162
+ },
163
+ removeLegacyAttributeBindingMarkers(node) {
164
+ node.removeAttribute(this.legacyAttributeMarkerName);
165
+ for (const name of node.getAttributeNames()) {
166
+ if (name.startsWith(`${this.legacyAttributeMarkerName}-`) ||
167
+ name.startsWith(`${this.legacyCompactAttributeMarkerName}-`)) {
168
+ node.removeAttribute(name);
169
+ }
134
170
  }
135
- return indexes;
136
- },
137
- /**
138
- * Parses the ViewBehaviorFactory index from string data. Returns
139
- * the binding index or null if the index cannot be retrieved.
140
- */
141
- parseContentBindingStartMarker(content) {
142
- return parseIndexAndIdMarker(bindingStartMarker, content);
143
- },
144
- parseContentBindingEndMarker(content) {
145
- return parseIndexAndIdMarker(bindingEndMarker, content);
146
171
  },
147
- /**
148
- * Parses the index of a repeat directive from a content string.
149
- */
150
- parseRepeatStartMarker(content) {
151
- return parseIntMarker(repeatViewStartMarker, content);
152
- },
153
- parseRepeatEndMarker(content) {
154
- return parseIntMarker(repeatViewEndMarker, content);
155
- },
156
- /**
157
- * Parses element Id from element boundary markers
158
- */
159
- parseElementBoundaryStartMarker(content) {
160
- return parseStringMarker(elementBoundaryStartMarker, content.trim());
161
- },
162
- parseElementBoundaryEndMarker(content) {
163
- return parseStringMarker(elementBoundaryEndMarker, content);
172
+ parseLegacyContentBindingStartIndex(data) {
173
+ return parseLegacyIntMarker(legacyBindingStartMarker, data);
164
174
  },
165
175
  });
166
- function parseIntMarker(regex, content) {
167
- const match = regex.exec(content);
168
- return match === null ? match : parseInt(match[1]);
169
- }
170
- function parseStringMarker(regex, content) {
171
- const match = regex.exec(content);
172
- return match === null ? match : match[1];
173
- }
174
- function parseIndexAndIdMarker(regex, content) {
175
- const match = regex.exec(content);
176
- return match === null ? match : [parseInt(match[1]), match[2]];
176
+ function parseLegacyIntMarker(pattern, data) {
177
+ const match = pattern.exec(data);
178
+ return match === null ? null : Number(match[1]);
177
179
  }
178
180
  /**
179
181
  * @internal
@@ -183,8 +185,3 @@ export const Hydratable = Symbol.for("fe-hydration");
183
185
  export function isHydratable(value) {
184
186
  return value[Hydratable] === Hydratable;
185
187
  }
186
- /**
187
- * The attribute used to defer hydration of an element.
188
- * @beta
189
- */
190
- export const deferHydrationAttribute = "defer-hydration";
@@ -0,0 +1,253 @@
1
+ // The context, in most cases the array property e.g. users
2
+ export const fastContextMetaData = "$fast_context";
3
+ // The list of contexts preceeding this context, the first of which should be the root property
4
+ export const fastContextsMetaData = "$fast_parent_contexts";
5
+ export const defsPropertyName = "$defs";
6
+ export const refPropertyName = "$ref";
7
+ /**
8
+ * Module-level registry that maps custom element names to their schema maps.
9
+ * Used for cross-element `$ref` resolution (e.g. nested element schemas).
10
+ * Each Schema instance registers itself here on construction.
11
+ * @public
12
+ */
13
+ export const schemaRegistry = new Map();
14
+ /**
15
+ * A constructed JSON schema from a template
16
+ * @public
17
+ */
18
+ export class Schema {
19
+ constructor(name) {
20
+ this.customElementName = name;
21
+ this.schemaMap = new Map();
22
+ schemaRegistry.set(name, this.schemaMap);
23
+ }
24
+ /**
25
+ * Add a path to a schema
26
+ * @param config - The path registration configuration.
27
+ */
28
+ addPath(config) {
29
+ var _a, _b, _c;
30
+ const splitPath = this.getSplitPath(config.pathConfig.path);
31
+ let schema = this.schemaMap.get(config.rootPropertyName);
32
+ let childRef = null;
33
+ // Create a root level property JSON
34
+ if (!schema) {
35
+ this.addNewSchema(config.rootPropertyName);
36
+ schema = this.schemaMap.get(config.rootPropertyName);
37
+ }
38
+ if (config.childrenMap) {
39
+ childRef = this.getSchemaId(config.childrenMap.customElementName, config.childrenMap.attributeName);
40
+ if (splitPath.length === 1) {
41
+ schema.anyOf
42
+ ? schema.anyOf.push({ [refPropertyName]: childRef })
43
+ : (schema.anyOf = [{ [refPropertyName]: childRef }]);
44
+ }
45
+ }
46
+ switch (config.pathConfig.type) {
47
+ case "default":
48
+ case "access": {
49
+ if (splitPath.length > 1) {
50
+ if (config.pathConfig.currentContext === null) {
51
+ this.addPropertiesToAnObject(schema, splitPath.slice(1), config.pathConfig.currentContext, childRef);
52
+ }
53
+ else {
54
+ if (!((_a = schema[defsPropertyName]) === null || _a === void 0 ? void 0 : _a[splitPath[0]])) {
55
+ schema[defsPropertyName] = Object.assign(Object.assign({}, schema[defsPropertyName]), { [splitPath[0]]: {} });
56
+ }
57
+ this.addPropertiesToAContext(schema[defsPropertyName][splitPath[0]], splitPath.slice(1), config.pathConfig.currentContext, childRef);
58
+ }
59
+ }
60
+ break;
61
+ }
62
+ case "repeat": {
63
+ this.addContext(schema, splitPath[splitPath.length - 1], // example items
64
+ config.pathConfig.currentContext, // example item
65
+ config.pathConfig.parentContext);
66
+ if (splitPath.length > 2) {
67
+ let updatedSchema = schema;
68
+ const hasParentContext = !!config.pathConfig.parentContext;
69
+ if (hasParentContext) {
70
+ updatedSchema = this.addPropertiesToAnObject((_b = schema[defsPropertyName]) === null || _b === void 0 ? void 0 : _b[config.pathConfig.parentContext], splitPath.slice(1, -1), config.pathConfig.parentContext, childRef);
71
+ }
72
+ this.addPropertiesToAnObject(updatedSchema, hasParentContext ? splitPath.slice(2) : splitPath.slice(1), config.pathConfig.currentContext, childRef, "array");
73
+ }
74
+ else if (splitPath.length > 1) {
75
+ let schemaDefinition;
76
+ if (config.pathConfig.parentContext) {
77
+ schemaDefinition = (_c = schema === null || schema === void 0 ? void 0 : schema[defsPropertyName]) === null || _c === void 0 ? void 0 : _c[config.pathConfig.parentContext];
78
+ }
79
+ this.addPropertiesToAnObject(schemaDefinition !== null && schemaDefinition !== void 0 ? schemaDefinition : schema, splitPath.slice(1), config.pathConfig.currentContext, childRef, "array");
80
+ }
81
+ else {
82
+ schema.type = "array";
83
+ schema[refPropertyName] = this.getDefsPath(config.pathConfig.currentContext);
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Gets the JSON schema for a property name
91
+ * @param rootPropertyName - the root property the JSON schema is mapped to
92
+ * @returns The JSON schema for the root property
93
+ */
94
+ getSchema(rootPropertyName) {
95
+ var _a;
96
+ return (_a = this.schemaMap.get(rootPropertyName)) !== null && _a !== void 0 ? _a : null;
97
+ }
98
+ /**
99
+ * Gets root properties
100
+ * @returns IterableIterator<string>
101
+ */
102
+ getRootProperties() {
103
+ return this.schemaMap.keys();
104
+ }
105
+ /**
106
+ * Get a path split into property names
107
+ * @param path - The dot syntax path, e.g. `a.b.c`.
108
+ * @returns An array of items in the path
109
+ */
110
+ getSplitPath(path) {
111
+ return path.split(".");
112
+ }
113
+ /**
114
+ * Gets the path to the $def
115
+ * @param context - The context name. For example, `item in items` creates the `item` context.
116
+ * @returns A string to use as a $ref
117
+ */
118
+ getDefsPath(context) {
119
+ return `#/${defsPropertyName}/${context}`;
120
+ }
121
+ /**
122
+ * Get the schema $id
123
+ * @param customElementName - The custom element name
124
+ * @param propertyName - The property name
125
+ * @returns The ID that can be used in the JSON schema as $id
126
+ */
127
+ getSchemaId(customElementName, propertyName) {
128
+ return `https://fast.design/schemas/${customElementName}/${propertyName}.json`;
129
+ }
130
+ /**
131
+ * Add a new JSON schema to the JSON schema map
132
+ * @param propertyName - The name of the property to assign this JSON schema to.
133
+ */
134
+ addNewSchema(propertyName) {
135
+ this.schemaMap.set(propertyName, {
136
+ $schema: "https://json-schema.org/draft/2019-09/schema",
137
+ $id: this.getSchemaId(this.customElementName, propertyName),
138
+ [defsPropertyName]: {},
139
+ });
140
+ }
141
+ /**
142
+ * Add properties to a context
143
+ * @param schema - The schema to add the properties to.
144
+ * @param splitPath - The path split into property/context names.
145
+ * @param context - The path context.
146
+ */
147
+ addPropertiesToAContext(schema, splitPath, context, childRef) {
148
+ schema.type = "object";
149
+ if (schema.properties && !schema.properties[splitPath[0]]) {
150
+ schema.properties[splitPath[0]] = {};
151
+ }
152
+ else if (!schema.properties) {
153
+ schema.properties = {
154
+ [splitPath[0]]: {},
155
+ };
156
+ }
157
+ if (splitPath.length > 1) {
158
+ this.addPropertiesToAnObject(schema.properties[splitPath[0]], splitPath.slice(1), context, childRef);
159
+ }
160
+ else if (childRef) {
161
+ if (schema.properties[splitPath[0]].anyOf) {
162
+ schema.properties[splitPath[0]].anyOf.push({
163
+ [refPropertyName]: childRef,
164
+ });
165
+ }
166
+ else {
167
+ schema.properties[splitPath[0]].anyOf = [{ [refPropertyName]: childRef }];
168
+ }
169
+ }
170
+ }
171
+ /**
172
+ * Add properties to an object
173
+ * @param schema - The schema to add the properties to.
174
+ * @param splitPath - The path split into property/context names.
175
+ * @param context - The path context.
176
+ * @param type - The data type (see JSON schema for details).
177
+ */
178
+ addPropertiesToAnObject(schema, splitPath, context, childRef, type = "object") {
179
+ schema.type = "object";
180
+ if (schema.properties && !schema.properties[splitPath[0]]) {
181
+ schema.properties[splitPath[0]] = {};
182
+ }
183
+ else if (!schema.properties) {
184
+ schema.properties = {
185
+ [splitPath[0]]: {},
186
+ };
187
+ }
188
+ if (type === "object" && splitPath.length > 1) {
189
+ return this.addPropertiesToAnObject(schema.properties[splitPath[0]], splitPath.slice(1), context, childRef, type);
190
+ }
191
+ else if (type === "array") {
192
+ if (splitPath.length > 1) {
193
+ return this.addPropertiesToAnObject(schema.properties[splitPath[0]], splitPath.slice(1), context, childRef, type);
194
+ }
195
+ else {
196
+ return this.addArrayToAnObject(schema.properties[splitPath[0]], context);
197
+ }
198
+ }
199
+ if (schema.properties[splitPath[0]].anyOf && childRef) {
200
+ schema.properties[splitPath[0]].anyOf.push({ [refPropertyName]: childRef });
201
+ }
202
+ else if (childRef) {
203
+ schema.properties[splitPath[0]].anyOf = [{ [refPropertyName]: childRef }];
204
+ }
205
+ return schema.properties[splitPath[0]];
206
+ }
207
+ /**
208
+ * Add an array to an object property
209
+ * @param schema - The schema to add the properties to.
210
+ * @param context - The name of the context.
211
+ */
212
+ addArrayToAnObject(schema, context) {
213
+ schema.type = "array";
214
+ schema.items = {
215
+ [refPropertyName]: this.getDefsPath(context),
216
+ };
217
+ return schema.items;
218
+ }
219
+ /**
220
+ * Add a context to the $defs property
221
+ * @param schema - The schema to use.
222
+ * @param propertyName - The name of the property the context belongs to.
223
+ * @param currentContext - The current context.
224
+ * @param parentContext - The parent context.
225
+ * @returns
226
+ */
227
+ addContext(schema, propertyName, // e.g items
228
+ currentContext, // e.g. item
229
+ parentContext) {
230
+ if (schema[defsPropertyName][currentContext]) {
231
+ return;
232
+ }
233
+ schema[defsPropertyName][currentContext] = {
234
+ [fastContextMetaData]: propertyName,
235
+ [fastContextsMetaData]: this.getParentContexts(schema, parentContext),
236
+ };
237
+ }
238
+ /**
239
+ * Get parent contexts
240
+ * @param schema - The schema to use.
241
+ * @param parentContext - The parent context.
242
+ * @param contexts - A list of parent contexts.
243
+ * @returns
244
+ */
245
+ getParentContexts(schema, parentContext, contexts = []) {
246
+ var _a;
247
+ if (parentContext === null) {
248
+ return [null, ...contexts];
249
+ }
250
+ const parentParentContext = (_a = schema === null || schema === void 0 ? void 0 : schema[defsPropertyName]) === null || _a === void 0 ? void 0 : _a[parentContext][fastContextsMetaData];
251
+ return this.getParentContexts(schema, parentParentContext[parentParentContext.length - 1], [parentContext, ...contexts]);
252
+ }
253
+ }
@@ -112,9 +112,9 @@ export const Context = Object.freeze({
112
112
  },
113
113
  /**
114
114
  * Enables an event target to provide a context value.
115
- * @param target The target to provide the context value for.
116
- * @param context The context to provide the value for.
117
- * @param value The value to provide for the context.
115
+ * @param target - The target to provide the context value for.
116
+ * @param context - The context to provide the value for.
117
+ * @param value - The value to provide for the context.
118
118
  */
119
119
  provide(target, context, value) {
120
120
  Context.handle(target, (event) => {
@@ -146,9 +146,9 @@ export const Context = Object.freeze({
146
146
  /**
147
147
  * Defines a getter-only property on the target that will return the context
148
148
  * value for the target.
149
- * @param target The target to define the property on.
150
- * @param propertyName The name of the property to define.
151
- * @param context The context that will be used to retrieve the property value.
149
+ * @param target - The target to define the property on.
150
+ * @param propertyName - The name of the property to define.
151
+ * @param context - The context that will be used to retrieve the property value.
152
152
  * @remarks
153
153
  * Uses the default request strategy to locate the context and will return the
154
154
  * initialValue if the context isn't handled.
@@ -0,0 +1,3 @@
1
+ export { css } from "./styles/css.js";
2
+ export { CSSDirective, cssDirective, } from "./styles/css-directive.js";
3
+ export { ElementStyles, } from "./styles/element-styles.js";