@lushly-dev/fast-element 3.0.1-preview.0 → 3.0.1-preview.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 (250) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/command/command.api.json +7857 -0
  3. package/dist/context/context.api.json +1084 -0
  4. package/dist/declarative/declarative.api.json +8130 -0
  5. package/dist/definition-schema/definition-schema.api.json +2689 -0
  6. package/dist/di/di.api.json +4945 -0
  7. package/dist/dts/arrays.d.ts +2 -0
  8. package/dist/dts/binding/binding.d.ts +59 -0
  9. package/dist/dts/binding/exports.d.ts +9 -0
  10. package/dist/dts/binding/normalize.d.ts +9 -0
  11. package/dist/dts/binding/one-time.d.ts +11 -0
  12. package/dist/dts/binding/one-way.d.ts +20 -0
  13. package/dist/dts/binding/signal.d.ts +36 -0
  14. package/dist/dts/binding/two-way.d.ts +44 -0
  15. package/dist/dts/command/behavior.d.ts +94 -0
  16. package/dist/dts/command/behaviors/confirm-behavior.d.ts +139 -0
  17. package/dist/dts/command/behaviors/undo-behavior.d.ts +178 -0
  18. package/dist/dts/command/command.d.ts +79 -0
  19. package/dist/dts/command/component-registry.d.ts +50 -0
  20. package/dist/dts/command/components/confirm-dialog.d.ts +117 -0
  21. package/dist/dts/command/index.d.ts +21 -0
  22. package/dist/dts/command/registry.d.ts +201 -0
  23. package/dist/dts/command/schema-validation.d.ts +45 -0
  24. package/dist/dts/command/types.d.ts +332 -0
  25. package/dist/dts/command/validation.d.ts +116 -0
  26. package/dist/dts/command/weak-ref.d.ts +11 -0
  27. package/dist/dts/components/attributes.d.ts +153 -0
  28. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  29. package/dist/dts/components/element-controller.d.ts +349 -0
  30. package/dist/dts/components/element-hydration.d.ts +2 -0
  31. package/dist/dts/components/enable-hydration.d.ts +66 -0
  32. package/dist/dts/components/fast-definitions.d.ts +211 -0
  33. package/dist/dts/components/fast-element-registry.d.ts +23 -0
  34. package/dist/dts/components/fast-element.d.ts +91 -0
  35. package/dist/dts/components/hydration-tracker.d.ts +110 -0
  36. package/dist/dts/components/hydration.d.ts +52 -0
  37. package/dist/dts/components/schema.d.ts +205 -0
  38. package/dist/dts/context.d.ts +171 -0
  39. package/dist/dts/debug.d.ts +5 -0
  40. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  41. package/dist/dts/declarative/debug.d.ts +4 -0
  42. package/dist/dts/declarative/index.d.ts +14 -0
  43. package/dist/dts/declarative/interfaces.d.ts +8 -0
  44. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  45. package/dist/dts/declarative/observer-map.d.ts +89 -0
  46. package/dist/dts/declarative/runtime.d.ts +5 -0
  47. package/dist/dts/declarative/syntax.d.ts +21 -0
  48. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  49. package/dist/dts/declarative/template-parser.d.ts +98 -0
  50. package/dist/dts/declarative/template.d.ts +9 -0
  51. package/dist/dts/declarative/utilities.d.ts +358 -0
  52. package/dist/dts/definition-schema/api.d.ts +42 -0
  53. package/dist/dts/definition-schema/cem.d.ts +78 -0
  54. package/dist/dts/definition-schema/extension.d.ts +18 -0
  55. package/dist/dts/definition-schema/extract.d.ts +38 -0
  56. package/dist/dts/definition-schema/index.d.ts +9 -0
  57. package/dist/dts/definition-schema/storage.d.ts +35 -0
  58. package/dist/dts/definition-schema/types.d.ts +176 -0
  59. package/dist/dts/dev-mode.d.ts +13 -0
  60. package/dist/dts/di/di.d.ts +894 -0
  61. package/dist/dts/dom-policy.d.ts +101 -0
  62. package/dist/dts/dom.d.ts +88 -0
  63. package/dist/dts/hydration/diagnostics.d.ts +93 -0
  64. package/dist/dts/hydration/exports.d.ts +18 -0
  65. package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
  66. package/dist/dts/hydration/messages.d.ts +62 -0
  67. package/dist/dts/hydration/runtime.d.ts +7 -0
  68. package/dist/dts/hydration/target-builder.d.ts +107 -0
  69. package/dist/dts/index.d.ts +51 -0
  70. package/dist/dts/index.debug.d.ts +1 -0
  71. package/dist/dts/index.rollup.d.ts +1 -0
  72. package/dist/dts/index.rollup.debug.d.ts +1 -0
  73. package/dist/dts/interfaces.d.ts +106 -0
  74. package/dist/dts/metadata.d.ts +26 -0
  75. package/dist/dts/observation/arrays.d.ts +248 -0
  76. package/dist/dts/observation/notifier.d.ts +127 -0
  77. package/dist/dts/observation/observable.d.ts +276 -0
  78. package/dist/dts/observation/update-queue.d.ts +40 -0
  79. package/dist/dts/observation/volatile.d.ts +9 -0
  80. package/dist/dts/platform.d.ts +87 -0
  81. package/dist/dts/registry.d.ts +2 -0
  82. package/dist/dts/render.d.ts +7 -0
  83. package/dist/dts/schema.d.ts +1 -0
  84. package/dist/dts/scoped/detection.d.ts +55 -0
  85. package/dist/dts/scoped/index.d.ts +68 -0
  86. package/dist/dts/scoped/mixin.d.ts +118 -0
  87. package/dist/dts/scoped/registry.d.ts +76 -0
  88. package/dist/dts/scoped/types.d.ts +48 -0
  89. package/dist/dts/state/exports.d.ts +3 -0
  90. package/dist/dts/state/reactive.d.ts +8 -0
  91. package/dist/dts/state/state.d.ts +141 -0
  92. package/dist/dts/state/visitor.d.ts +6 -0
  93. package/dist/dts/state/watch.d.ts +10 -0
  94. package/dist/dts/styles/css-directive.d.ts +50 -0
  95. package/dist/dts/styles/css.d.ts +34 -0
  96. package/dist/dts/styles/element-styles.d.ts +61 -0
  97. package/dist/dts/styles/host.d.ts +65 -0
  98. package/dist/dts/styles/style-strategy.d.ts +42 -0
  99. package/dist/dts/templating/children.d.ts +62 -0
  100. package/dist/dts/templating/compiler.d.ts +54 -0
  101. package/dist/dts/templating/html-binding-directive.d.ts +155 -0
  102. package/dist/dts/templating/html-directive.d.ts +218 -0
  103. package/dist/dts/templating/html.d.ts +1 -0
  104. package/dist/dts/templating/hydration-view.d.ts +130 -0
  105. package/dist/dts/templating/markup.d.ts +48 -0
  106. package/dist/dts/templating/node-observation.d.ts +99 -0
  107. package/dist/dts/templating/ref.d.ts +23 -0
  108. package/dist/dts/templating/render.d.ts +318 -0
  109. package/dist/dts/templating/repeat.d.ts +131 -0
  110. package/dist/dts/templating/slotted.d.ts +38 -0
  111. package/dist/dts/templating/template.d.ts +221 -0
  112. package/dist/dts/templating/view.d.ts +268 -0
  113. package/dist/dts/templating/when.d.ts +12 -0
  114. package/dist/dts/testing/exports.d.ts +3 -0
  115. package/dist/dts/testing/fakes.d.ts +16 -0
  116. package/dist/dts/testing/fixture.d.ts +84 -0
  117. package/dist/dts/testing/models.d.ts +20 -0
  118. package/dist/dts/testing/timeout.d.ts +7 -0
  119. package/dist/dts/trust/index.d.ts +8 -0
  120. package/dist/dts/trust/types.d.ts +48 -0
  121. package/dist/dts/trust/utils.d.ts +26 -0
  122. package/dist/dts/tsdoc-metadata.json +11 -0
  123. package/dist/dts/utilities.d.ts +76 -0
  124. package/dist/esm/arrays.js +1 -0
  125. package/dist/esm/binding/binding.js +18 -0
  126. package/dist/esm/binding/exports.js +6 -0
  127. package/dist/esm/binding/normalize.js +17 -0
  128. package/dist/esm/binding/one-time.js +21 -0
  129. package/dist/esm/binding/one-way.js +30 -0
  130. package/dist/esm/binding/signal.js +99 -0
  131. package/dist/esm/binding/two-way.js +109 -0
  132. package/dist/esm/command/behavior.js +155 -0
  133. package/dist/esm/command/behaviors/confirm-behavior.js +225 -0
  134. package/dist/esm/command/behaviors/undo-behavior.js +313 -0
  135. package/dist/esm/command/command.js +104 -0
  136. package/dist/esm/command/component-registry.js +107 -0
  137. package/dist/esm/command/components/confirm-dialog.js +370 -0
  138. package/dist/esm/command/index.js +22 -0
  139. package/dist/esm/command/registry.js +755 -0
  140. package/dist/esm/command/schema-validation.js +194 -0
  141. package/dist/esm/command/types.js +86 -0
  142. package/dist/esm/command/validation.js +508 -0
  143. package/dist/esm/command/weak-ref.js +5 -0
  144. package/dist/esm/components/attributes.js +219 -0
  145. package/dist/esm/components/definition-schema-transforms.js +23 -0
  146. package/dist/esm/components/element-controller.js +840 -0
  147. package/dist/esm/components/element-hydration.js +2 -0
  148. package/dist/esm/components/enable-hydration.js +123 -0
  149. package/dist/esm/components/fast-definitions.js +294 -0
  150. package/dist/esm/components/fast-element-registry.js +67 -0
  151. package/dist/esm/components/fast-element.js +82 -0
  152. package/dist/esm/components/hydration-tracker.js +211 -0
  153. package/dist/esm/components/hydration.js +187 -0
  154. package/dist/esm/components/schema.js +253 -0
  155. package/dist/esm/context.js +185 -0
  156. package/dist/esm/debug.js +71 -0
  157. package/dist/esm/declarative/attribute-map.js +122 -0
  158. package/dist/esm/declarative/debug.js +4 -0
  159. package/dist/esm/declarative/index.js +10 -0
  160. package/dist/esm/declarative/interfaces.js +9 -0
  161. package/dist/esm/declarative/observer-map-utilities.js +565 -0
  162. package/dist/esm/declarative/observer-map.js +216 -0
  163. package/dist/esm/declarative/runtime.js +14 -0
  164. package/dist/esm/declarative/syntax.js +36 -0
  165. package/dist/esm/declarative/template-bridge.js +160 -0
  166. package/dist/esm/declarative/template-parser.js +306 -0
  167. package/dist/esm/declarative/template.js +116 -0
  168. package/dist/esm/declarative/utilities.js +1069 -0
  169. package/dist/esm/definition-schema/api.js +129 -0
  170. package/dist/esm/definition-schema/cem.js +89 -0
  171. package/dist/esm/definition-schema/extension.js +53 -0
  172. package/dist/esm/definition-schema/extract.js +167 -0
  173. package/dist/esm/definition-schema/index.js +8 -0
  174. package/dist/esm/definition-schema/storage.js +58 -0
  175. package/dist/esm/definition-schema/types.js +8 -0
  176. package/dist/esm/dev-mode.js +22 -0
  177. package/dist/esm/di/di.js +1441 -0
  178. package/dist/esm/dom-policy.js +374 -0
  179. package/dist/esm/dom.js +101 -0
  180. package/dist/esm/hydration/diagnostics.js +50 -0
  181. package/dist/esm/hydration/exports.js +6 -0
  182. package/dist/esm/hydration/hydration-debugger.js +112 -0
  183. package/dist/esm/hydration/messages.js +84 -0
  184. package/dist/esm/hydration/runtime.js +33 -0
  185. package/dist/esm/hydration/target-builder.js +264 -0
  186. package/dist/esm/index.debug.js +3 -0
  187. package/dist/esm/index.js +49 -0
  188. package/dist/esm/index.rollup.debug.js +6 -0
  189. package/dist/esm/index.rollup.js +4 -0
  190. package/dist/esm/interfaces.js +55 -0
  191. package/dist/esm/metadata.js +57 -0
  192. package/dist/esm/observation/arrays.js +661 -0
  193. package/dist/esm/observation/notifier.js +162 -0
  194. package/dist/esm/observation/observable.js +324 -0
  195. package/dist/esm/observation/update-queue.js +56 -0
  196. package/dist/esm/observation/volatile.js +16 -0
  197. package/dist/esm/platform.js +98 -0
  198. package/dist/esm/registry.js +2 -0
  199. package/dist/esm/render.js +1 -0
  200. package/dist/esm/schema.js +1 -0
  201. package/dist/esm/scoped/detection.js +102 -0
  202. package/dist/esm/scoped/index.js +69 -0
  203. package/dist/esm/scoped/mixin.js +127 -0
  204. package/dist/esm/scoped/registry.js +125 -0
  205. package/dist/esm/scoped/types.js +4 -0
  206. package/dist/esm/state/exports.js +3 -0
  207. package/dist/esm/state/reactive.js +34 -0
  208. package/dist/esm/state/state.js +148 -0
  209. package/dist/esm/state/visitor.js +28 -0
  210. package/dist/esm/state/watch.js +36 -0
  211. package/dist/esm/styles/css-directive.js +36 -0
  212. package/dist/esm/styles/css.js +56 -0
  213. package/dist/esm/styles/element-styles.js +144 -0
  214. package/dist/esm/styles/host.js +1 -0
  215. package/dist/esm/styles/style-strategy.js +1 -0
  216. package/dist/esm/templating/children.js +67 -0
  217. package/dist/esm/templating/compiler.js +359 -0
  218. package/dist/esm/templating/html-binding-directive.js +288 -0
  219. package/dist/esm/templating/html-directive.js +113 -0
  220. package/dist/esm/templating/html.js +1 -0
  221. package/dist/esm/templating/hydration-view.js +228 -0
  222. package/dist/esm/templating/markup.js +83 -0
  223. package/dist/esm/templating/node-observation.js +84 -0
  224. package/dist/esm/templating/ref.js +21 -0
  225. package/dist/esm/templating/render.js +468 -0
  226. package/dist/esm/templating/repeat.js +434 -0
  227. package/dist/esm/templating/slotted.js +49 -0
  228. package/dist/esm/templating/template.js +206 -0
  229. package/dist/esm/templating/view.js +298 -0
  230. package/dist/esm/templating/when.js +22 -0
  231. package/dist/esm/testing/exports.js +3 -0
  232. package/dist/esm/testing/fakes.js +107 -0
  233. package/dist/esm/testing/fixture.js +86 -0
  234. package/dist/esm/testing/models.js +58 -0
  235. package/dist/esm/testing/timeout.js +24 -0
  236. package/dist/esm/trust/index.js +7 -0
  237. package/dist/esm/trust/types.js +6 -0
  238. package/dist/esm/trust/utils.js +126 -0
  239. package/dist/esm/utilities.js +140 -0
  240. package/dist/fast-element.api.json +26798 -0
  241. package/dist/fast-element.d.ts +3985 -0
  242. package/dist/fast-element.debug.js +7604 -0
  243. package/dist/fast-element.debug.min.js +3 -0
  244. package/dist/fast-element.js +7603 -0
  245. package/dist/fast-element.min.js +3 -0
  246. package/dist/fast-element.untrimmed.d.ts +4103 -0
  247. package/dist/observation/arrays/arrays.api.json +2621 -0
  248. package/dist/scoped/scoped.api.json +891 -0
  249. package/dist/trust/trust.api.json +629 -0
  250. package/package.json +21 -23
