@microsoft/fast-element 2.10.3 → 3.0.0-rc.1

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 (351) hide show
  1. package/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +1 -1
  2. package/ARCHITECTURE_OVERVIEW.md +2 -2
  3. package/CHANGELOG.json +31 -1
  4. package/CHANGELOG.md +10 -2
  5. package/DECLARATIVE_DESIGN.md +806 -0
  6. package/DECLARATIVE_HTML.md +470 -0
  7. package/DECLARATIVE_MIGRATION.md +215 -0
  8. package/DECLARATIVE_RENDERING.md +530 -0
  9. package/DECLARATIVE_RENDERING_LIFECYCLE.md +288 -0
  10. package/DECLARATIVE_SCHEMA_OBSERVER_MAP.md +489 -0
  11. package/DESIGN.md +143 -34
  12. package/MIGRATION.md +387 -0
  13. package/README.md +208 -1
  14. package/SIZES.md +25 -0
  15. package/api-extractor.arrays.json +15 -0
  16. package/api-extractor.context.json +1 -0
  17. package/api-extractor.declarative.json +15 -0
  18. package/api-extractor.di.json +1 -0
  19. package/api-extractor.hydration.json +15 -0
  20. package/api-extractor.styles.json +15 -0
  21. package/dist/arrays/arrays.api.json +2621 -0
  22. package/dist/context/context.api.json +1 -1
  23. package/dist/declarative/declarative.api.json +7844 -0
  24. package/dist/di/di.api.json +2 -2
  25. package/dist/dts/array-observer.d.ts +2 -0
  26. package/dist/dts/arrays.d.ts +2 -0
  27. package/dist/dts/attr.d.ts +1 -0
  28. package/dist/dts/binding/signal.d.ts +6 -6
  29. package/dist/dts/binding/two-way.d.ts +1 -0
  30. package/dist/dts/binding.d.ts +7 -0
  31. package/dist/dts/components/attributes.d.ts +2 -5
  32. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  33. package/dist/dts/components/element-controller.d.ts +80 -114
  34. package/dist/dts/components/element-hydration.d.ts +1 -1
  35. package/dist/dts/components/enable-hydration.d.ts +34 -0
  36. package/dist/dts/components/fast-definitions.d.ts +91 -42
  37. package/dist/dts/components/fast-element.d.ts +5 -8
  38. package/dist/dts/components/hydration-tracker.d.ts +40 -0
  39. package/dist/dts/components/hydration.d.ts +18 -53
  40. package/dist/dts/components/schema.d.ts +205 -0
  41. package/dist/dts/context.d.ts +6 -6
  42. package/dist/dts/css.d.ts +3 -0
  43. package/dist/dts/debug.d.ts +5 -1
  44. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  45. package/dist/dts/declarative/debug.d.ts +5 -0
  46. package/dist/dts/declarative/index.d.ts +13 -0
  47. package/dist/dts/declarative/interfaces.d.ts +9 -0
  48. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  49. package/dist/dts/declarative/observer-map.d.ts +89 -0
  50. package/dist/dts/declarative/runtime.d.ts +5 -0
  51. package/dist/dts/declarative/syntax.d.ts +21 -0
  52. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  53. package/dist/dts/declarative/template-parser.d.ts +98 -0
  54. package/dist/dts/declarative/template.d.ts +9 -0
  55. package/dist/dts/declarative/utilities.d.ts +312 -0
  56. package/dist/dts/di/di.d.ts +1 -1
  57. package/dist/dts/directives/children.d.ts +2 -0
  58. package/dist/dts/directives/node-observation.d.ts +2 -0
  59. package/dist/dts/directives/ref.d.ts +2 -0
  60. package/dist/dts/directives/repeat.d.ts +4 -0
  61. package/dist/dts/directives/slotted.d.ts +2 -0
  62. package/dist/dts/directives/when.d.ts +3 -0
  63. package/dist/dts/dom-policy.d.ts +1 -1
  64. package/dist/dts/html.d.ts +5 -0
  65. package/dist/dts/hydration/runtime.d.ts +7 -0
  66. package/dist/dts/hydration/target-builder.d.ts +15 -12
  67. package/dist/dts/hydration.d.ts +14 -0
  68. package/dist/dts/index.d.ts +38 -42
  69. package/dist/dts/index.debug.d.ts +0 -1
  70. package/dist/dts/index.rollup.debug.d.ts +0 -1
  71. package/dist/dts/interfaces.d.ts +1 -49
  72. package/dist/dts/observable.d.ts +3 -6
  73. package/dist/dts/observation/arrays.d.ts +1 -1
  74. package/dist/dts/observation/update-queue.d.ts +1 -1
  75. package/dist/dts/platform.d.ts +25 -4
  76. package/dist/dts/render.d.ts +7 -0
  77. package/dist/dts/schema.d.ts +1 -0
  78. package/dist/dts/state/exports.d.ts +1 -1
  79. package/dist/dts/state/state.d.ts +2 -2
  80. package/dist/dts/styles/css-directive.d.ts +5 -12
  81. package/dist/dts/styles/css.d.ts +5 -7
  82. package/dist/dts/styles/element-styles.d.ts +0 -10
  83. package/dist/dts/styles.d.ts +6 -0
  84. package/dist/dts/templating/children.d.ts +1 -1
  85. package/dist/dts/templating/html-binding-directive.d.ts +10 -0
  86. package/dist/dts/templating/html-directive.d.ts +17 -0
  87. package/dist/dts/templating/hydration-view.d.ts +109 -0
  88. package/dist/dts/templating/ref.d.ts +1 -1
  89. package/dist/dts/templating/render.d.ts +8 -2
  90. package/dist/dts/templating/repeat.d.ts +2 -2
  91. package/dist/dts/templating/slotted.d.ts +1 -1
  92. package/dist/dts/templating/template.d.ts +17 -9
  93. package/dist/dts/templating/view.d.ts +25 -102
  94. package/dist/dts/templating/when.d.ts +1 -1
  95. package/dist/dts/templating.d.ts +10 -0
  96. package/dist/dts/testing/exports.d.ts +2 -2
  97. package/dist/dts/tsdoc-metadata.json +1 -1
  98. package/dist/dts/updates.d.ts +1 -0
  99. package/dist/dts/volatile.d.ts +2 -0
  100. package/dist/esm/array-observer.js +1 -0
  101. package/dist/esm/arrays.js +1 -0
  102. package/dist/esm/attr.js +1 -0
  103. package/dist/esm/binding/normalize.js +1 -1
  104. package/dist/esm/binding/signal.js +4 -4
  105. package/dist/esm/binding/two-way.js +2 -1
  106. package/dist/esm/binding.js +4 -0
  107. package/dist/esm/components/attributes.js +8 -5
  108. package/dist/esm/components/definition-schema-transforms.js +23 -0
  109. package/dist/esm/components/element-controller.js +200 -269
  110. package/dist/esm/components/element-hydration.js +1 -1
  111. package/dist/esm/components/enable-hydration.js +100 -0
  112. package/dist/esm/components/fast-definitions.js +211 -49
  113. package/dist/esm/components/fast-element.js +18 -27
  114. package/dist/esm/components/hydration-tracker.js +93 -0
  115. package/dist/esm/components/hydration.js +62 -144
  116. package/dist/esm/components/schema.js +253 -0
  117. package/dist/esm/context.js +6 -6
  118. package/dist/esm/css.js +3 -0
  119. package/dist/esm/debug.js +26 -26
  120. package/dist/esm/declarative/attribute-map.js +121 -0
  121. package/dist/esm/declarative/debug.js +5 -0
  122. package/dist/esm/declarative/index.js +3 -0
  123. package/dist/esm/declarative/interfaces.js +10 -0
  124. package/dist/esm/declarative/observer-map-utilities.js +562 -0
  125. package/dist/esm/declarative/observer-map.js +216 -0
  126. package/dist/esm/declarative/runtime.js +14 -0
  127. package/dist/esm/declarative/syntax.js +36 -0
  128. package/dist/esm/declarative/template-bridge.js +170 -0
  129. package/dist/esm/declarative/template-parser.js +306 -0
  130. package/dist/esm/declarative/template.js +142 -0
  131. package/dist/esm/declarative/utilities.js +834 -0
  132. package/dist/esm/di/di.js +6 -8
  133. package/dist/esm/directives/children.js +1 -0
  134. package/dist/esm/directives/node-observation.js +1 -0
  135. package/dist/esm/directives/ref.js +1 -0
  136. package/dist/esm/directives/repeat.js +1 -0
  137. package/dist/esm/directives/slotted.js +1 -0
  138. package/dist/esm/directives/when.js +1 -0
  139. package/dist/esm/dom-policy.js +2 -2
  140. package/dist/esm/dom.js +1 -1
  141. package/dist/esm/html.js +2 -0
  142. package/dist/esm/hydration/runtime.js +33 -0
  143. package/dist/esm/hydration/target-builder.js +97 -90
  144. package/dist/esm/hydration.js +4 -0
  145. package/dist/esm/index.debug.js +2 -1
  146. package/dist/esm/index.js +34 -29
  147. package/dist/esm/index.rollup.debug.js +3 -2
  148. package/dist/esm/index.rollup.js +1 -1
  149. package/dist/esm/interfaces.js +1 -45
  150. package/dist/esm/observable.js +1 -4
  151. package/dist/esm/observation/arrays.js +1 -1
  152. package/dist/esm/observation/observable.js +5 -5
  153. package/dist/esm/observation/update-queue.js +47 -58
  154. package/dist/esm/platform.js +31 -30
  155. package/dist/esm/render.js +1 -0
  156. package/dist/esm/schema.js +1 -0
  157. package/dist/esm/state/exports.js +1 -1
  158. package/dist/esm/styles/css-directive.js +1 -2
  159. package/dist/esm/styles/css.js +15 -56
  160. package/dist/esm/styles/element-styles.js +69 -15
  161. package/dist/esm/styles.js +2 -0
  162. package/dist/esm/templating/html-binding-directive.js +24 -10
  163. package/dist/esm/templating/hydration-view.js +235 -0
  164. package/dist/esm/templating/render.js +13 -2
  165. package/dist/esm/templating/repeat.js +36 -34
  166. package/dist/esm/templating/template.js +7 -7
  167. package/dist/esm/templating/view.js +24 -233
  168. package/dist/esm/templating.js +7 -0
  169. package/dist/esm/testing/exports.js +2 -2
  170. package/dist/esm/updates.js +1 -0
  171. package/dist/esm/volatile.js +1 -0
  172. package/dist/fast-element.api.json +9017 -6996
  173. package/dist/fast-element.d.ts +3557 -796
  174. package/dist/fast-element.debug.js +5093 -4419
  175. package/dist/fast-element.debug.min.js +2 -2
  176. package/dist/fast-element.js +5398 -4655
  177. package/dist/fast-element.min.js +2 -2
  178. package/dist/fast-element.untrimmed.d.ts +881 -481
  179. package/dist/hydration/hydration.api.json +5237 -0
  180. package/dist/styles/styles.api.json +2672 -0
  181. package/docs/api-report.api.md +344 -167
  182. package/docs/arrays/api-report.api.md +114 -0
  183. package/docs/declarative/api-report.api.md +397 -0
  184. package/docs/hydration/api-report.api.md +285 -0
  185. package/docs/styles/api-report.api.md +135 -0
  186. package/package.json +149 -40
  187. package/playwright.declarative.config.ts +26 -0
  188. package/playwright.declarative.webui.config.ts +20 -0
  189. package/scripts/declarative/build-fixtures-with-webui.js +135 -0
  190. package/scripts/declarative/build-fixtures.js +49 -0
  191. package/scripts/declarative/build-fixtures.utilities.js +101 -0
  192. package/scripts/measure-sizes.js +219 -0
  193. package/scripts/run-api-extractor.js +39 -20
  194. package/test/declarative/fixtures/README.md +72 -0
  195. package/test/declarative/fixtures/WRITING_FIXTURES.md +330 -0
  196. package/test/declarative/fixtures/bindings/README.md +12 -0
  197. package/test/declarative/fixtures/bindings/attribute/entry.html +13 -0
  198. package/test/declarative/fixtures/bindings/attribute/fast-build.config.json +6 -0
  199. package/test/declarative/fixtures/bindings/attribute/index.html +25 -0
  200. package/test/declarative/fixtures/bindings/attribute/main.ts +41 -0
  201. package/test/declarative/fixtures/bindings/attribute/state.json +8 -0
  202. package/test/declarative/fixtures/bindings/attribute/templates.html +11 -0
  203. package/test/declarative/fixtures/bindings/content/entry.html +12 -0
  204. package/test/declarative/fixtures/bindings/content/fast-build.config.json +6 -0
  205. package/test/declarative/fixtures/bindings/content/index.html +19 -0
  206. package/test/declarative/fixtures/bindings/content/main.ts +27 -0
  207. package/test/declarative/fixtures/bindings/content/state.json +4 -0
  208. package/test/declarative/fixtures/bindings/content/templates.html +6 -0
  209. package/test/declarative/fixtures/bindings/dot-syntax/entry.html +11 -0
  210. package/test/declarative/fixtures/bindings/dot-syntax/fast-build.config.json +6 -0
  211. package/test/declarative/fixtures/bindings/dot-syntax/index.html +47 -0
  212. package/test/declarative/fixtures/bindings/dot-syntax/main.ts +59 -0
  213. package/test/declarative/fixtures/bindings/dot-syntax/state.json +16 -0
  214. package/test/declarative/fixtures/bindings/dot-syntax/templates.html +17 -0
  215. package/test/declarative/fixtures/bindings/event/entry.html +11 -0
  216. package/test/declarative/fixtures/bindings/event/fast-build.config.json +6 -0
  217. package/test/declarative/fixtures/bindings/event/index.html +43 -0
  218. package/test/declarative/fixtures/bindings/event/main.ts +43 -0
  219. package/test/declarative/fixtures/bindings/event/state.json +3 -0
  220. package/test/declarative/fixtures/bindings/event/templates.html +18 -0
  221. package/test/declarative/fixtures/bindings/host/entry.html +40 -0
  222. package/test/declarative/fixtures/bindings/host/fast-build.config.json +6 -0
  223. package/test/declarative/fixtures/bindings/host/index.html +96 -0
  224. package/test/declarative/fixtures/bindings/host/main.ts +222 -0
  225. package/test/declarative/fixtures/bindings/host/state.json +9 -0
  226. package/test/declarative/fixtures/bindings/host/templates.html +55 -0
  227. package/test/declarative/fixtures/directives/README.md +12 -0
  228. package/test/declarative/fixtures/directives/children/entry.html +11 -0
  229. package/test/declarative/fixtures/directives/children/fast-build.config.json +6 -0
  230. package/test/declarative/fixtures/directives/children/index.html +15 -0
  231. package/test/declarative/fixtures/directives/children/main.ts +22 -0
  232. package/test/declarative/fixtures/directives/children/state.json +3 -0
  233. package/test/declarative/fixtures/directives/children/templates.html +3 -0
  234. package/test/declarative/fixtures/directives/ref/entry.html +11 -0
  235. package/test/declarative/fixtures/directives/ref/fast-build.config.json +6 -0
  236. package/test/declarative/fixtures/directives/ref/index.html +15 -0
  237. package/test/declarative/fixtures/directives/ref/main.ts +17 -0
  238. package/test/declarative/fixtures/directives/ref/state.json +1 -0
  239. package/test/declarative/fixtures/directives/ref/templates.html +3 -0
  240. package/test/declarative/fixtures/directives/repeat/entry.html +21 -0
  241. package/test/declarative/fixtures/directives/repeat/fast-build.config.json +6 -0
  242. package/test/declarative/fixtures/directives/repeat/index.html +133 -0
  243. package/test/declarative/fixtures/directives/repeat/main.ts +110 -0
  244. package/test/declarative/fixtures/directives/repeat/sprites.svg +8 -0
  245. package/test/declarative/fixtures/directives/repeat/state.json +10 -0
  246. package/test/declarative/fixtures/directives/repeat/templates.html +75 -0
  247. package/test/declarative/fixtures/directives/slotted/entry.html +17 -0
  248. package/test/declarative/fixtures/directives/slotted/fast-build.config.json +6 -0
  249. package/test/declarative/fixtures/directives/slotted/index.html +27 -0
  250. package/test/declarative/fixtures/directives/slotted/main.ts +29 -0
  251. package/test/declarative/fixtures/directives/slotted/state.json +1 -0
  252. package/test/declarative/fixtures/directives/slotted/templates.html +7 -0
  253. package/test/declarative/fixtures/directives/when/entry.html +51 -0
  254. package/test/declarative/fixtures/directives/when/fast-build.config.json +6 -0
  255. package/test/declarative/fixtures/directives/when/index.html +136 -0
  256. package/test/declarative/fixtures/directives/when/main.ts +172 -0
  257. package/test/declarative/fixtures/directives/when/state.json +12 -0
  258. package/test/declarative/fixtures/directives/when/templates.html +75 -0
  259. package/test/declarative/fixtures/ecosystem/README.md +11 -0
  260. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/entry.html +12 -0
  261. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/fast-build.config.json +6 -0
  262. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/index.html +20 -0
  263. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/main.ts +68 -0
  264. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/state.json +4 -0
  265. package/test/declarative/fixtures/ecosystem/declarative-no-hydration/templates.html +7 -0
  266. package/test/declarative/fixtures/ecosystem/errors/entry.html +12 -0
  267. package/test/declarative/fixtures/ecosystem/errors/fast-build.config.json +6 -0
  268. package/test/declarative/fixtures/ecosystem/errors/index.html +20 -0
  269. package/test/declarative/fixtures/ecosystem/errors/main.ts +17 -0
  270. package/test/declarative/fixtures/ecosystem/errors/state.json +1 -0
  271. package/test/declarative/fixtures/ecosystem/errors/templates.html +7 -0
  272. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/entry.html +17 -0
  273. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/fast-build.config.json +6 -0
  274. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/index.html +56 -0
  275. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/main.ts +134 -0
  276. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/state.json +12 -0
  277. package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/templates.html +34 -0
  278. package/test/declarative/fixtures/ecosystem/performance-metrics/entry.html +25 -0
  279. package/test/declarative/fixtures/ecosystem/performance-metrics/fast-build.config.json +6 -0
  280. package/test/declarative/fixtures/ecosystem/performance-metrics/fast-card.css +10 -0
  281. package/test/declarative/fixtures/ecosystem/performance-metrics/index.html +181 -0
  282. package/test/declarative/fixtures/ecosystem/performance-metrics/main.ts +58 -0
  283. package/test/declarative/fixtures/ecosystem/performance-metrics/state.json +6 -0
  284. package/test/declarative/fixtures/ecosystem/performance-metrics/templates.html +15 -0
  285. package/test/declarative/fixtures/extensions/README.md +15 -0
  286. package/test/declarative/fixtures/extensions/attribute-map/entry.html +14 -0
  287. package/test/declarative/fixtures/extensions/attribute-map/fast-build.config.json +6 -0
  288. package/test/declarative/fixtures/extensions/attribute-map/index.html +31 -0
  289. package/test/declarative/fixtures/extensions/attribute-map/main.ts +40 -0
  290. package/test/declarative/fixtures/extensions/attribute-map/state.json +4 -0
  291. package/test/declarative/fixtures/extensions/attribute-map/templates.html +14 -0
  292. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/entry.html +12 -0
  293. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/fast-build.config.json +7 -0
  294. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/index.html +25 -0
  295. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/main.ts +31 -0
  296. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/state.json +5 -0
  297. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/templates.html +11 -0
  298. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/entry.html +13 -0
  299. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/fast-build.config.json +7 -0
  300. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/index.html +23 -0
  301. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/main.ts +37 -0
  302. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/state.json +1 -0
  303. package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/templates.html +9 -0
  304. package/test/declarative/fixtures/extensions/observer-map/entry.html +15 -0
  305. package/test/declarative/fixtures/extensions/observer-map/fast-build.config.json +6 -0
  306. package/test/declarative/fixtures/extensions/observer-map/index.html +442 -0
  307. package/test/declarative/fixtures/extensions/observer-map/main.ts +482 -0
  308. package/test/declarative/fixtures/extensions/observer-map/state.json +158 -0
  309. package/test/declarative/fixtures/extensions/observer-map/templates.html +172 -0
  310. package/test/declarative/fixtures/extensions/observer-map-config-object/entry.html +16 -0
  311. package/test/declarative/fixtures/extensions/observer-map-config-object/fast-build.config.json +6 -0
  312. package/test/declarative/fixtures/extensions/observer-map-config-object/index.html +27 -0
  313. package/test/declarative/fixtures/extensions/observer-map-config-object/main.ts +53 -0
  314. package/test/declarative/fixtures/extensions/observer-map-config-object/state.json +9 -0
  315. package/test/declarative/fixtures/extensions/observer-map-config-object/templates.html +12 -0
  316. package/test/declarative/fixtures/extensions/observer-map-deep-merge/README.md +98 -0
  317. package/test/declarative/fixtures/extensions/observer-map-deep-merge/entry.html +156 -0
  318. package/test/declarative/fixtures/extensions/observer-map-deep-merge/fast-build.config.json +6 -0
  319. package/test/declarative/fixtures/extensions/observer-map-deep-merge/index.html +376 -0
  320. package/test/declarative/fixtures/extensions/observer-map-deep-merge/main.ts +366 -0
  321. package/test/declarative/fixtures/extensions/observer-map-deep-merge/state.json +69 -0
  322. package/test/declarative/fixtures/extensions/observer-map-deep-merge/templates.html +91 -0
  323. package/test/declarative/fixtures/extensions/observer-map-properties/entry.html +14 -0
  324. package/test/declarative/fixtures/extensions/observer-map-properties/fast-build.config.json +6 -0
  325. package/test/declarative/fixtures/extensions/observer-map-properties/index.html +110 -0
  326. package/test/declarative/fixtures/extensions/observer-map-properties/main.ts +175 -0
  327. package/test/declarative/fixtures/extensions/observer-map-properties/state.json +29 -0
  328. package/test/declarative/fixtures/extensions/observer-map-properties/templates.html +55 -0
  329. package/test/declarative/fixtures/scenarios/README.md +7 -0
  330. package/test/declarative/fixtures/scenarios/nested-elements/entry.html +16 -0
  331. package/test/declarative/fixtures/scenarios/nested-elements/fast-build.config.json +6 -0
  332. package/test/declarative/fixtures/scenarios/nested-elements/index.html +126 -0
  333. package/test/declarative/fixtures/scenarios/nested-elements/main.ts +214 -0
  334. package/test/declarative/fixtures/scenarios/nested-elements/state.json +10 -0
  335. package/test/declarative/fixtures/scenarios/nested-elements/templates.html +54 -0
  336. package/test/declarative/index.html +12 -0
  337. package/test/declarative/vite.config.ts +55 -0
  338. package/test/declarative-main.ts +6 -0
  339. package/test/extension-subpaths-main.ts +9 -0
  340. package/test/main.ts +38 -33
  341. package/test/pure-declarative-main.ts +1 -0
  342. package/dist/dts/components/install-hydration.d.ts +0 -1
  343. package/dist/dts/pending-task.d.ts +0 -32
  344. package/dist/dts/polyfills.d.ts +0 -0
  345. package/dist/dts/styles/css-binding-directive.d.ts +0 -60
  346. package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
  347. package/dist/esm/components/install-hydration.js +0 -3
  348. package/dist/esm/pending-task.js +0 -28
  349. package/dist/esm/polyfills.js +0 -60
  350. package/dist/esm/styles/css-binding-directive.js +0 -76
  351. package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
@@ -0,0 +1,834 @@
1
+ import { defsPropertyName, fastContextMetaData, } from "../components/schema.js";
2
+ import { attributeDirectivePrefix, clientSideCloseExpression, clientSideOpenExpression, closeExpression, eventArgAccessor, executionContextAccessor, openExpression, repeatDirectiveClose, repeatDirectiveOpen, unescapedCloseExpression, unescapedOpenExpression, whenDirectiveClose, whenDirectiveOpen, } from "./syntax.js";
3
+ export { assignObservables, assignProxy, deepEqual, deepMerge, findDef, isPlainObject, } from "./observer-map-utilities.js";
4
+ /**
5
+ * Prefix used for execution context paths.
6
+ * @public
7
+ */
8
+ export const contextPrefixDot = `${executionContextAccessor}.`;
9
+ export { eventArgAccessor, executionContextAccessor };
10
+ /**
11
+ * Parses the arguments string of an event handler binding into an array of
12
+ * typed argument descriptors. Unrecognised tokens are returned as `"binding"`
13
+ * type with their raw string preserved.
14
+ *
15
+ * Special arguments:
16
+ * - `$e` — resolves to the DOM event object
17
+ * - `$c` — resolves to the full execution context object
18
+ *
19
+ * Any other token is treated as a binding path and resolved against the current
20
+ * data source.
21
+ *
22
+ * @param argsString - The raw arguments string from between the parentheses,
23
+ * e.g. `""`, `"$e"`, `"$c"`, or `"$e, $c"`.
24
+ * @returns An array of {@link ParsedEventArg} descriptors.
25
+ * @public
26
+ */
27
+ export function parseEventArgs(argsString) {
28
+ if (argsString.trim() === "")
29
+ return [];
30
+ return argsString
31
+ .split(",")
32
+ .map(arg => arg.trim())
33
+ .filter(arg => arg !== "")
34
+ .map((arg) => {
35
+ switch (arg) {
36
+ case eventArgAccessor:
37
+ return { type: "event" };
38
+ case executionContextAccessor:
39
+ return { type: "context" };
40
+ default:
41
+ return { type: "binding", rawArg: arg };
42
+ }
43
+ });
44
+ }
45
+ const startInnerHTMLDiv = `<div :innerHTML="{{`;
46
+ const startInnerHTMLDivLength = startInnerHTMLDiv.length;
47
+ const endInnerHTMLDiv = `}}"></div>`;
48
+ const endInnerHTMLDivLength = endInnerHTMLDiv.length;
49
+ /**
50
+ * Logical operator tokens.
51
+ * @public
52
+ */
53
+ export const LogicalOperator = {
54
+ AND: "&&",
55
+ OR: "||",
56
+ };
57
+ /**
58
+ * Comparison operator tokens.
59
+ * @public
60
+ */
61
+ export const ComparisonOperator = {
62
+ ACCESS: "access",
63
+ EQUALS: "==",
64
+ GREATER_THAN: ">",
65
+ GREATER_THAN_OR_EQUALS: ">=",
66
+ LESS_THAN: "<",
67
+ LESS_THAN_OR_EQUALS: "<=",
68
+ NOT: "!",
69
+ NOT_EQUALS: "!=",
70
+ };
71
+ /**
72
+ * Declarative expression operator tokens.
73
+ * @public
74
+ */
75
+ export const Operator = Object.assign(Object.assign({}, LogicalOperator), ComparisonOperator);
76
+ /**
77
+ * Get the index of the next matching tag
78
+ * @param openingTagStartSlice - The slice starting from the opening tag
79
+ * @param openingTag - The opening tag string
80
+ * @param closingTag - The closing tag
81
+ * @param openingTagStartIndex - The opening tag start index derived from the innerHTML
82
+ * @returns index
83
+ * @public
84
+ */
85
+ export function getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex) {
86
+ let tagCount = 1;
87
+ let matchingCloseTagIndex = -1;
88
+ const openingTagLength = openingTag.length;
89
+ const closingTagLength = closingTag.length;
90
+ let nextSlice = openingTagStartSlice.slice(openingTagLength);
91
+ let nextOpenTag = nextSlice.indexOf(openingTag);
92
+ let nextCloseTag = nextSlice.indexOf(closingTag);
93
+ let tagOffset = openingTagStartIndex + openingTagLength;
94
+ do {
95
+ // if a closing tag has been found for the last open tag, decrement the tag count
96
+ if (nextOpenTag > nextCloseTag || nextOpenTag === -1) {
97
+ tagCount--;
98
+ if (tagCount === 0) {
99
+ matchingCloseTagIndex = nextCloseTag + tagOffset;
100
+ break;
101
+ }
102
+ tagOffset += nextCloseTag + closingTagLength;
103
+ nextSlice = nextSlice.slice(nextCloseTag + closingTagLength);
104
+ nextOpenTag = nextSlice.indexOf(openingTag);
105
+ nextCloseTag = nextSlice.indexOf(closingTag);
106
+ }
107
+ else if (nextOpenTag !== -1) {
108
+ tagCount++;
109
+ tagOffset += nextOpenTag + openingTagLength;
110
+ nextSlice = nextSlice.slice(nextOpenTag + openingTagLength);
111
+ nextOpenTag = nextSlice.indexOf(openingTag);
112
+ nextCloseTag = nextSlice.indexOf(closingTag);
113
+ }
114
+ if (tagCount === 0) {
115
+ matchingCloseTagIndex = nextCloseTag + tagOffset;
116
+ break;
117
+ }
118
+ } while (tagCount > 0);
119
+ return matchingCloseTagIndex;
120
+ }
121
+ /**
122
+ * Get the next directive
123
+ * @param innerHTML - The innerHTML string to evaluate
124
+ * @returns DirectiveBehaviorConfig - A configuration object
125
+ */
126
+ function getNextDirectiveBehavior(innerHTML) {
127
+ const whenIndex = innerHTML.indexOf(whenDirectiveOpen);
128
+ const repeatIndex = innerHTML.indexOf(repeatDirectiveOpen);
129
+ const isWhen = whenIndex !== -1 && (repeatIndex === -1 || whenIndex < repeatIndex);
130
+ let openingTag = repeatDirectiveOpen;
131
+ let closingTag = repeatDirectiveClose;
132
+ let directiveTag = "repeat";
133
+ let openingTagStartIndex = repeatIndex;
134
+ if (isWhen) {
135
+ openingTag = whenDirectiveOpen;
136
+ closingTag = whenDirectiveClose;
137
+ directiveTag = "when";
138
+ openingTagStartIndex = whenIndex;
139
+ }
140
+ const openingTagStartSlice = innerHTML.slice(openingTagStartIndex);
141
+ const openingTagEndIndex = // account for f-when which may include >= or > as operators, but will always include a condition attr
142
+ openingTagStartSlice.indexOf(`">`) + openingTagStartIndex + 2;
143
+ const directiveValue = getNextDataBindingBehavior(innerHTML);
144
+ const matchingCloseTagIndex = getIndexOfNextMatchingTag(openingTagStartSlice, openingTag, closingTag, openingTagStartIndex);
145
+ return {
146
+ type: "templateDirective",
147
+ name: directiveTag,
148
+ value: innerHTML.slice(directiveValue.openingEndIndex, directiveValue.closingStartIndex),
149
+ openingTagStartIndex,
150
+ openingTagEndIndex,
151
+ closingTagStartIndex: matchingCloseTagIndex,
152
+ closingTagEndIndex: matchingCloseTagIndex + closingTag.length,
153
+ };
154
+ }
155
+ /**
156
+ * Determine if this binding is an attribute binding
157
+ * @param innerHTML - The innerHTML string to evaluate
158
+ * @param openingStartIndex - The index of the binding opening marker
159
+ * @returns boolean
160
+ */
161
+ function isAttribute(innerHTML, openingStartIndex) {
162
+ return innerHTML.slice(openingStartIndex - 2, openingStartIndex - 1) === "=";
163
+ }
164
+ /**
165
+ * Determine if this binding is an attribute directive binding
166
+ * @param innerHTML - The innerHTML string to evaluate
167
+ * @param openingStartIndex - The index of the binding opening marker
168
+ * @returns boolean
169
+ */
170
+ function isAttributeDirective(innerHTML, openingStartIndex) {
171
+ const splitHTML = innerHTML.slice(0, openingStartIndex - 2).split(" ");
172
+ return splitHTML[splitHTML.length - 1].startsWith(attributeDirectivePrefix);
173
+ }
174
+ /**
175
+ * Get the attribute binding config
176
+ * @param innerHTML - The innerHTML string to evaluate
177
+ * @param config - The base configuration of the binding
178
+ * @returns AttributeDataBindingBehaviorConfig
179
+ */
180
+ function getAttributeDataBindingConfig(innerHTML, config) {
181
+ const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
182
+ const firstCharOfAttribute = splitInnerHTML[splitInnerHTML.length - 1][0];
183
+ const aspect = firstCharOfAttribute === "?" ||
184
+ firstCharOfAttribute === "@" ||
185
+ firstCharOfAttribute === ":"
186
+ ? firstCharOfAttribute
187
+ : null;
188
+ return Object.assign(Object.assign({}, config), { subtype: "attribute", aspect });
189
+ }
190
+ /**
191
+ * Get the attribute directive binding config
192
+ * @param innerHTML - The innerHTML string to evaluate
193
+ * @param config - The base configuration of the binding
194
+ * @returns AttributeDirectiveBindingBehaviorConfig
195
+ */
196
+ function getAttributeDirectiveDataBindingConfig(innerHTML, config) {
197
+ const splitInnerHTML = innerHTML.slice(0, config.openingStartIndex).split(" ");
198
+ const lastItem = splitInnerHTML[splitInnerHTML.length - 1];
199
+ const equals = lastItem.indexOf("=");
200
+ const name = lastItem.slice(2, equals);
201
+ return Object.assign(Object.assign({}, config), { subtype: "attributeDirective", name: name });
202
+ }
203
+ /**
204
+ * Get the content data binding config
205
+ * @param config - The base configuration of the binding
206
+ * @returns ContentDataBindingBehaviorConfig
207
+ */
208
+ function getContentDataBindingConfig(config) {
209
+ return Object.assign(Object.assign({}, config), { subtype: "content" });
210
+ }
211
+ /**
212
+ * Finds the next data binding in innerHTML and determines its type and indices
213
+ * @param innerHTML - The innerHTML string to search for data bindings
214
+ * @returns NextDataBindingBehaviorConfig containing the binding type and start indices
215
+ */
216
+ function getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML) {
217
+ // {{{}}} binding
218
+ const openingUnescapedStartIndex = innerHTML.indexOf(unescapedOpenExpression);
219
+ const closingUnescapedStartIndex = innerHTML.indexOf(unescapedCloseExpression);
220
+ // {{}} binding
221
+ const openingContentStartIndex = innerHTML.indexOf(openExpression);
222
+ const closingContentStartIndex = innerHTML.indexOf(closeExpression);
223
+ // {} binding
224
+ const openingClientStartIndex = innerHTML.indexOf(clientSideOpenExpression);
225
+ const closingClientStartIndex = innerHTML.indexOf(clientSideCloseExpression);
226
+ if (openingUnescapedStartIndex !== -1 &&
227
+ openingUnescapedStartIndex <= openingContentStartIndex &&
228
+ openingUnescapedStartIndex <= openingClientStartIndex) {
229
+ // is unescaped {{{}}}
230
+ return {
231
+ openingStartIndex: openingUnescapedStartIndex,
232
+ closingStartIndex: closingUnescapedStartIndex,
233
+ bindingType: "unescaped",
234
+ };
235
+ }
236
+ else if (openingContentStartIndex !== -1 &&
237
+ openingContentStartIndex <= openingClientStartIndex) {
238
+ // is default {{}}
239
+ return {
240
+ openingStartIndex: openingContentStartIndex,
241
+ closingStartIndex: closingContentStartIndex,
242
+ bindingType: "default",
243
+ };
244
+ }
245
+ // is client {}
246
+ return {
247
+ openingStartIndex: openingClientStartIndex,
248
+ closingStartIndex: closingClientStartIndex,
249
+ bindingType: "client",
250
+ };
251
+ }
252
+ /**
253
+ * Get the next data binding
254
+ * @param innerHTML - The innerHTML string to evaluate
255
+ * @returns DataBindingBehaviorConfig - A configuration object
256
+ */
257
+ function getNextDataBindingBehavior(innerHTML) {
258
+ const { openingStartIndex, closingStartIndex, bindingType } = getIndexAndBindingTypeOfNextDataBindingBehavior(innerHTML);
259
+ const bindingLength = bindingType === "client" ? 1 : bindingType === "default" ? 2 : 3;
260
+ const partialConfig = {
261
+ type: "dataBinding",
262
+ bindingType,
263
+ openingStartIndex,
264
+ openingEndIndex: openingStartIndex + bindingLength,
265
+ closingStartIndex,
266
+ closingEndIndex: closingStartIndex + bindingLength,
267
+ };
268
+ return isAttributeDirective(innerHTML, openingStartIndex)
269
+ ? getAttributeDirectiveDataBindingConfig(innerHTML, partialConfig)
270
+ : isAttribute(innerHTML, openingStartIndex)
271
+ ? getAttributeDataBindingConfig(innerHTML, partialConfig)
272
+ : getContentDataBindingConfig(partialConfig);
273
+ }
274
+ /**
275
+ * Get the next behavior
276
+ * @param innerHTML - The innerHTML string to evaluate
277
+ * @param offset - The current offset in the original string.
278
+ * @returns DataBindingBehaviorConfig | DirectiveBehaviorConfig | null - A configuration object or null
279
+ * @public
280
+ */
281
+ export function getNextBehavior(innerHTML, offset = 0) {
282
+ // eslint-disable-next-line no-constant-condition
283
+ while (true) {
284
+ const currentSlice = innerHTML.slice(offset);
285
+ // client side binding will capture all bindings starting with "{"
286
+ const dataBindingOpen = currentSlice.indexOf(clientSideOpenExpression);
287
+ const whenDirectiveIndex = currentSlice.indexOf(whenDirectiveOpen);
288
+ const repeatDirectiveIndex = currentSlice.indexOf(repeatDirectiveOpen);
289
+ const directiveBindingOpen = whenDirectiveIndex === -1
290
+ ? repeatDirectiveIndex
291
+ : repeatDirectiveIndex === -1
292
+ ? whenDirectiveIndex
293
+ : Math.min(whenDirectiveIndex, repeatDirectiveIndex);
294
+ const nextDataBindingBehavior = getNextDataBindingBehavior(currentSlice);
295
+ if (dataBindingOpen === -1 && directiveBindingOpen === -1) {
296
+ return null;
297
+ }
298
+ if (dataBindingOpen !== -1 &&
299
+ nextDataBindingBehavior.bindingType === "client" &&
300
+ !isLegitimateClientSideBinding(nextDataBindingBehavior)) {
301
+ offset = nextDataBindingBehavior.closingEndIndex + offset;
302
+ continue;
303
+ }
304
+ if (directiveBindingOpen !== -1 &&
305
+ (dataBindingOpen === -1 || dataBindingOpen > directiveBindingOpen)) {
306
+ return offsetDirective(getNextDirectiveBehavior(currentSlice), offset);
307
+ }
308
+ return offsetDataBinding(nextDataBindingBehavior, offset);
309
+ }
310
+ }
311
+ /**
312
+ * Apply an offset to a data binding
313
+ * @param config DataBindingBehaviorConfig
314
+ * @param offset number
315
+ * @returns DataBindingBehaviorConfig
316
+ */
317
+ function offsetDataBinding(config, offset) {
318
+ config.openingStartIndex = config.openingStartIndex + offset;
319
+ config.openingEndIndex = config.openingEndIndex + offset;
320
+ config.closingStartIndex = config.closingStartIndex + offset;
321
+ config.closingEndIndex = config.closingEndIndex + offset;
322
+ return config;
323
+ }
324
+ /**
325
+ * Apply an offset to a directive
326
+ * @param config TemplateDirectiveBehaviorConfig
327
+ * @param offset number
328
+ * @returns TemplateDirectiveBehaviorConfig
329
+ */
330
+ function offsetDirective(config, offset) {
331
+ config.openingTagStartIndex = config.openingTagStartIndex + offset;
332
+ config.openingTagEndIndex = config.openingTagEndIndex + offset;
333
+ config.closingTagStartIndex = config.closingTagStartIndex + offset;
334
+ config.closingTagEndIndex = config.closingTagEndIndex + offset;
335
+ return config;
336
+ }
337
+ /**
338
+ * Determine if this client side binding is legitimate.
339
+ * Single-brace (client) bindings are only valid for events, properties, and attribute directives.
340
+ * Checking for this prevents CSS/JS curly braces from being misinterpreted as bindings.
341
+ * @param result
342
+ * @returns
343
+ */
344
+ function isLegitimateClientSideBinding(result) {
345
+ return ((result.subtype === "attribute" &&
346
+ (result.aspect === "@" || result.aspect === ":")) ||
347
+ result.subtype === "attributeDirective");
348
+ }
349
+ /**
350
+ * Create a function to resolve a value from an object using a path with dot syntax.
351
+ * e.g. "foo.bar"
352
+ * @param path - The dot syntax path to an objects property.
353
+ * @param contextPath - The current repeat context path.
354
+ * @param level - The current repeat nesting level.
355
+ * @param rootSchema - The root schema for resolving context paths.
356
+ * @returns A function to access the value from a given path.
357
+ * @public
358
+ */
359
+ export function pathResolver(path, contextPath, level, rootSchema) {
360
+ var _a, _b;
361
+ let splitPath = path.split(".");
362
+ // Explicit context access via executionContextAccessor — resolve directly from ExecutionContext
363
+ if (splitPath[0] === executionContextAccessor) {
364
+ const contextAccessPath = splitPath.slice(1);
365
+ return (_accessibleObject, context) => {
366
+ return contextAccessPath.reduce((prev, item) => prev === null || prev === void 0 ? void 0 : prev[item], context);
367
+ };
368
+ }
369
+ let levelCount = level;
370
+ let self = splitPath[0] === contextPath;
371
+ const parentContexts = [];
372
+ if (level > 0 &&
373
+ ((_b = (_a = rootSchema === null || rootSchema === void 0 ? void 0 : rootSchema[defsPropertyName]) === null || _a === void 0 ? void 0 : _a[contextPath]) === null || _b === void 0 ? void 0 : _b[fastContextMetaData]) ===
374
+ splitPath[splitPath.length - 1]) {
375
+ self = true;
376
+ }
377
+ while (levelCount > 0 && !self) {
378
+ if (levelCount !== 1) {
379
+ parentContexts.push("parentContext");
380
+ }
381
+ else {
382
+ parentContexts.push("parent");
383
+ }
384
+ levelCount--;
385
+ }
386
+ splitPath = [...parentContexts, ...splitPath];
387
+ return pathWithContextResolver(splitPath, self);
388
+ }
389
+ /**
390
+ * Creates a resolver function that can access properties from an object using a split path array
391
+ * @param splitPath - The dot syntax path split into an array of property names
392
+ * @param self - Whether the first item in the path refers to the item itself
393
+ * @returns A function that resolves the value from the given path on an accessible object
394
+ */
395
+ function pathWithContextResolver(splitPath, self) {
396
+ const isInPreviousContext = splitPath[0] === "parent" || splitPath[0] === "parentContext";
397
+ if (self && !isInPreviousContext) {
398
+ if (splitPath.length > 1) {
399
+ splitPath = splitPath.slice(1);
400
+ }
401
+ else {
402
+ return (accessibleObject) => {
403
+ return accessibleObject;
404
+ };
405
+ }
406
+ }
407
+ if (isInPreviousContext) {
408
+ return (accessibleObject, context) => {
409
+ return splitPath.reduce((previousAccessors, pathItem) => {
410
+ return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
411
+ }, context);
412
+ };
413
+ }
414
+ return (accessibleObject) => {
415
+ return splitPath.reduce((previousAccessors, pathItem) => {
416
+ return previousAccessors === null || previousAccessors === void 0 ? void 0 : previousAccessors[pathItem];
417
+ }, accessibleObject);
418
+ };
419
+ }
420
+ /**
421
+ * Creates a binding resolver and records the binding path in the schema.
422
+ * @param previousString - The previous literal string before the binding.
423
+ * @param rootPropertyName - The current root property name.
424
+ * @param path - The binding path to resolve.
425
+ * @param parentContext - The parent repeat context.
426
+ * @param type - The schema path type.
427
+ * @param schema - The schema to record paths in.
428
+ * @param currentContext - The current repeat context.
429
+ * @param level - The current repeat nesting level.
430
+ * @returns A function that resolves the binding path.
431
+ * @public
432
+ */
433
+ export function bindingResolver(previousString, rootPropertyName, path, parentContext, type, schema, currentContext, level) {
434
+ // Explicit context access — resolve from ExecutionContext, skip schema tracking
435
+ if (path.startsWith(contextPrefixDot)) {
436
+ const segments = path.split(".").slice(1);
437
+ return (_x, context) => {
438
+ return segments.reduce((prev, item) => prev === null || prev === void 0 ? void 0 : prev[item], context);
439
+ };
440
+ }
441
+ rootPropertyName = getRootPropertyName(rootPropertyName, path, currentContext, type);
442
+ if (type !== "event" && rootPropertyName !== null) {
443
+ const childrenMap = getChildrenMap(previousString);
444
+ schema.addPath({
445
+ pathConfig: {
446
+ type,
447
+ currentContext,
448
+ parentContext,
449
+ path,
450
+ },
451
+ rootPropertyName,
452
+ childrenMap,
453
+ });
454
+ }
455
+ return pathResolver(path, currentContext, level, schema.getSchema(rootPropertyName));
456
+ }
457
+ /**
458
+ * Creates a resolver for a chained expression and records its paths in the schema.
459
+ * @param rootPropertyName - The current root property name.
460
+ * @param expression - The expression to resolve.
461
+ * @param parentContext - The parent repeat context.
462
+ * @param level - The current repeat nesting level.
463
+ * @param schema - The schema to record paths in.
464
+ * @returns A function that resolves the expression.
465
+ * @public
466
+ */
467
+ export function expressionResolver(rootPropertyName, expression, parentContext, level, schema) {
468
+ // Extract all paths from the expression and add them to the schema
469
+ if (rootPropertyName !== null) {
470
+ const paths = extractPathsFromChainedExpression(expression);
471
+ paths.forEach(path => {
472
+ if (path.startsWith(contextPrefixDot))
473
+ return;
474
+ schema.addPath({
475
+ pathConfig: {
476
+ type: "access",
477
+ currentContext: parentContext,
478
+ parentContext: null,
479
+ path,
480
+ },
481
+ rootPropertyName,
482
+ childrenMap: null,
483
+ });
484
+ });
485
+ }
486
+ return (x, c) => resolveChainedExpression(x, c, level, parentContext || null, expression, schema.getSchema(rootPropertyName));
487
+ }
488
+ /**
489
+ * Extracts all paths from a ChainedExpression, including nested expressions
490
+ * @param chainedExpression - The chained expression to extract paths from
491
+ * @returns A Set containing all unique paths found in the expression chain
492
+ * @public
493
+ */
494
+ export function extractPathsFromChainedExpression(chainedExpression) {
495
+ const paths = new Set();
496
+ function processExpression(expr) {
497
+ // Check left operand (only add if it's not a literal value)
498
+ if (typeof expr.left === "string" && !expr.leftIsValue) {
499
+ paths.add(expr.left);
500
+ }
501
+ // Check right operand (only add if it's not a literal value)
502
+ if (typeof expr.right === "string" && !expr.rightIsValue) {
503
+ paths.add(expr.right);
504
+ }
505
+ }
506
+ let current = chainedExpression;
507
+ while (current !== undefined) {
508
+ processExpression(current.expression);
509
+ current = current.next;
510
+ }
511
+ return paths;
512
+ }
513
+ /**
514
+ * Determine if the operand is a value (boolean, number, string) or an accessor.
515
+ * @param operand - The string to evaluate as either a literal value or property accessor
516
+ * @returns An object containing the parsed value and whether it represents a literal value
517
+ */
518
+ function isOperandValue(operand) {
519
+ try {
520
+ operand = operand.replace(/'/g, '"');
521
+ const value = JSON.parse(operand);
522
+ return {
523
+ value,
524
+ isValue: true,
525
+ };
526
+ }
527
+ catch (_a) {
528
+ return {
529
+ value: operand,
530
+ isValue: false,
531
+ };
532
+ }
533
+ }
534
+ /**
535
+ * Evaluates parts of an expression chain and chains them with the specified operator
536
+ * @param parts - Each part of an expression chain to be evaluated
537
+ * @param operator - The logical operator used to chain the expression parts
538
+ * @returns A ChainedExpression object representing the linked expressions, or void if no valid expressions found
539
+ */
540
+ function evaluatePartsInExpressionChain(parts, operator) {
541
+ // Process each part recursively and chain them with ||
542
+ const firstPart = getExpressionChain(parts[0]);
543
+ if (firstPart) {
544
+ let current = firstPart;
545
+ for (let i = 1; i < parts.length; i++) {
546
+ const nextPart = getExpressionChain(parts[i]);
547
+ if (nextPart) {
548
+ // Find the end of the current chain
549
+ while (current.next) {
550
+ current = current.next;
551
+ }
552
+ current.next = Object.assign({ operator }, nextPart);
553
+ }
554
+ }
555
+ return firstPart;
556
+ }
557
+ }
558
+ /**
559
+ * Gets the expression chain as a configuration object
560
+ * @param value - The binding string value
561
+ * @returns - A configuration object containing information about the expression
562
+ * @public
563
+ */
564
+ export function getExpressionChain(value) {
565
+ // Decode HTML entities in the expression value first
566
+ const decodedValue = decodeExpressionOperators(value);
567
+ // Handle operator precedence: || has lower precedence than &&
568
+ // First, split by || (lowest precedence)
569
+ const orParts = decodedValue.split(/\s*\|\|\s*/);
570
+ if (orParts.length > 1) {
571
+ const firstPart = evaluatePartsInExpressionChain(orParts, Operator.OR);
572
+ if (firstPart) {
573
+ return firstPart;
574
+ }
575
+ }
576
+ // If no ||, check for && (higher precedence)
577
+ const andParts = decodedValue.split(/\s*&&\s*/);
578
+ if (andParts.length > 1) {
579
+ // Process each part recursively and chain them with &&
580
+ const firstPart = evaluatePartsInExpressionChain(andParts, "&&");
581
+ if (firstPart) {
582
+ return firstPart;
583
+ }
584
+ }
585
+ // No chaining operators found, create a single expression
586
+ if (decodedValue.trim()) {
587
+ return {
588
+ expression: getExpression(decodedValue.trim()),
589
+ };
590
+ }
591
+ return void 0;
592
+ }
593
+ /**
594
+ * Parses a binding value string into an Expression object
595
+ * @param value - The binding string value to parse (e.g., "!condition", "foo == bar", "property")
596
+ * @returns An Expression object containing the operator, operands, and whether operands are literal values
597
+ */
598
+ function getExpression(value) {
599
+ if (value[0] === Operator.NOT) {
600
+ const left = value.slice(1);
601
+ const operandValue = isOperandValue(left);
602
+ return {
603
+ operator: Operator.NOT,
604
+ left,
605
+ leftIsValue: operandValue.isValue,
606
+ right: null,
607
+ rightIsValue: null,
608
+ };
609
+ }
610
+ const split = value.split(/\s*([=!]=|[><]=?)\s*/);
611
+ if (split.length === 3) {
612
+ const operator = split[1];
613
+ const right = split[2];
614
+ const rightOperandValue = isOperandValue(right);
615
+ const left = split[0];
616
+ const leftOperandValue = isOperandValue(left);
617
+ return {
618
+ operator,
619
+ left: split[0],
620
+ leftIsValue: leftOperandValue.isValue,
621
+ right: rightOperandValue.isValue ? rightOperandValue.value : right,
622
+ rightIsValue: rightOperandValue.isValue,
623
+ };
624
+ }
625
+ return {
626
+ operator: Operator.ACCESS,
627
+ left: value,
628
+ leftIsValue: false,
629
+ right: null,
630
+ rightIsValue: null,
631
+ };
632
+ }
633
+ /**
634
+ * Decodes HTML entities within expression strings only (for operators like &&, <, >)
635
+ * This is safer than decoding the entire template as it preserves HTML-encoded content
636
+ * and only decodes operators needed for expression evaluation
637
+ * @param expression - The expression string to decode
638
+ * @returns The expression with operators decoded
639
+ */
640
+ function decodeExpressionOperators(expression) {
641
+ return expression
642
+ .replace(/&amp;&amp;/g, Operator.AND)
643
+ .replace(/&lt;/g, Operator.LESS_THAN)
644
+ .replace(/&gt;/g, Operator.GREATER_THAN);
645
+ }
646
+ /**
647
+ * Resolve a single expression by evaluating its operator and operands
648
+ * @param x - The current data context
649
+ * @param c - The parent context for accessing parent scope data
650
+ * @param level - The nesting level for context resolution
651
+ * @param contextPath - The current context path for property resolution
652
+ * @param expression - The expression object to evaluate
653
+ * @param rootSchema - The root JSON schema for data validation and navigation
654
+ * @returns The resolved value of the expression
655
+ */
656
+ function resolveExpression(x, c, level, contextPath, expression, rootSchema) {
657
+ const { operator, left, right, rightIsValue } = expression;
658
+ const resolvedLeft = pathResolver(left, contextPath, level, rootSchema)(x, c);
659
+ let resolvedRight = right;
660
+ if (!rightIsValue && typeof right === "string") {
661
+ resolvedRight = pathResolver(right, contextPath, level, rootSchema)(x, c);
662
+ }
663
+ switch (operator) {
664
+ case Operator.NOT: {
665
+ return !resolvedLeft;
666
+ }
667
+ case Operator.EQUALS: {
668
+ // biome-ignore lint/suspicious/noDoubleEquals: Breaks prior existing functionality - see when fixture
669
+ return resolvedLeft == resolvedRight;
670
+ }
671
+ case Operator.NOT_EQUALS: {
672
+ // biome-ignore lint/suspicious/noDoubleEquals: Breaks prior existing functionality - see when fixture
673
+ return resolvedLeft != resolvedRight;
674
+ }
675
+ case Operator.GREATER_THAN_OR_EQUALS: {
676
+ return resolvedLeft >= resolvedRight;
677
+ }
678
+ case Operator.GREATER_THAN: {
679
+ return resolvedLeft > resolvedRight;
680
+ }
681
+ case Operator.LESS_THAN_OR_EQUALS: {
682
+ return resolvedLeft <= resolvedRight;
683
+ }
684
+ case Operator.LESS_THAN: {
685
+ return resolvedLeft < resolvedRight;
686
+ }
687
+ default: {
688
+ if (typeof resolvedLeft === "boolean") {
689
+ return resolvedLeft;
690
+ }
691
+ if (typeof resolvedLeft === "number") {
692
+ return resolvedLeft !== 0;
693
+ }
694
+ if (typeof resolvedLeft === "string") {
695
+ return resolvedLeft.length > 0;
696
+ }
697
+ return !!resolvedLeft;
698
+ }
699
+ }
700
+ }
701
+ /**
702
+ * Resolve a chained expression by evaluating expressions linked with logical operators
703
+ * @param x - The current data context
704
+ * @param c - The parent context for accessing parent scope data
705
+ * @param level - The nesting level for context resolution
706
+ * @param contextPath - The current context path for property resolution
707
+ * @param expression - The chained expression object containing linked expressions
708
+ * @param rootSchema - The root JSON schema for data validation and navigation
709
+ * @returns The resolved boolean result of the chained expression
710
+ */
711
+ function resolveChainedExpression(x, c, level, contextPath, expression, rootSchema) {
712
+ const { expression: expr, next } = expression;
713
+ const resolvedLeft = resolveExpression(x, c, level, contextPath, expr, rootSchema);
714
+ if (next) {
715
+ const resolvedRight = resolveChainedExpression(x, c, level, contextPath, next, rootSchema);
716
+ switch (next.operator) {
717
+ case Operator.AND: {
718
+ return resolvedLeft && resolvedRight;
719
+ }
720
+ case Operator.OR: {
721
+ return resolvedLeft || resolvedRight;
722
+ }
723
+ }
724
+ }
725
+ return resolvedLeft;
726
+ }
727
+ /**
728
+ * This is the transform utility for rationalizing declarative HTML syntax
729
+ * with bindings in the ViewTemplate
730
+ * @param innerHTML - The innerHTML to transform.
731
+ * @param index - The index to start the current slice of HTML to evaluate.
732
+ * @public
733
+ */
734
+ export function transformInnerHTML(innerHTML, index = 0) {
735
+ const sliceToEvaluate = innerHTML.slice(index);
736
+ const nextBinding = getNextBehavior(sliceToEvaluate);
737
+ let transformedInnerHTML = innerHTML;
738
+ if (nextBinding && nextBinding.type === "dataBinding") {
739
+ if (nextBinding.bindingType === "unescaped") {
740
+ transformedInnerHTML = `${innerHTML.slice(0, index)}${sliceToEvaluate.slice(0, nextBinding.openingStartIndex)}${startInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.openingStartIndex + 3, nextBinding.closingStartIndex)}${endInnerHTMLDiv}${sliceToEvaluate.slice(nextBinding.closingStartIndex + 3)}`;
741
+ return transformInnerHTML(transformedInnerHTML, index +
742
+ startInnerHTMLDivLength +
743
+ endInnerHTMLDivLength +
744
+ nextBinding.closingStartIndex -
745
+ 3);
746
+ }
747
+ else if (nextBinding.bindingType === "client") {
748
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
749
+ }
750
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingEndIndex);
751
+ }
752
+ else if (nextBinding) {
753
+ return transformInnerHTML(transformedInnerHTML, index + nextBinding.closingTagEndIndex);
754
+ }
755
+ return transformedInnerHTML;
756
+ }
757
+ /**
758
+ * Resolves boolean logic
759
+ * used for f-when and boolean attributes
760
+ * @param rootPropertyName - The current root property name.
761
+ * @param expression - The chained expression to resolve.
762
+ * @param parentContext - The parent repeat context.
763
+ * @param level - The current repeat nesting level.
764
+ * @param schema - The schema to record paths in.
765
+ * @returns - A binding that resolves the chained expression logic
766
+ * @public
767
+ */
768
+ export function getBooleanBinding(rootPropertyName, expression, parentContext, level, schema) {
769
+ const binding = expressionResolver(rootPropertyName, expression, parentContext, level, schema);
770
+ return (x, c) => binding(x, c);
771
+ }
772
+ /**
773
+ * Get the root property name
774
+ * @param rootPropertyName - The root property
775
+ * @param path - The dot syntax path
776
+ * @param context - The context created by a repeat
777
+ * @param type - The type of path binding
778
+ * @returns
779
+ * @public
780
+ */
781
+ export function getRootPropertyName(rootPropertyName, path, context, type) {
782
+ return (rootPropertyName === null || context === null) && type !== "event"
783
+ ? path.split(".")[0]
784
+ : rootPropertyName;
785
+ }
786
+ /**
787
+ * Get details of bindings to the attributes of child custom elements
788
+ * @param previousString - The previous string before the binding
789
+ * @returns null, or a custom element name and attribute name
790
+ * @public
791
+ */
792
+ export function getChildrenMap(previousString) {
793
+ if (typeof previousString === "string" &&
794
+ isAttribute(previousString, previousString.length)) {
795
+ const customElementName = getAttributesCustomElementName(previousString);
796
+ if (customElementName) {
797
+ return {
798
+ customElementName,
799
+ attributeName: getAttributeName(previousString),
800
+ };
801
+ }
802
+ }
803
+ return null;
804
+ }
805
+ /**
806
+ * Get the HTML element that is passing the attribute binding
807
+ * @param previousString - The previous string before the binding
808
+ * @returns null if this is not a custom element, or the custom element that is passing the binding as an attribute
809
+ */
810
+ function getAttributesCustomElementName(previousString) {
811
+ const indexOfElementTagStart = previousString.lastIndexOf("<") + 1;
812
+ const indexOfElementTagEnd = previousString.slice(indexOfElementTagStart).indexOf(" ") +
813
+ indexOfElementTagStart;
814
+ const elementName = previousString.slice(indexOfElementTagStart, indexOfElementTagEnd);
815
+ if (elementName.includes("-")) {
816
+ return elementName;
817
+ }
818
+ return null;
819
+ }
820
+ /**
821
+ * Gets a non-aspected attribute name
822
+ * @param previousString - The previous string before the binding
823
+ * @returns The attribute name with any aspects (:, ?, @) removed
824
+ */
825
+ function getAttributeName(previousString) {
826
+ const indexOfAttributeStart = previousString.lastIndexOf(" ") + 1;
827
+ const indexOfAttributeEnd = previousString.slice(indexOfAttributeStart).indexOf("=") + indexOfAttributeStart;
828
+ const attributeName = previousString.slice(indexOfAttributeStart, indexOfAttributeEnd);
829
+ const potentialAspect = attributeName.charAt(0);
830
+ if (potentialAspect === ":" || potentialAspect === "@" || potentialAspect === "?") {
831
+ return attributeName.slice(1);
832
+ }
833
+ return attributeName;
834
+ }