@@ -0,0 +1,211 @@
1
+ import { FASTElementDefinition } from "./fast-definitions.js";
2
+ /**
3
+ * Describes when FAST should stop hydrating newly connected prerendered elements.
4
+ * @public
5
+ */
6
+ export const StopHydration = Object.freeze({
7
+ /**
8
+ * Stop hydrating new prerendered elements after the active hydration batch completes.
9
+ */
10
+ hydrationComplete: "hydration-complete",
11
+ /**
12
+ * Keep the hydration hook active for later prerendered elements.
13
+ */
14
+ never: "never",
15
+ });
16
+ /**
17
+ * Tracks prerendered elements through the hydration lifecycle and
18
+ * exposes the active global hydration completion promise.
19
+ *
20
+ * @public
21
+ */
22
+ export class HydrationTracker {
23
+ constructor(options) {
24
+ var _a;
25
+ this.elements = new Set();
26
+ this.elementTags = new WeakMap();
27
+ this.tagHydrationStates = new Map();
28
+ this.started = false;
29
+ this.completed = false;
30
+ this.checkTimer = null;
31
+ this.resolveWhenHydrated = null;
32
+ this.prepareHydrationPromise();
33
+ this.stopHydration = (_a = options.stopHydration) !== null && _a !== void 0 ? _a : StopHydration.hydrationComplete;
34
+ }
35
+ /**
36
+ * Resolves when the active hydration batch completes, or when hydration work
37
+ * for the specified tag name completes.
38
+ */
39
+ whenHydrated(tagName) {
40
+ if (tagName !== void 0) {
41
+ return this.getTagHydrationPromise(tagName);
42
+ }
43
+ return this._whenHydrated;
44
+ }
45
+ /**
46
+ * Indicates whether the hydration hook should attempt to hydrate
47
+ * prerendered elements.
48
+ */
49
+ get shouldHydrate() {
50
+ return !this.completed || this.stopHydration === StopHydration.never;
51
+ }
52
+ /**
53
+ * Registers an element as pending hydration.
54
+ */
55
+ add(element) {
56
+ var _a;
57
+ var _b;
58
+ this.completed = false;
59
+ if (!this.started) {
60
+ this.started = true;
61
+ if (this.resolveWhenHydrated === null) {
62
+ this.prepareHydrationPromise();
63
+ }
64
+ }
65
+ if (!this.elements.has(element)) {
66
+ const tagName = (_b = (_a = FASTElementDefinition.getForInstance(element)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : element.localName;
67
+ this.elements.add(element);
68
+ this.elementTags.set(element, tagName);
69
+ this.addTagHydration(tagName);
70
+ }
71
+ }
72
+ /**
73
+ * Removes an element from the pending set and schedules
74
+ * a debounced completion check.
75
+ */
76
+ remove(element) {
77
+ if (this.elements.delete(element)) {
78
+ const tagName = this.elementTags.get(element);
79
+ if (tagName !== void 0) {
80
+ this.elementTags.delete(element);
81
+ this.removeTagHydration(tagName);
82
+ }
83
+ }
84
+ // Debounce: reset on every removal so we wait until no
85
+ // new elements arrive before declaring complete.
86
+ if (this.checkTimer !== null) {
87
+ clearTimeout(this.checkTimer);
88
+ }
89
+ if (this.elements.size === 0) {
90
+ this.checkTimer = setTimeout(() => {
91
+ this.checkTimer = null;
92
+ if (this.elements.size === 0) {
93
+ if (this.stopHydration !== StopHydration.never) {
94
+ this.resolveHydrationPromise();
95
+ this.completed = true;
96
+ }
97
+ this.started = false;
98
+ }
99
+ }, 0);
100
+ }
101
+ }
102
+ /**
103
+ * Merges additional options into the tracker.
104
+ */
105
+ mergeOptions(incoming) {
106
+ if (incoming.stopHydration !== void 0) {
107
+ this.stopHydration = incoming.stopHydration;
108
+ if (incoming.stopHydration === StopHydration.never &&
109
+ this.resolveWhenHydrated === null) {
110
+ this.prepareHydrationPromise();
111
+ }
112
+ }
113
+ }
114
+ prepareHydrationPromise() {
115
+ this._whenHydrated = new Promise(resolve => {
116
+ this.resolveWhenHydrated = resolve;
117
+ });
118
+ }
119
+ getTagHydrationPromise(tagName) {
120
+ const state = this.getTagHydrationState(tagName);
121
+ if (this.completed && this.stopHydration !== StopHydration.never) {
122
+ this.resolveTagHydrationState(state);
123
+ }
124
+ return state.promise;
125
+ }
126
+ addTagHydration(tagName) {
127
+ const state = this.getTagHydrationState(tagName);
128
+ if (state.resolveTimer !== null) {
129
+ clearTimeout(state.resolveTimer);
130
+ state.resolveTimer = null;
131
+ }
132
+ if (state.resolved) {
133
+ this.prepareTagHydrationState(state);
134
+ }
135
+ state.pendingCount++;
136
+ }
137
+ removeTagHydration(tagName) {
138
+ const state = this.getTagHydrationState(tagName);
139
+ if (state.pendingCount > 0) {
140
+ state.pendingCount--;
141
+ }
142
+ if (state.pendingCount === 0) {
143
+ this.scheduleTagHydrationResolution(state);
144
+ }
145
+ }
146
+ getTagHydrationState(tagName) {
147
+ const normalizedTagName = tagName.toLowerCase();
148
+ let state = this.tagHydrationStates.get(normalizedTagName);
149
+ if (state === void 0) {
150
+ state = this.createTagHydrationState();
151
+ this.tagHydrationStates.set(normalizedTagName, state);
152
+ }
153
+ return state;
154
+ }
155
+ createTagHydrationState() {
156
+ let resolve;
157
+ const promise = new Promise(settle => {
158
+ resolve = settle;
159
+ });
160
+ return {
161
+ promise,
162
+ pendingCount: 0,
163
+ resolve,
164
+ resolveTimer: null,
165
+ resolved: false,
166
+ };
167
+ }
168
+ prepareTagHydrationState(state) {
169
+ let resolve;
170
+ state.promise = new Promise(settle => {
171
+ resolve = settle;
172
+ });
173
+ state.resolve = resolve;
174
+ state.resolved = false;
175
+ }
176
+ resolveTagHydrationState(state) {
177
+ if (state.resolved) {
178
+ return;
179
+ }
180
+ if (state.resolveTimer !== null) {
181
+ clearTimeout(state.resolveTimer);
182
+ state.resolveTimer = null;
183
+ }
184
+ state.resolved = true;
185
+ state.resolve();
186
+ }
187
+ scheduleTagHydrationResolution(state) {
188
+ if (state.resolveTimer !== null) {
189
+ clearTimeout(state.resolveTimer);
190
+ }
191
+ state.resolveTimer = setTimeout(() => {
192
+ state.resolveTimer = null;
193
+ if (state.pendingCount === 0) {
194
+ this.resolveTagHydrationState(state);
195
+ }
196
+ }, 0);
197
+ }
198
+ resolveTagHydrationPromises() {
199
+ for (const state of this.tagHydrationStates.values()) {
200
+ if (state.pendingCount === 0) {
201
+ this.resolveTagHydrationState(state);
202
+ }
203
+ }
204
+ }
205
+ resolveHydrationPromise() {
206
+ const resolve = this.resolveWhenHydrated;
207
+ this.resolveWhenHydrated = null;
208
+ resolve === null || resolve === void 0 ? void 0 : resolve();
209
+ this.resolveTagHydrationPromises();
210
+ }
211
+ }
@@ -0,0 +1,187 @@
1
+ import { Message } from "../interfaces.js";
2
+ import { FAST } from "../platform.js";
3
+ /**
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.
10
+ *
11
+ * Content binding markers bracket text/template content:
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-->
19
+ *
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)
23
+ *
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.
27
+ */
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})$/;
34
+ function isComment(node) {
35
+ return node && node.nodeType === Node.COMMENT_NODE;
36
+ }
37
+ /**
38
+ * Markup utilities to aid in template hydration.
39
+ * @internal
40
+ */
41
+ export const HydrationMarkup = Object.freeze({
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";
49
+ },
50
+ contentBindingEndMarker() {
51
+ return "fe:/b";
52
+ },
53
+ // Repeat item markers (no arguments)
54
+ repeatStartMarker() {
55
+ return "fe:r";
56
+ },
57
+ repeatEndMarker() {
58
+ return "fe:/r";
59
+ },
60
+ // Element boundary markers (no arguments)
61
+ elementBoundaryStartMarker() {
62
+ return "fe:e";
63
+ },
64
+ elementBoundaryEndMarker() {
65
+ return "fe:/e";
66
+ },
67
+ // Detection — simple string equality
68
+ isContentBindingStartMarker(data) {
69
+ return data === "fe:b" || legacyBindingStartMarker.test(data);
70
+ },
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);
79
+ },
80
+ isElementBoundaryStartMarker(node) {
81
+ return (isComment(node) &&
82
+ (node.data === "fe:e" || legacyElementBoundaryStartMarker.test(node.data)));
83
+ },
84
+ isElementBoundaryEndMarker(node) {
85
+ return (isComment(node) &&
86
+ (node.data === "fe:/e" || legacyElementBoundaryEndMarker.test(node.data)));
87
+ },
88
+ /**
89
+ * Returns the count of attribute bindings on the element, or null
90
+ * if no attribute binding marker is present.
91
+ *
92
+ * Parses the `data-fe="N"` attribute format where N is the count
93
+ * of attribute binding factories targeting this element.
94
+ */
95
+ parseAttributeBindingCount(node) {
96
+ const attr = node.getAttribute(this.attributeMarkerName);
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;
121
+ }
122
+ const index = Number(value);
123
+ if (!Number.isInteger(index) || index < 0) {
124
+ throw FAST.error(Message.invalidHydrationAttributeMarker, {
125
+ value: attr,
126
+ });
127
+ }
128
+ indices.push(index);
129
+ }
130
+ }
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
+ }
160
+ }
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
+ }
170
+ }
171
+ },
172
+ parseLegacyContentBindingStartIndex(data) {
173
+ return parseLegacyIntMarker(legacyBindingStartMarker, data);
174
+ },
175
+ });
176
+ function parseLegacyIntMarker(pattern, data) {
177
+ const match = pattern.exec(data);
178
+ return match === null ? null : Number(match[1]);
179
+ }
180
+ /**
181
+ * @internal
182
+ */
183
+ export const Hydratable = Symbol.for("fe-hydration");
184
+ /** @beta */
185
+ export function isHydratable(value) {
186
+ return value[Hydratable] === Hydratable;
187
+ }
@@ -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
+ }