@velarscript/web 0.31.0 → 0.33.0

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 (393) hide show
  1. package/README.md +1 -1
  2. package/dist/analysis/calls/intrinsics/config.d.ts +10 -0
  3. package/dist/analysis/calls/intrinsics/config.d.ts.map +1 -0
  4. package/dist/analysis/calls/intrinsics/config.js +19 -0
  5. package/dist/analysis/calls/intrinsics/config.js.map +1 -0
  6. package/dist/analysis/calls/intrinsics/forms.d.ts +10 -0
  7. package/dist/analysis/calls/intrinsics/forms.d.ts.map +1 -0
  8. package/dist/analysis/calls/intrinsics/forms.js +38 -0
  9. package/dist/analysis/calls/intrinsics/forms.js.map +1 -0
  10. package/dist/analysis/calls/intrinsics/http.d.ts +10 -0
  11. package/dist/analysis/calls/intrinsics/http.d.ts.map +1 -0
  12. package/dist/analysis/calls/intrinsics/http.js +37 -0
  13. package/dist/analysis/calls/intrinsics/http.js.map +1 -0
  14. package/dist/analysis/calls/intrinsics/reactive.d.ts +10 -0
  15. package/dist/analysis/calls/intrinsics/reactive.d.ts.map +1 -0
  16. package/dist/analysis/calls/intrinsics/reactive.js +30 -0
  17. package/dist/analysis/calls/intrinsics/reactive.js.map +1 -0
  18. package/dist/analysis/calls/intrinsics/storage.d.ts +16 -0
  19. package/dist/analysis/calls/intrinsics/storage.d.ts.map +1 -0
  20. package/dist/analysis/calls/intrinsics/storage.js +91 -0
  21. package/dist/analysis/calls/intrinsics/storage.js.map +1 -0
  22. package/dist/analysis/calls/intrinsics/web.d.ts +10 -0
  23. package/dist/analysis/calls/intrinsics/web.d.ts.map +1 -0
  24. package/dist/analysis/calls/intrinsics/web.js +100 -0
  25. package/dist/analysis/calls/intrinsics/web.js.map +1 -0
  26. package/dist/analysis/calls/intrinsics.d.ts +13 -0
  27. package/dist/analysis/calls/intrinsics.d.ts.map +1 -0
  28. package/dist/analysis/calls/intrinsics.js +31 -0
  29. package/dist/analysis/calls/intrinsics.js.map +1 -0
  30. package/dist/analysis/components/contracts.d.ts +19 -0
  31. package/dist/analysis/components/contracts.d.ts.map +1 -0
  32. package/dist/analysis/components/contracts.js +83 -0
  33. package/dist/analysis/components/contracts.js.map +1 -0
  34. package/dist/analysis/components/declaration.d.ts +4 -0
  35. package/dist/analysis/components/declaration.d.ts.map +1 -0
  36. package/dist/analysis/components/declaration.js +163 -0
  37. package/dist/analysis/components/declaration.js.map +1 -0
  38. package/dist/analysis/components/host.d.ts +61 -0
  39. package/dist/analysis/components/host.d.ts.map +1 -0
  40. package/dist/analysis/components/host.js +22 -0
  41. package/dist/analysis/components/host.js.map +1 -0
  42. package/dist/analysis/components/lifecycle.d.ts +22 -0
  43. package/dist/analysis/components/lifecycle.d.ts.map +1 -0
  44. package/dist/analysis/components/lifecycle.js +33 -0
  45. package/dist/analysis/components/lifecycle.js.map +1 -0
  46. package/dist/analysis/components/ownership.d.ts +74 -0
  47. package/dist/analysis/components/ownership.d.ts.map +1 -0
  48. package/dist/analysis/components/ownership.js +106 -0
  49. package/dist/analysis/components/ownership.js.map +1 -0
  50. package/dist/analysis/declarations.d.ts +99 -0
  51. package/dist/analysis/declarations.d.ts.map +1 -0
  52. package/dist/analysis/declarations.js +176 -0
  53. package/dist/analysis/declarations.js.map +1 -0
  54. package/dist/analysis/inference.d.ts +75 -0
  55. package/dist/analysis/inference.d.ts.map +1 -0
  56. package/dist/analysis/inference.js +257 -0
  57. package/dist/analysis/inference.js.map +1 -0
  58. package/dist/analysis/jsx/attributes.d.ts +103 -0
  59. package/dist/analysis/jsx/attributes.d.ts.map +1 -0
  60. package/dist/analysis/jsx/attributes.js +601 -0
  61. package/dist/analysis/jsx/attributes.js.map +1 -0
  62. package/dist/analysis/jsx/elements.d.ts +17 -0
  63. package/dist/analysis/jsx/elements.d.ts.map +1 -0
  64. package/dist/analysis/jsx/elements.js +213 -0
  65. package/dist/analysis/jsx/elements.js.map +1 -0
  66. package/dist/analysis/jsx/host.d.ts +61 -0
  67. package/dist/analysis/jsx/host.d.ts.map +1 -0
  68. package/dist/analysis/jsx/host.js +15 -0
  69. package/dist/analysis/jsx/host.js.map +1 -0
  70. package/dist/analysis/jsx/keys.d.ts +15 -0
  71. package/dist/analysis/jsx/keys.d.ts.map +1 -0
  72. package/dist/analysis/jsx/keys.js +67 -0
  73. package/dist/analysis/jsx/keys.js.map +1 -0
  74. package/dist/analysis/jsx/security.d.ts +29 -0
  75. package/dist/analysis/jsx/security.d.ts.map +1 -0
  76. package/dist/analysis/jsx/security.js +61 -0
  77. package/dist/analysis/jsx/security.js.map +1 -0
  78. package/dist/analysis/jsx-detection.d.ts +49 -0
  79. package/dist/analysis/jsx-detection.d.ts.map +1 -0
  80. package/dist/analysis/jsx-detection.js +196 -0
  81. package/dist/analysis/jsx-detection.js.map +1 -0
  82. package/dist/analysis/keyed-rebuild.d.ts +148 -0
  83. package/dist/analysis/keyed-rebuild.d.ts.map +1 -0
  84. package/dist/analysis/keyed-rebuild.js +299 -0
  85. package/dist/analysis/keyed-rebuild.js.map +1 -0
  86. package/dist/analysis/keyframes-analysis.d.ts +6 -0
  87. package/dist/analysis/keyframes-analysis.d.ts.map +1 -0
  88. package/dist/analysis/keyframes-analysis.js +79 -0
  89. package/dist/analysis/keyframes-analysis.js.map +1 -0
  90. package/dist/analysis/look/builders.d.ts +29 -0
  91. package/dist/analysis/look/builders.d.ts.map +1 -0
  92. package/dist/analysis/look/builders.js +174 -0
  93. package/dist/analysis/look/builders.js.map +1 -0
  94. package/dist/analysis/look/conditions.d.ts +13 -0
  95. package/dist/analysis/look/conditions.d.ts.map +1 -0
  96. package/dist/analysis/look/conditions.js +84 -0
  97. package/dist/analysis/look/conditions.js.map +1 -0
  98. package/dist/analysis/look/edits.d.ts +36 -0
  99. package/dist/analysis/look/edits.d.ts.map +1 -0
  100. package/dist/analysis/look/edits.js +80 -0
  101. package/dist/analysis/look/edits.js.map +1 -0
  102. package/dist/analysis/look/entries.d.ts +56 -0
  103. package/dist/analysis/look/entries.d.ts.map +1 -0
  104. package/dist/analysis/look/entries.js +223 -0
  105. package/dist/analysis/look/entries.js.map +1 -0
  106. package/dist/analysis/look/host.d.ts +47 -0
  107. package/dist/analysis/look/host.d.ts.map +1 -0
  108. package/dist/analysis/look/host.js +16 -0
  109. package/dist/analysis/look/host.js.map +1 -0
  110. package/dist/analysis/look/tokens.d.ts +75 -0
  111. package/dist/analysis/look/tokens.d.ts.map +1 -0
  112. package/dist/analysis/look/tokens.js +156 -0
  113. package/dist/analysis/look/tokens.js.map +1 -0
  114. package/dist/analysis/look/values.d.ts +45 -0
  115. package/dist/analysis/look/values.d.ts.map +1 -0
  116. package/dist/analysis/look/values.js +148 -0
  117. package/dist/analysis/look/values.js.map +1 -0
  118. package/dist/analysis/look-conditions.d.ts +47 -0
  119. package/dist/analysis/look-conditions.d.ts.map +1 -0
  120. package/dist/analysis/look-conditions.js +157 -0
  121. package/dist/analysis/look-conditions.js.map +1 -0
  122. package/dist/analysis/look-sites.d.ts +62 -0
  123. package/dist/analysis/look-sites.d.ts.map +1 -0
  124. package/dist/analysis/look-sites.js +121 -0
  125. package/dist/analysis/look-sites.js.map +1 -0
  126. package/dist/analysis/look-values.d.ts +19 -0
  127. package/dist/analysis/look-values.d.ts.map +1 -1
  128. package/dist/analysis/look-values.js +38 -0
  129. package/dist/analysis/look-values.js.map +1 -1
  130. package/dist/analysis/look-vocabulary-guidance.d.ts +76 -0
  131. package/dist/analysis/look-vocabulary-guidance.d.ts.map +1 -0
  132. package/dist/analysis/look-vocabulary-guidance.js +338 -0
  133. package/dist/analysis/look-vocabulary-guidance.js.map +1 -0
  134. package/dist/analysis/media-conditions.d.ts +33 -0
  135. package/dist/analysis/media-conditions.d.ts.map +1 -0
  136. package/dist/analysis/media-conditions.js +92 -0
  137. package/dist/analysis/media-conditions.js.map +1 -0
  138. package/dist/analysis/program-passes.d.ts +106 -0
  139. package/dist/analysis/program-passes.d.ts.map +1 -0
  140. package/dist/analysis/program-passes.js +149 -0
  141. package/dist/analysis/program-passes.js.map +1 -0
  142. package/dist/analysis/reactivity/bindings.d.ts +37 -0
  143. package/dist/analysis/reactivity/bindings.d.ts.map +1 -0
  144. package/dist/analysis/reactivity/bindings.js +88 -0
  145. package/dist/analysis/reactivity/bindings.js.map +1 -0
  146. package/dist/analysis/reactivity/derived.d.ts +39 -0
  147. package/dist/analysis/reactivity/derived.d.ts.map +1 -0
  148. package/dist/analysis/reactivity/derived.js +80 -0
  149. package/dist/analysis/reactivity/derived.js.map +1 -0
  150. package/dist/analysis/reactivity/host.d.ts +38 -0
  151. package/dist/analysis/reactivity/host.d.ts.map +1 -0
  152. package/dist/analysis/reactivity/host.js +14 -0
  153. package/dist/analysis/reactivity/host.js.map +1 -0
  154. package/dist/analysis/reactivity/retired-accessors.d.ts +82 -0
  155. package/dist/analysis/reactivity/retired-accessors.d.ts.map +1 -0
  156. package/dist/analysis/reactivity/retired-accessors.js +118 -0
  157. package/dist/analysis/reactivity/retired-accessors.js.map +1 -0
  158. package/dist/analysis/renderable.d.ts +47 -0
  159. package/dist/analysis/renderable.d.ts.map +1 -0
  160. package/dist/analysis/renderable.js +105 -0
  161. package/dist/analysis/renderable.js.map +1 -0
  162. package/dist/analysis/routes.d.ts +64 -0
  163. package/dist/analysis/routes.d.ts.map +1 -0
  164. package/dist/analysis/routes.js +182 -0
  165. package/dist/analysis/routes.js.map +1 -0
  166. package/dist/analysis/url-attributes.d.ts +12 -0
  167. package/dist/analysis/url-attributes.d.ts.map +1 -0
  168. package/dist/analysis/url-attributes.js +48 -0
  169. package/dist/analysis/url-attributes.js.map +1 -0
  170. package/dist/analysis/watch-cycles.d.ts +102 -0
  171. package/dist/analysis/watch-cycles.d.ts.map +1 -1
  172. package/dist/analysis/watch-cycles.js +240 -1
  173. package/dist/analysis/watch-cycles.js.map +1 -1
  174. package/dist/analysis/watch-subject.d.ts +45 -0
  175. package/dist/analysis/watch-subject.d.ts.map +1 -0
  176. package/dist/analysis/watch-subject.js +272 -0
  177. package/dist/analysis/watch-subject.js.map +1 -0
  178. package/dist/analysis/web-types.d.ts +27 -0
  179. package/dist/analysis/web-types.d.ts.map +1 -0
  180. package/dist/analysis/web-types.js +170 -0
  181. package/dist/analysis/web-types.js.map +1 -0
  182. package/dist/analyzer.d.ts +18 -617
  183. package/dist/analyzer.d.ts.map +1 -1
  184. package/dist/analyzer.js +211 -4853
  185. package/dist/analyzer.js.map +1 -1
  186. package/dist/compiler.d.ts +20 -0
  187. package/dist/compiler.d.ts.map +1 -1
  188. package/dist/compiler.js +31 -864
  189. package/dist/compiler.js.map +1 -1
  190. package/dist/documentation.d.ts +28 -0
  191. package/dist/documentation.d.ts.map +1 -0
  192. package/dist/documentation.js +67 -0
  193. package/dist/documentation.js.map +1 -0
  194. package/dist/editor/completions.d.ts +12 -0
  195. package/dist/editor/completions.d.ts.map +1 -0
  196. package/dist/editor/completions.js +6 -0
  197. package/dist/editor/completions.js.map +1 -0
  198. package/dist/editor/jsx-completion.d.ts +12 -0
  199. package/dist/editor/jsx-completion.d.ts.map +1 -0
  200. package/dist/editor/jsx-completion.js +137 -0
  201. package/dist/editor/jsx-completion.js.map +1 -0
  202. package/dist/editor/look-completion.d.ts +29 -0
  203. package/dist/editor/look-completion.d.ts.map +1 -0
  204. package/dist/editor/look-completion.js +159 -0
  205. package/dist/editor/look-completion.js.map +1 -0
  206. package/dist/editor.d.ts.map +1 -1
  207. package/dist/editor.js +12 -288
  208. package/dist/editor.js.map +1 -1
  209. package/dist/emit/components.d.ts +33 -0
  210. package/dist/emit/components.d.ts.map +1 -0
  211. package/dist/emit/components.js +135 -0
  212. package/dist/emit/components.js.map +1 -0
  213. package/dist/emit/jsx.d.ts +57 -0
  214. package/dist/emit/jsx.d.ts.map +1 -0
  215. package/dist/emit/jsx.js +384 -0
  216. package/dist/emit/jsx.js.map +1 -0
  217. package/dist/emit/look-css.d.ts +44 -0
  218. package/dist/emit/look-css.d.ts.map +1 -0
  219. package/dist/emit/look-css.js +177 -0
  220. package/dist/emit/look-css.js.map +1 -0
  221. package/dist/emit/look.d.ts +39 -0
  222. package/dist/emit/look.d.ts.map +1 -0
  223. package/dist/emit/look.js +218 -0
  224. package/dist/emit/look.js.map +1 -0
  225. package/dist/emit/runtime-imports.d.ts +40 -0
  226. package/dist/emit/runtime-imports.d.ts.map +1 -0
  227. package/dist/emit/runtime-imports.js +188 -0
  228. package/dist/emit/runtime-imports.js.map +1 -0
  229. package/dist/emitter.d.ts +15 -68
  230. package/dist/emitter.d.ts.map +1 -1
  231. package/dist/emitter.js +79 -1008
  232. package/dist/emitter.js.map +1 -1
  233. package/dist/look/animation.d.ts +7 -0
  234. package/dist/look/animation.d.ts.map +1 -0
  235. package/dist/look/animation.js +13 -0
  236. package/dist/look/animation.js.map +1 -0
  237. package/dist/look/builders.d.ts +35 -0
  238. package/dist/look/builders.d.ts.map +1 -0
  239. package/dist/look/builders.js +74 -0
  240. package/dist/look/builders.js.map +1 -0
  241. package/dist/look/css-functions.d.ts +28 -0
  242. package/dist/look/css-functions.d.ts.map +1 -0
  243. package/dist/look/css-functions.js +54 -0
  244. package/dist/look/css-functions.js.map +1 -0
  245. package/dist/look/keyword-sets.d.ts +41 -0
  246. package/dist/look/keyword-sets.d.ts.map +1 -0
  247. package/dist/look/keyword-sets.js +117 -0
  248. package/dist/look/keyword-sets.js.map +1 -0
  249. package/dist/look/keywords.d.ts +55 -0
  250. package/dist/look/keywords.d.ts.map +1 -0
  251. package/dist/look/keywords.js +387 -0
  252. package/dist/look/keywords.js.map +1 -0
  253. package/dist/look/media.d.ts +19 -0
  254. package/dist/look/media.d.ts.map +1 -0
  255. package/dist/look/media.js +27 -0
  256. package/dist/look/media.js.map +1 -0
  257. package/dist/look/naming.d.ts +9 -0
  258. package/dist/look/naming.d.ts.map +1 -0
  259. package/dist/look/naming.js +45 -0
  260. package/dist/look/naming.js.map +1 -0
  261. package/dist/look/properties.d.ts +16 -0
  262. package/dist/look/properties.d.ts.map +1 -0
  263. package/dist/look/properties.js +52 -0
  264. package/dist/look/properties.js.map +1 -0
  265. package/dist/look/shorthands.d.ts +25 -0
  266. package/dist/look/shorthands.d.ts.map +1 -0
  267. package/dist/look/shorthands.js +130 -0
  268. package/dist/look/shorthands.js.map +1 -0
  269. package/dist/look/tokens.d.ts +38 -0
  270. package/dist/look/tokens.d.ts.map +1 -0
  271. package/dist/look/tokens.js +59 -0
  272. package/dist/look/tokens.js.map +1 -0
  273. package/dist/look/units.d.ts +24 -0
  274. package/dist/look/units.d.ts.map +1 -0
  275. package/dist/look/units.js +33 -0
  276. package/dist/look/units.js.map +1 -0
  277. package/dist/look.d.ts +32 -227
  278. package/dist/look.d.ts.map +1 -1
  279. package/dist/look.js +28 -933
  280. package/dist/look.js.map +1 -1
  281. package/dist/module-roster.d.ts +16 -0
  282. package/dist/module-roster.d.ts.map +1 -0
  283. package/dist/module-roster.js +28 -0
  284. package/dist/module-roster.js.map +1 -0
  285. package/dist/modules/app.d.ts +9 -0
  286. package/dist/modules/app.d.ts.map +1 -0
  287. package/dist/modules/app.js +20 -0
  288. package/dist/modules/app.js.map +1 -0
  289. package/dist/modules/browser-test.d.ts +9 -0
  290. package/dist/modules/browser-test.d.ts.map +1 -0
  291. package/dist/modules/browser-test.js +67 -0
  292. package/dist/modules/browser-test.js.map +1 -0
  293. package/dist/modules/browser.d.ts +10 -0
  294. package/dist/modules/browser.d.ts.map +1 -0
  295. package/dist/modules/browser.js +89 -0
  296. package/dist/modules/browser.js.map +1 -0
  297. package/dist/modules/config.d.ts +9 -0
  298. package/dist/modules/config.d.ts.map +1 -0
  299. package/dist/modules/config.js +14 -0
  300. package/dist/modules/config.js.map +1 -0
  301. package/dist/modules/files.d.ts +9 -0
  302. package/dist/modules/files.d.ts.map +1 -0
  303. package/dist/modules/files.js +16 -0
  304. package/dist/modules/files.js.map +1 -0
  305. package/dist/modules/forms.d.ts +9 -0
  306. package/dist/modules/forms.d.ts.map +1 -0
  307. package/dist/modules/forms.js +26 -0
  308. package/dist/modules/forms.js.map +1 -0
  309. package/dist/modules/http.d.ts +9 -0
  310. package/dist/modules/http.d.ts.map +1 -0
  311. package/dist/modules/http.js +127 -0
  312. package/dist/modules/http.js.map +1 -0
  313. package/dist/modules/look.d.ts +9 -0
  314. package/dist/modules/look.d.ts.map +1 -0
  315. package/dist/modules/look.js +58 -0
  316. package/dist/modules/look.js.map +1 -0
  317. package/dist/modules/realtime.d.ts +9 -0
  318. package/dist/modules/realtime.d.ts.map +1 -0
  319. package/dist/modules/realtime.js +163 -0
  320. package/dist/modules/realtime.js.map +1 -0
  321. package/dist/modules/storage.d.ts +9 -0
  322. package/dist/modules/storage.d.ts.map +1 -0
  323. package/dist/modules/storage.js +59 -0
  324. package/dist/modules/storage.js.map +1 -0
  325. package/dist/modules/types.d.ts +78 -0
  326. package/dist/modules/types.d.ts.map +1 -0
  327. package/dist/modules/types.js +154 -0
  328. package/dist/modules/types.js.map +1 -0
  329. package/dist/modules/web.d.ts +9 -0
  330. package/dist/modules/web.d.ts.map +1 -0
  331. package/dist/modules/web.js +63 -0
  332. package/dist/modules/web.js.map +1 -0
  333. package/dist/modules/websocket.d.ts +11 -0
  334. package/dist/modules/websocket.d.ts.map +1 -0
  335. package/dist/modules/websocket.js +75 -0
  336. package/dist/modules/websocket.js.map +1 -0
  337. package/dist/parser/expressions/jsx.d.ts +17 -0
  338. package/dist/parser/expressions/jsx.d.ts.map +1 -0
  339. package/dist/parser/expressions/jsx.js +43 -0
  340. package/dist/parser/expressions/jsx.js.map +1 -0
  341. package/dist/parser/expressions/keyframes.d.ts +15 -0
  342. package/dist/parser/expressions/keyframes.d.ts.map +1 -0
  343. package/dist/parser/expressions/keyframes.js +33 -0
  344. package/dist/parser/expressions/keyframes.js.map +1 -0
  345. package/dist/parser/expressions/look.d.ts +16 -0
  346. package/dist/parser/expressions/look.d.ts.map +1 -0
  347. package/dist/parser/expressions/look.js +37 -0
  348. package/dist/parser/expressions/look.js.map +1 -0
  349. package/dist/parser/expressions/visual-block.d.ts +17 -0
  350. package/dist/parser/expressions/visual-block.d.ts.map +1 -0
  351. package/dist/parser/expressions/visual-block.js +21 -0
  352. package/dist/parser/expressions/visual-block.js.map +1 -0
  353. package/dist/parser/keyframes-source.d.ts +24 -0
  354. package/dist/parser/keyframes-source.d.ts.map +1 -0
  355. package/dist/parser/keyframes-source.js +133 -0
  356. package/dist/parser/keyframes-source.js.map +1 -0
  357. package/dist/parser/look-source.d.ts +25 -0
  358. package/dist/parser/look-source.d.ts.map +1 -0
  359. package/dist/parser/look-source.js +189 -0
  360. package/dist/parser/look-source.js.map +1 -0
  361. package/dist/parser/spans.d.ts +24 -0
  362. package/dist/parser/spans.d.ts.map +1 -0
  363. package/dist/parser/spans.js +113 -0
  364. package/dist/parser/spans.js.map +1 -0
  365. package/dist/parser/statements/components.d.ts +37 -0
  366. package/dist/parser/statements/components.d.ts.map +1 -0
  367. package/dist/parser/statements/components.js +185 -0
  368. package/dist/parser/statements/components.js.map +1 -0
  369. package/dist/parser/statements/heads.d.ts +38 -0
  370. package/dist/parser/statements/heads.d.ts.map +1 -0
  371. package/dist/parser/statements/heads.js +55 -0
  372. package/dist/parser/statements/heads.js.map +1 -0
  373. package/dist/parser/statements/imports.d.ts +9 -0
  374. package/dist/parser/statements/imports.d.ts.map +1 -0
  375. package/dist/parser/statements/imports.js +31 -0
  376. package/dist/parser/statements/imports.js.map +1 -0
  377. package/dist/parser/statements/reactive.d.ts +31 -0
  378. package/dist/parser/statements/reactive.d.ts.map +1 -0
  379. package/dist/parser/statements/reactive.js +68 -0
  380. package/dist/parser/statements/reactive.js.map +1 -0
  381. package/dist/parser/statements/unsafe-css.d.ts +21 -0
  382. package/dist/parser/statements/unsafe-css.d.ts.map +1 -0
  383. package/dist/parser/statements/unsafe-css.js +42 -0
  384. package/dist/parser/statements/unsafe-css.js.map +1 -0
  385. package/dist/parser.d.ts +37 -50
  386. package/dist/parser.d.ts.map +1 -1
  387. package/dist/parser.js +98 -882
  388. package/dist/parser.js.map +1 -1
  389. package/dist/runtime-sources.generated.d.ts +1 -1
  390. package/dist/runtime-sources.generated.d.ts.map +1 -1
  391. package/dist/runtime-sources.generated.js +4 -4
  392. package/dist/runtime-sources.generated.js.map +1 -1
  393. package/package.json +2 -2
package/dist/emitter.js CHANGED
@@ -1,10 +1,17 @@
1
- import { cssPropertyName, LOOK_ARITHMETIC_HINT, LOOK_MEDIA_LENGTH_UNITS, LOOK_PROPERTIES, LOOK_PROPERTY_KEYWORDS, LOOK_PROPERTY_VALUE_KINDS } from "./look.js";
2
- import { isCssDeclarationValue } from "./css-tokens.js";
3
- import { collectLookStaticValues, evaluateLookStaticExpression, isLookStaticValue, lookStaticCss } from "./look-static.js";
4
- import { keyframeCssValue, keyframesCanonical, keyframesName } from "./keyframes.js";
5
- import { JavaScriptEmitter, spanIdentity, VELAR_ERROR_NORMALIZATION_MODULE, VELAR_RUNTIME_REGISTRY_KEY } from "@velarscript/compiler/extension";
6
- import { CSS_STRING_RUNTIME_BODY, LOOK_ARITHMETIC_RUNTIME, WEB_FILE_TYPE_RUNTIME, WEB_LOCAL_REACTIVE_BRIDGE_RUNTIME, WEB_LOCAL_REACTIVE_COLLECTION_BRIDGE_RUNTIME, WEB_RUNTIME_BODY, WEB_RUNTIME_FOUNDATION, WEB_RUNTIME_FOUNDATION_SHARED_ERROR, } from "./runtime-sources.generated.js";
1
+ import { JavaScriptEmitter, spanIdentity } from "@velarscript/compiler/extension";
2
+ import { LOOK_ARITHMETIC_HINT } from "./look.js";
3
+ import { isLookStaticValue } from "./look-static.js";
4
+ import { keyframesCanonical, keyframesName } from "./keyframes.js";
7
5
  import { isWebExpression, isWebJsx, isWebKeyframes, isWebLook, isWebStatement, isWebUnit, webExpressionContainsDirectAwait, webStatementContainsDirectAwait, webWatchSubjectLabel, } from "./ast.js";
6
+ import { emitComponent, emitReactiveAssignment } from "./emit/components.js";
7
+ import { emitJsx } from "./emit/jsx.js";
8
+ import { emitLook, emitLookArithmetic, prepareLooks } from "./emit/look.js";
9
+ import { additionalHelpers, containsUnitLiteral, containsWebSyntax, detachedTaskHelpers, emitIsCheck, emitTypeCheck, includesErrorNormalizationRuntime, reactiveBridgeHelpers, visitLookExpressions, } from "./emit/runtime-imports.js";
10
+ // D115 P4 R3d: the JSX recognizers and the scalar-text hint are the emitter's
11
+ // vocabulary, shared with the analyzer that diagnoses what emission demotes.
12
+ // They live with the lowering that defines them and reach their existing
13
+ // importers from here, so no import path moves.
14
+ export { dynamicChildLeaves, jsxKeyedList, JSX_SCALAR_TEXT_HINT, } from "./emit/jsx.js";
8
15
  /**
9
16
  * Statements whose body is not module evaluation. A `def`, a class method, and
10
17
  * a `test` run when something calls them, and reach that caller's failure
@@ -47,22 +54,29 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
47
54
  lookKeywordProperties = new Set();
48
55
  jsxId = 0;
49
56
  keyframeNames = new Map();
57
+ /**
58
+ * D115 P4 R3d: the four emission families this emitter owns as collaborators
59
+ * rather than as more of itself, and the one host object they reach it
60
+ * through. Every `protected` seam is still declared on this class, forwarding
61
+ * to the family that owns its body, so the base emitter reaches the same seam
62
+ * it always did.
63
+ */
64
+ host;
50
65
  constructor(hints, forcedFunctionExports = new Set(), resourceContents = new Map(), extensionImports = new Map(), options = {}) {
51
66
  super(hints, forcedFunctionExports, options);
52
67
  this.resourceContents = resourceContents;
53
68
  this.importedLookStaticValues = new Map([...(extensionImports.get("@velarscript/web") ?? [])]
54
69
  .filter((entry) => isLookStaticValue(entry[1])));
70
+ this.host = this.emitHost();
55
71
  }
56
72
  emit(program) {
57
- this.lookStaticValues = collectLookStaticValues(program, this.importedLookStaticValues);
58
- this.prepareLooks(program);
73
+ prepareLooks(this.host, program);
59
74
  this.webOutput = containsWebSyntax(program);
60
75
  this.needsFileTypeHelper = false;
61
76
  this.needsLookArithmeticRuntime = [...this.hints.extensionCalls.values()].includes(LOOK_ARITHMETIC_HINT);
62
77
  this.moduleEvaluation = true;
63
78
  return super.emit(program);
64
79
  }
65
- /** Emits `render` with module evaluation switched off, for a body that runs under an owner of its own. */
66
80
  outsideModuleEvaluation(render) {
67
81
  const previous = this.moduleEvaluation;
68
82
  this.moduleEvaluation = false;
@@ -83,132 +97,22 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
83
97
  return this.webOutput;
84
98
  }
85
99
  emitTypeCheck(type, value, state = "undefined") {
86
- if (type.kind === "named") {
87
- if (type.name === "Event" || type.name === "KeyboardEvent" || type.name === "PointerEvent" || type.name === "InputEvent" || type.name === "CompositionEvent" || type.name === "ClipboardEvent") {
88
- return `(typeof ${type.name} !== "undefined" && ${value} instanceof ${type.name})`;
89
- }
90
- if (type.name === "Element")
91
- return `(typeof Element !== "undefined" && ${value} instanceof Element)`;
92
- if (type.name === "CanvasElement")
93
- return `(typeof HTMLCanvasElement !== "undefined" && ${value} instanceof HTMLCanvasElement)`;
94
- if (type.name === "DialogElement")
95
- return `(typeof HTMLDialogElement !== "undefined" && ${value} instanceof HTMLDialogElement)`;
96
- if (type.name === "InputElement") {
97
- return `((typeof HTMLInputElement !== "undefined" && ${value} instanceof HTMLInputElement) || (typeof HTMLSelectElement !== "undefined" && ${value} instanceof HTMLSelectElement) || (typeof HTMLTextAreaElement !== "undefined" && ${value} instanceof HTMLTextAreaElement))`;
98
- }
99
- if (type.name === "TextAreaElement")
100
- return `(typeof HTMLTextAreaElement !== "undefined" && ${value} instanceof HTMLTextAreaElement)`;
101
- if (type.name === "Blob")
102
- return `(typeof Blob !== "undefined" && ${value} instanceof Blob)`;
103
- if (type.name === "File") {
104
- this.needsFileTypeHelper = true;
105
- return `__velarFileTypeIs(${value})`;
106
- }
107
- }
108
- return super.emitTypeCheck(type, value, state);
100
+ return emitTypeCheck(this.host, type, value, state);
109
101
  }
110
102
  emitIsCheck(type, value) {
111
- if (type.kind === "named" && (type.name === "Event"
112
- || type.name === "KeyboardEvent"
113
- || type.name === "PointerEvent"
114
- || type.name === "InputEvent"
115
- || type.name === "CompositionEvent"
116
- || type.name === "ClipboardEvent"
117
- || type.name === "Element"
118
- || type.name === "CanvasElement"
119
- || type.name === "DialogElement"
120
- || type.name === "InputElement"
121
- || type.name === "TextAreaElement"
122
- || type.name === "Blob"
123
- || type.name === "File"))
124
- return this.emitTypeCheck(type, value);
125
- return super.emitIsCheck(type, value);
103
+ return emitIsCheck(this.host, type, value);
126
104
  }
127
105
  additionalHelpers(_program) {
128
- return [
129
- ...(this.needsLookArithmeticRuntime ? [LOOK_ARITHMETIC_RUNTIME] : []),
130
- ...(this.webOutput ? this.webRuntimeHelpers() : []),
131
- ...(this.needsFileTypeHelper ? [WEB_FILE_TYPE_RUNTIME] : []),
132
- ];
133
- }
134
- webRuntimeHelpers() {
135
- if (!this.usesSharedRuntimeModules())
136
- return [webRuntime(WEB_RUNTIME_FOUNDATION, this.lookKeywordTable())];
137
- this.requireRuntimeModule(VELAR_ERROR_NORMALIZATION_MODULE);
138
- return [
139
- `import { errorApply as __velarErrorApply, errorCode as __velarErrorCode, isError as __velarIsError, normalizeError as __velarNormalizeError } from ${JSON.stringify(VELAR_ERROR_NORMALIZATION_MODULE)};`,
140
- webRuntime(WEB_RUNTIME_FOUNDATION_SHARED_ERROR, this.lookKeywordTable()),
141
- ];
142
- }
143
- /**
144
- * The closed keyword sets of the properties this module styles, so a value
145
- * the compiler could not read is still checked before it reaches the DOM.
146
- * Only the properties written here ship: the whole table is 17 KiB, and a
147
- * module pays for the properties it uses.
148
- */
149
- lookKeywordTable() {
150
- const entries = [...this.lookKeywordProperties].sort()
151
- .map((name) => ` ${JSON.stringify(cssPropertyName(name))}: ${JSON.stringify([...LOOK_PROPERTY_KEYWORDS.get(name) ?? []])},`);
152
- return entries.length === 0
153
- ? "const __velarLookKeywords = { __proto__: null };"
154
- : `const __velarLookKeywords = {\n __proto__: null,\n${entries.join("\n")}\n};`;
106
+ return additionalHelpers(this.host);
155
107
  }
156
108
  reactiveBridgeHelpers(needsJavaScriptCallBoundary, needsCollections, usedIdentifiers = new Set()) {
157
- if (this.usesSharedRuntimeModules())
158
- return super.reactiveBridgeHelpers(needsJavaScriptCallBoundary, needsCollections, usedIdentifiers);
159
- if (!this.webOutput)
160
- return super.reactiveBridgeHelpers(needsJavaScriptCallBoundary, needsCollections, usedIdentifiers);
161
- if (!needsJavaScriptCallBoundary && !needsCollections)
162
- return [];
163
- return [WEB_LOCAL_REACTIVE_BRIDGE_RUNTIME, ...(needsCollections ? [WEB_LOCAL_REACTIVE_COLLECTION_BRIDGE_RUNTIME] : [])];
109
+ return reactiveBridgeHelpers(this.host, needsJavaScriptCallBoundary, needsCollections, usedIdentifiers);
164
110
  }
165
111
  includesErrorNormalizationRuntime() {
166
- return this.webOutput;
112
+ return includesErrorNormalizationRuntime(this.host);
167
113
  }
168
- // Web detached tasks report through the velar/app error chain with the
169
- // distinct "detached" phase. The runtime registry is looked up at report
170
- // time (module-level tasks can finish before or after the application
171
- // runtime installs); the captured microtask throw keeps a failure loud when
172
- // no runtime exists yet, and 'unhandled: true' keeps it loud when no
173
- // onError handler is installed. Host operations are captured at module
174
- // initialization, matching the owned-callback discipline.
175
114
  detachedTaskHelpers() {
176
- // A module with no Web syntax emits no Web runtime, so it must keep Core's
177
- // host reporting: the browser path would route a detached failure through a
178
- // runtime registry that never gets installed and end in a microtask throw,
179
- // which under `velar test` kills the whole Node test process.
180
- if (!this.webOutput)
181
- return super.detachedTaskHelpers();
182
- return [[
183
- `const __velarDetachedRegistryKey = Symbol.for(${JSON.stringify(VELAR_RUNTIME_REGISTRY_KEY)});`,
184
- "const __velarDetachedPromiseThen = globalThis.Promise.prototype.then;",
185
- "const __velarDetachedApply = Reflect.apply;",
186
- "const __velarDetachedEnqueue = queueMicrotask;",
187
- "function __velarDetachedReport(failure) {",
188
- " const error = __velarNormalizeError(failure);",
189
- " const runtime = globalThis[__velarDetachedRegistryKey];",
190
- " if (runtime && typeof runtime.report === \"function\") {",
191
- " // An action reports its own failure once, in the action phase with",
192
- " // the action's name as detail. The detached observer of that same",
193
- " // rejection must not report it a second time.",
194
- " try {",
195
- " if (__velarIsError(failure) && __velarGraphWeakSetRemove(runtime.actionFailures, failure)) return;",
196
- " } catch {}",
197
- " runtime.report(error, { phase: \"detached\", detail: \"\", unhandled: true });",
198
- " return;",
199
- " }",
200
- " __velarDetachedApply(__velarDetachedEnqueue, globalThis, [() => { throw error; }]);",
201
- "}",
202
- "function __velarDetachedTask(task) {",
203
- // D114 W2: the one place a detached Promise enters the Web runtime, and
204
- // so the one place the reactive window can be told that an observer run
205
- // started asynchronous work. The runtime foundation decides whether a run
206
- // is in progress; this site only reports the fact.
207
- " __velarNoteAsyncWork();",
208
- " __velarDetachedApply(__velarDetachedPromiseThen, task, [null, __velarDetachedReport]);",
209
- " return null;",
210
- "}",
211
- ].join("\n")];
115
+ return detachedTaskHelpers(this.host);
212
116
  }
213
117
  visitExtensionRuntimeExpression(expression, visitExpression) {
214
118
  if (isWebUnit(expression))
@@ -302,7 +206,7 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
302
206
  if (statement.kind === "ExtensionStatement:web:unsafe-css")
303
207
  return "";
304
208
  if (statement.kind === "ExtensionStatement:web:component")
305
- return this.emitComponent(statement, depth);
209
+ return emitComponent(this.host, statement, depth);
306
210
  if (statement.kind === "ExtensionStatement:web:state") {
307
211
  const indentation = " ".repeat(depth);
308
212
  return `${indentation}${statement.exported ? "export " : ""}const ${statement.name} = __velarState(${this.emitMappedExpression(statement.initializer)}, ${JSON.stringify(statement.name)});`;
@@ -338,7 +242,7 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
338
242
  }
339
243
  }
340
244
  if (statement.kind === "AssignmentStatement") {
341
- const reactive = this.emitReactiveAssignment(statement, depth);
245
+ const reactive = emitReactiveAssignment(this.host, statement, depth);
342
246
  if (reactive)
343
247
  return reactive;
344
248
  }
@@ -369,12 +273,12 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
369
273
  if (expression.kind === "BinaryExpression" && ["+", "-", "*", "/"].includes(expression.operator)
370
274
  && (containsUnitLiteral(expression)
371
275
  || this.hints.extensionCalls.get(spanIdentity(expression.span)) === LOOK_ARITHMETIC_HINT)) {
372
- return this.emitLookArithmetic(expression);
276
+ return emitLookArithmetic(this.host, expression);
373
277
  }
374
278
  if (isWebExpression(expression) && expression.kind === "ExtensionExpression:web:look-hook")
375
279
  return "false";
376
280
  if (isWebLook(expression))
377
- return this.emitLook(expression);
281
+ return emitLook(this.host, expression);
378
282
  if (expression.kind === "CallExpression") {
379
283
  // D103 rule 2: a checked design token reference is compile-time text. The
380
284
  // analyzer proved the name is a literal custom property identifier and
@@ -398,7 +302,7 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
398
302
  return JSON.stringify(controlled);
399
303
  }
400
304
  if (isWebJsx(expression)) {
401
- return this.emitJsx(expression, this.currentScope ?? "__velarGlobalScope", this.currentScope !== null, this.currentJsxNamespace, false);
305
+ return emitJsx(this.host, expression, this.currentScope ?? "__velarGlobalScope", this.currentScope !== null, this.currentJsxNamespace, false);
402
306
  }
403
307
  if (expression.kind === "CallExpression" && expression.callee.kind === "IdentifierExpression"
404
308
  && expression.callee.name === "mount" && expression.arguments.length === 2) {
@@ -429,887 +333,54 @@ export class WebJavaScriptEmitter extends JavaScriptEmitter {
429
333
  return emitted;
430
334
  return emitted.replaceAll("__velarListPop(", "__velarWebListPop(");
431
335
  }
432
- emitLook(expression) {
433
- return `__velarLook([${this.emitLookEntries(expression.entries, [EMPTY_LOOK_TERM], "").join(", ")}])`;
434
- }
435
- emitLookEntries(entries, contexts, target) {
436
- const parts = [];
437
- for (const entry of entries) {
438
- if (entry.kind === "LookSpread") {
439
- parts.push(this.emitMappedExpression(entry.value));
440
- continue;
441
- }
442
- if (entry.kind === "LookIf") {
443
- const thenContexts = combineLookTerms(contexts, lookConditionTerms(entry.condition, false, this.lookStaticValues));
444
- const elseContexts = combineLookTerms(contexts, lookConditionTerms(entry.condition, true, this.lookStaticValues));
445
- parts.push(...this.emitLookEntries(entry.thenEntries, thenContexts, target));
446
- parts.push(...this.emitLookEntries(entry.elseEntries, elseContexts, target));
447
- continue;
448
- }
449
- if (entry.kind === "LookTarget") {
450
- parts.push(...this.emitLookEntries(entry.entries, contexts, entry.name));
451
- continue;
452
- }
453
- const property = cssPropertyName(entry.name);
454
- for (const context of contexts) {
455
- const token = lookToken(context.staticAtoms, target, property);
456
- const rule = `{ rules: { ${JSON.stringify(token)}: ${this.emitLookValue(entry.value)} } }`;
457
- const runtime = context.runtimeAtoms.map((atom) => {
458
- const value = this.emitCondition(atom.expression);
459
- return atom.negated ? `!(${value})` : `(${value})`;
460
- }).join(" && ");
461
- parts.push(runtime ? `(${runtime} ? ${rule} : null)` : rule);
462
- }
463
- }
464
- return parts;
465
- }
466
- emitLookValue(expression) {
467
- return this.emitMappedExpression(expression);
468
- }
469
- emitLookArithmetic(expression) {
470
- return `__velarLookMath(${JSON.stringify(expression.operator)}, ${this.emitMappedExpression(expression.left)}, ${this.emitMappedExpression(expression.right)})`;
471
- }
472
- emitComponent(statement, depth) {
473
- const indentation = " ".repeat(depth);
474
- const outerIndent = " ".repeat(depth + 1);
475
- const bodyIndent = " ".repeat(depth + 2);
476
- const previousScope = this.currentScope;
477
- const previousJsxNamespace = this.currentJsxNamespace;
478
- this.currentScope = "__velarComponentScope";
479
- this.currentJsxNamespace = "__velarNamespace";
480
- // Props are live reactive inputs: every parameter becomes a read-only
481
- // handle over the per-instance props store, so prop reads lower through
482
- // .get() exactly like state reads do.
483
- const lines = [];
484
- for (const parameter of statement.parameters) {
485
- if (parameter.defaultValue) {
486
- lines.push(`${bodyIndent}const ${parameter.name} = __velarProp(__velarProps, ${JSON.stringify(parameter.name)}, () => (${this.emitMappedExpression(parameter.defaultValue)}));`);
487
- }
488
- else {
489
- lines.push(`${bodyIndent}const ${parameter.name} = __velarRequiredProp(__velarProps, ${JSON.stringify(parameter.name)}, ${JSON.stringify(statement.name)});`);
490
- }
491
- }
492
- let render = null;
493
- let expose = null;
494
- let mountedBody = [];
495
- let cleanupBody = [];
496
- for (const item of statement.body) {
497
- if (item.kind === "ExtensionStatement:web:state") {
498
- lines.push(`${bodyIndent}const ${item.name} = __velarState(${this.emitMappedExpression(item.initializer)}, ${JSON.stringify(item.name)});`);
499
- }
500
- else if (item.kind === "ExtensionStatement:web:computed") {
501
- lines.push(`${bodyIndent}const ${item.name} = __velarComputed(() => (${this.emitMappedExpression(item.initializer)}));`);
502
- }
503
- else if (item.kind === "ExtensionStatement:web:resource") {
504
- lines.push(`${bodyIndent}const ${item.name} = __velarResource(() => ${this.emitMappedExpression(item.initializer)}, __velarComponentScope, ${JSON.stringify(item.name)});`);
505
- }
506
- else if (item.kind === "ExtensionStatement:web:action") {
507
- const parameters = item.parameters.map((parameter) => this.emitParameter(parameter.name, parameter.defaultValue, parameter.rest)).join(", ");
508
- const actionLines = [...this.emitStatementLines(item.body, depth + 3)];
509
- if (!this.blockAlwaysReturns(item.body))
510
- actionLines.push(`${" ".repeat(depth + 3)}return null;`);
511
- const actionBody = actionLines.join("\n");
512
- lines.push(`${bodyIndent}const ${item.name} = __velarAction(async (${parameters}) => {${actionBody ? `\n${actionBody}\n${bodyIndent}` : ""}}, __velarComponentScope, ${JSON.stringify(item.name)});`);
513
- }
514
- else if (item.kind === "ExtensionStatement:web:watch") {
515
- const parameters = [item.currentName, item.previousName].filter((name) => name !== null).join(", ");
516
- const watchLines = this.emitStatementLines(item.body, depth + 3).join("\n");
517
- lines.push(`${bodyIndent}__velarWatch(() => ${this.emitMappedExpression(item.expression)}, (${parameters}) => {${watchLines ? `\n${watchLines}\n${bodyIndent}` : ""}}, __velarComponentScope, ${JSON.stringify(webWatchSubjectLabel(item.expression))});`);
518
- }
519
- else if (item.kind === "ExtensionStatement:web:expose") {
520
- expose ??= item.value;
521
- }
522
- else if (item.kind === "ExtensionStatement:web:mounted") {
523
- mountedBody = item.body;
524
- }
525
- else if (item.kind === "ExtensionStatement:web:cleanup") {
526
- cleanupBody = item.body;
527
- }
528
- else if (item.kind === "ReturnStatement") {
529
- render = item.value;
530
- }
531
- else {
532
- lines.push(this.emitMappedStatement(item, depth + 2));
533
- }
534
- }
535
- // A direct JSX root owns its own attribute/child observers and keeps a
536
- // stable host. Every other WebNode expression is a live root position:
537
- // evaluate it inside a dedicated child scope so conditions and helper
538
- // calls can replace the root without rerunning component setup.
539
- let renderedRoot = "__velarDomCreateComment(\"missing render\")";
540
- if (render) {
541
- if (isWebJsx(render))
542
- renderedRoot = this.emitMappedExpression(render);
543
- else {
544
- const rootScope = this.currentScope;
545
- this.currentScope = "__velarDynamicScope";
546
- try {
547
- renderedRoot = `__velarDynamicComponent((__velarDynamicScope) => ${this.emitMappedExpression(render)}, __velarComponentScope)`;
548
- }
549
- finally {
550
- this.currentScope = rootScope;
551
- }
552
- }
553
- }
554
- lines.push(`${bodyIndent}const __velarRoot = ${renderedRoot};`);
555
- lines.push(`${bodyIndent}const __velarHandle = ${expose ? `__velarComponentHandle(${this.emitMappedExpression(expose)}, ${JSON.stringify(statement.name)})` : "null"};`);
556
- lines.push(`${bodyIndent}if (__velarProps.class !== undefined) __velarClassBindRoot(__velarRoot, () => __velarProps.class, __velarComponentScope);`);
557
- lines.push(`${bodyIndent}if (__velarProps.look !== undefined) __velarLookBindRoot(__velarRoot, () => __velarProps.look, __velarComponentScope);`);
558
- // 'class' and 'look' are fields a component may declare and read, so they
559
- // arrive as props. The 'style:' slot is not: it is bound to the instance
560
- // root by whoever wrote it, at the instantiation site, for every component
561
- // alike -- see __velarInstantiate.
562
- const mounted = this.emitStatementLines(mountedBody, depth + 3).join("\n");
563
- const cleanup = cleanupBody.map((child) => {
564
- if (["VariableDeclaration", "FunctionDeclaration", "ClassDeclaration", "TypeDeclaration", "EnumDeclaration"].includes(child.kind)) {
565
- return this.emitMappedStatement(child, depth + 3);
566
- }
567
- const inner = this.emitMappedStatement(child, depth + 4);
568
- if (!inner)
569
- return "";
570
- const cleanupIndent = " ".repeat(depth + 3);
571
- return `${cleanupIndent}__velarCleanupStep(() => {\n${inner}\n${cleanupIndent}}, __velarComponentScope);`;
572
- }).filter(Boolean).join("\n");
573
- const cleanupBodyText = `() => {${cleanup ? `\n${cleanup}\n${bodyIndent}` : ""}}`;
574
- const functionLines = [
575
- `${outerIndent}const __velarComponentScope = __velarSetupBegin(__velarScope(${JSON.stringify(statement.name)}));`,
576
- `${outerIndent}let __velarConstructionCleanup = () => {};`,
577
- `${outerIndent}try {`,
578
- `${bodyIndent}__velarConstructionCleanup = ${cleanupBodyText};`,
579
- ...lines,
580
- `${bodyIndent}return __velarSetupEnd(__velarComponent(__velarRoot, __velarComponentScope, async () => {${mounted ? `\n${mounted}\n${bodyIndent}` : ""}}, __velarConstructionCleanup, __velarHandle));`,
581
- `${outerIndent}} catch (__velarConstructionError) {`,
582
- `${bodyIndent}__velarSetupEnd(null);`,
583
- `${bodyIndent}try { __velarConstructionCleanup(); } catch (__velarCleanupError) { __velarReport(__velarCleanupError, "cleanup", __velarComponentScope); }`,
584
- `${bodyIndent}__velarDestroyScope(__velarComponentScope);`,
585
- `${bodyIndent}throw __velarConstructionError;`,
586
- `${outerIndent}}`,
587
- ];
588
- this.currentScope = previousScope;
589
- this.currentJsxNamespace = previousJsxNamespace;
590
- return `${indentation}${statement.exported ? "export " : ""}function ${statement.name}(__velarProps = {}, __velarNamespace = "html") {\n${functionLines.filter(Boolean).join("\n")}\n${indentation}}`;
591
- }
592
- emitReactiveAssignment(statement, depth) {
593
- const indentation = " ".repeat(depth);
594
- if (statement.target.kind === "IdentifierExpression"
595
- && this.hints.reactiveReferences.get(spanIdentity(statement.target.span)) === "state") {
596
- const state = statement.target.name;
597
- const value = this.emitMappedExpression(statement.value);
598
- if (statement.operator === "=")
599
- return `${indentation}${state}.set(${value});`;
600
- return `${indentation}${state}.set(${state}.get() ${statement.operator.slice(0, -1)} ${value});`;
601
- }
602
- return null;
603
- }
604
- emitJsx(expression, scope, asChild, namespace, mapped = true) {
605
- const render = () => this.emitJsxCode(expression, scope, asChild, namespace);
606
- return mapped ? this.emitMappedJavaScript(expression.span, render) : render();
607
- }
608
- emitJsxCode(expression, scope, asChild, namespace) {
609
- if (/^[A-Z]/u.test(expression.tag)) {
610
- const reactiveComponent = this.hints.reactiveReferences.has(spanIdentity(expression.tagSpan));
611
- const componentScope = reactiveComponent ? "__velarDynamicScope" : scope;
612
- const previousScope = this.currentScope;
613
- if (reactiveComponent)
614
- this.currentScope = componentScope;
615
- try {
616
- // Static component identity keeps the existing stable child fast path.
617
- // A reactive Component value owns a dynamic region that remounts only
618
- // when the constructor identity itself changes; ordinary prop updates
619
- // continue through the child's live prop cells.
620
- const properties = expression.attributes
621
- .filter((attribute) => attribute.name !== "key" && attribute.name !== "ref" && attribute.name !== "look" && !attribute.name.startsWith("look:")
622
- && attribute.name !== "style" && !attribute.name.startsWith("style:"))
623
- .map((attribute) => this.emitMappedJavaScript(attribute.span, () => `${this.emitObjectKey(attribute.name)}: () => (${this.emitJsxAttributeValue(attribute)})`));
624
- const lookValue = this.emitJsxLookValue(expression);
625
- const lookAttribute = expression.attributes.find((attribute) => attribute.name === "look" || attribute.name.startsWith("look:"));
626
- if (lookValue && lookAttribute) {
627
- properties.push(this.emitMappedJavaScript(lookAttribute.span, () => `look: () => (${lookValue})`));
628
- }
629
- const styleValue = this.emitJsxStyleValue(expression);
630
- const styleAttribute = expression.attributes.find((attribute) => attribute.name.startsWith("style:"));
631
- if (styleValue && styleAttribute) {
632
- properties.push(this.emitMappedJavaScript(styleAttribute.span, () => `__velarStyle: () => (${styleValue})`));
633
- }
634
- // Children stay a thunk so the charter's evaluation order holds at
635
- // the runtime boundary: props left to right, then children, then the
636
- // component function. The thunk takes the scope to build into, so the
637
- // position that shows the slot owns what it built and destroys it when
638
- // it stops showing it.
639
- const children = hasMeaningfulChildren(expression.children)
640
- ? `(__velarChildrenScope = ${componentScope}) => (${this.emitJsxChildrenCode(expression.children, namespace)})`
641
- : "undefined";
642
- const ref = expression.attributes.find((attribute) => attribute.name === "ref")?.value;
643
- const refSetter = ref && typeof ref !== "string" && ref.kind === "IdentifierExpression"
644
- ? `(next, previous) => { if (previous === undefined || ${ref.name} === previous) ${ref.name} = next; }`
645
- : null;
646
- const component = reactiveComponent ? `${expression.tag}.get()` : expression.tag;
647
- const arguments_ = `${component}, { ${properties.join(", ")} }, ${children}, ${componentScope}, ${namespace}${refSetter ? `, ${refSetter}` : ""}`;
648
- if (reactiveComponent) {
649
- return `__velarDynamicComponent((__velarDynamicScope) => __velarChild(${arguments_}), ${scope})`;
650
- }
651
- if (asChild)
652
- return `__velarChild(${arguments_})`;
653
- // D90 R4-b's designed site: `const root = <App />` builds its instance
654
- // while the module evaluates, which is outside every transaction the
655
- // runtime owns. The site stays legal and eager; only its failure moves,
656
- // from an uncaught module-evaluation throw to the same no-blank-page
657
- // machinery `mount` has always run.
658
- return `${this.moduleEvaluation ? "__velarModuleInstantiate" : "__velarInstantiate"}(${arguments_})`;
659
- }
660
- finally {
661
- this.currentScope = previousScope;
662
- }
663
- }
664
- const id = ++this.jsxId;
665
- const element = `__velarElement${id}`;
666
- const elementNamespace = expression.tag === "svg" ? '"svg"' : namespace;
667
- const childNamespace = expression.tag === "foreignObject" ? '"html"' : elementNamespace;
668
- const lines = [expression.tag
669
- ? `const ${element} = __velarCreateElement(${JSON.stringify(expression.tag)}, ${elementNamespace});`
670
- : `const ${element} = __velarDomCreateFragment();`];
671
- let emittedLook = false;
672
- let emittedStyle = false;
673
- for (const attribute of expression.attributes) {
674
- if (attribute.name === "key")
675
- continue;
676
- if (attribute.name === "look" || attribute.name.startsWith("look:")) {
677
- if (!emittedLook) {
678
- emittedLook = true;
679
- const lookValue = this.emitJsxLookValue(expression);
680
- if (lookValue)
681
- lines.push(this.emitMappedJavaScript(attribute.span, () => `__velarLookBind(${element}, () => ${lookValue}, ${scope});`));
682
- }
683
- continue;
684
- }
685
- if (attribute.name.startsWith("style:")) {
686
- if (!emittedStyle) {
687
- emittedStyle = true;
688
- const styleValue = this.emitJsxStyleValue(expression);
689
- if (styleValue)
690
- lines.push(this.emitMappedJavaScript(attribute.span, () => `__velarStyleBind(${element}, () => (${styleValue}), ${scope});`));
691
- }
692
- continue;
693
- }
694
- if (attribute.name === "style")
695
- continue;
696
- lines.push(this.emitMappedJavaScript(attribute.span, () => {
697
- const value = attribute.value;
698
- if (attribute.name === "ref" && value && typeof value !== "string" && value.kind === "IdentifierExpression") {
699
- return `${value.name} = ${element}; __velarAppendOwned(${scope}.cleanups, () => { if (${value.name} === ${element}) ${value.name} = null; });`;
700
- }
701
- if (attribute.name.startsWith("on:") && value && typeof value !== "string") {
702
- const [event, ...modifiers] = attribute.name.slice(3).split(".");
703
- return `__velarOn(${element}, ${JSON.stringify(event)}, () => (${this.emitMappedExpression(value)}), ${scope}, ${JSON.stringify(modifiers)});`;
704
- }
705
- if (attribute.name === "bind:value" && value && typeof value !== "string") {
706
- const numeric = expression.tag === "input" && expression.attributes.some((item) => item.name === "type" && item.value === "number");
707
- const enumName = this.hints.enumValueBindings.get(attribute.span.start);
708
- return `__velarBindValue(${element}, ${this.emitBindTarget(value)}, ${scope}, ${numeric}${enumName ? `, ${enumName}.parse` : ""});`;
709
- }
710
- if (attribute.name === "bind:checked" && value && typeof value !== "string") {
711
- return `__velarBindChecked(${element}, ${this.emitBindTarget(value)}, ${scope});`;
712
- }
713
- if (attribute.name === "bind:group" && value && typeof value !== "string") {
714
- const multiple = expression.attributes.some((item) => item.name === "type" && item.value === "checkbox");
715
- const enumName = this.hints.enumValueBindings.get(attribute.span.start);
716
- return `__velarBindGroup(${element}, ${this.emitBindTarget(value)}, ${scope}, ${multiple}${enumName ? `, ${enumName}.parse` : ""});`;
717
- }
718
- if (attribute.name.startsWith("class:") && value && typeof value !== "string") {
719
- return `__velarClass(${element}, ${JSON.stringify(attribute.name.slice(6))}, () => ${this.emitMappedExpression(value)}, ${scope});`;
720
- }
721
- if (attribute.name === "host")
722
- return `${element}.__velarHost = true;`;
723
- if (attribute.name === "class" && value && typeof value !== "string") {
724
- return `__velarClassBind(${element}, () => ${this.emitMappedExpression(value)}, ${scope});`;
725
- }
726
- if (attribute.name === "unsafe:html") {
727
- const html = typeof value === "string" ? JSON.stringify(value) : value === null ? '""' : this.emitMappedExpression(value);
728
- return `__velarHtml(${element}, () => ${html}, ${scope});`;
729
- }
730
- if (typeof value === "string" || value === null) {
731
- return `__velarStaticAttr(${element}, ${JSON.stringify(attribute.name)}, ${value === null ? "true" : JSON.stringify(value)});`;
732
- }
733
- return `__velarAttr(${element}, ${JSON.stringify(attribute.name)}, () => ${this.emitMappedExpression(value)}, ${scope});`;
734
- }));
735
- }
736
- for (const child of expression.children) {
737
- if (child.kind === "JSXText") {
738
- const text = normalizeJsxText(child.value);
739
- if (text)
740
- lines.push(this.emitMappedJavaScript(child.span, () => `__velarDomAppend(${element}, __velarDomCreateTextNode(${JSON.stringify(text)}));`));
741
- }
742
- else if (child.kind === "ExtensionExpression:web:jsx") {
743
- lines.push(this.emitMappedJavaScript(child.span, () => `__velarAppend(${element}, ${this.emitJsx(child, scope, true, childNamespace)});`));
744
- }
745
- else {
746
- lines.push(this.emitMappedJavaScript(child.expression.span, () => this.emitDynamicChild(element, child.expression, scope, childNamespace)));
747
- }
748
- }
749
- lines.push(`return ${element};`);
750
- return `(() => { ${lines.join(" ")} })()`;
751
- }
752
- emitJsxChildren(children, scope, namespace) {
753
- const fragmentSpan = children[0]?.span ?? { start: 0, end: 0 };
754
- const fragment = { kind: "ExtensionExpression:web:jsx", tag: "", tagSpan: { start: fragmentSpan.start, end: fragmentSpan.start }, attributes: [], children, span: fragmentSpan };
755
- return this.emitJsx(fragment, scope, true, namespace);
756
- }
757
- // The slot body builds into whichever scope the consuming position hands it,
758
- // so every observer, ref and cleanup it registers dies with that position
759
- // rather than accumulating on the caller for the component's whole lifetime.
760
- emitJsxChildrenCode(children, namespace) {
761
- const previousScope = this.currentScope;
762
- this.currentScope = "__velarChildrenScope";
763
- try {
764
- return this.emitJsxChildren(children, "__velarChildrenScope", namespace);
765
- }
766
- finally {
767
- this.currentScope = previousScope;
768
- }
769
- }
770
- emitDynamicChild(parent, expression, scope, namespace) {
771
- const leaves = dynamicChildLeaves(expression);
772
- const previousScope = this.currentScope;
773
- const previousJsxNamespace = this.currentJsxNamespace;
774
- this.currentScope = "__velarChildScope";
775
- this.currentJsxNamespace = namespace;
776
- // A conditional splits into one region per branch leaf only when a keyed
777
- // list is somewhere among them; each region gates itself on the shared
778
- // branch conditions, so at most one region renders content at a time and
779
- // the keyed list keeps identity-preserving children across the branch flip.
780
- // Without a keyed leaf the interpolation stays one dynamic region -- unless
781
- // its checked type can only ever be one text node, which is the whole tree
782
- // of a conversation surface and is answered by one text node instead (F1).
783
- const keyed = leaves.some((leaf) => leaf.list?.key);
784
- const scalarText = !keyed && this.isScalarTextChild(expression);
785
- // A scalar region owns no child scope, so nothing inside it may address
786
- // one; the guard above proves nothing does.
787
- if (scalarText)
788
- this.currentScope = scope;
789
- const statements = keyed
790
- ? leaves.map((leaf) => this.emitDynamicChildLeaf(parent, leaf, scope, namespace))
791
- : scalarText
792
- ? [`__velarText(${parent}, () => ${this.emitMappedExpression(expression)}, ${scope});`]
793
- : [`__velarDynamic(${parent}, (__velarChildScope) => ${this.emitMappedExpression(expression)}, ${scope});`];
794
- this.currentScope = previousScope;
795
- this.currentJsxNamespace = previousJsxNamespace;
796
- return statements.join(" ");
797
- }
798
336
  /**
799
- * The two conditions for the scalar-text fast path, both of which must hold:
800
- * the analyzer proved the checked type renders as exactly one text node, and
801
- * the expression builds no JSX of its own. Everything else keeps the full
802
- * dynamic region, so a widening of the type rule can only ever be a
803
- * deliberate edit to `VelarWebAnalyzer.isScalarTextType`.
337
+ * The one object every family is handed. Its properties are live reads and
338
+ * writes of this emitter: a family that records "this module needs the
339
+ * file-type helper" or assigns the stylesheet must set the emitter's own
340
+ * field, because `emit()`, `css()` and `styleSegments()` read them after
341
+ * every family has run.
804
342
  */
805
- isScalarTextChild(expression) {
806
- return this.hints.extensionCalls.get(spanIdentity(expression.span)) === JSX_SCALAR_TEXT_HINT
807
- && !containsJsxExpression(expression);
808
- }
809
- emitDynamicChildLeaf(parent, leaf, scope, namespace) {
810
- const list = leaf.list;
811
- if (list?.key) {
812
- const source = this.emitGuardedExpression(leaf.guards, this.emitMappedExpression(list.source), "[]");
813
- const parameter = list.arrow.parameters[0].name;
814
- const key = this.emitJsxAttributeValue(list.key);
815
- const render = this.emitJsx(list.arrow.body, "__velarChildScope", true, namespace);
816
- return `__velarKeyed(${parent}, () => ${source}, (${parameter}) => ${key}, (${parameter}, __velarChildScope) => ${render}, ${scope});`;
817
- }
818
- const value = this.emitGuardedExpression(leaf.guards, this.emitMappedExpression(leaf.expression), "null");
819
- return `__velarDynamic(${parent}, (__velarChildScope) => ${value}, ${scope});`;
820
- }
821
- // Wraps a leaf's expression in its branch conditions, innermost last, so the
822
- // leaf evaluates only while its branch is active and yields the inactive
823
- // placeholder ('[]' for keyed reads, 'null' for dynamic regions) otherwise.
824
- emitGuardedExpression(guards, inner, inactive) {
825
- let output = inner;
826
- for (let index = guards.length - 1; index >= 0; index -= 1) {
827
- const guard = guards[index];
828
- const condition = this.emitMappedExpression(guard.condition);
829
- output = guard.thenBranch
830
- ? `(${condition}) ? (${output}) : ${inactive}`
831
- : `(${condition}) ? ${inactive} : (${output})`;
832
- }
833
- return output;
834
- }
835
- /**
836
- * D47 rule 84(A): a bind target is a state cell, or a writable reactive
837
- * location inside one. A member/index path lowers to the get/set pair the
838
- * binding helpers already expect, so a field of state reads and writes through
839
- * exactly the same statements the author would have written by hand.
840
- */
841
- emitBindTarget(value) {
842
- if (value.kind === "IdentifierExpression")
843
- return value.name;
844
- const next = { kind: "IdentifierExpression", name: "__velarBindNext", span: value.span };
845
- const read = this.emitMappedExpression(value);
846
- const assignment = { kind: "AssignmentStatement", target: value, value: next, operator: "=", span: value.span };
847
- const write = this.emitStatement(assignment, 0).trim();
848
- return `{ get: () => (${read}), set: (__velarBindNext) => { ${write} } }`;
849
- }
850
- emitJsxAttributeValue(attribute) {
851
- if (attribute.value === null)
852
- return "true";
853
- if (typeof attribute.value === "string")
854
- return JSON.stringify(attribute.value);
855
- return this.emitMappedExpression(attribute.value);
856
- }
857
- emitJsxLookValue(expression) {
858
- const base = expression.attributes.find((attribute) => attribute.name === "look");
859
- const inline = expression.attributes.filter((attribute) => attribute.name.startsWith("look:"));
860
- const baseValue = base?.value && typeof base.value !== "string" ? this.emitMappedExpression(base.value) : null;
861
- if (inline.length === 0)
862
- return baseValue;
863
- const rules = inline.map((attribute) => {
864
- const property = cssPropertyName(attribute.name.slice("look:".length));
865
- const token = lookToken([], "", property);
866
- const value = attribute.value === null ? "null"
867
- : typeof attribute.value === "string" ? JSON.stringify(attribute.value)
868
- : this.emitMappedExpression(attribute.value);
869
- return `${JSON.stringify(token)}: ${value}`;
870
- });
871
- const anonymous = `{ rules: { ${rules.join(", ")} } }`;
872
- return `__velarLook([${[baseValue, anonymous].filter(Boolean).join(", ")}])`;
873
- }
874
- emitJsxStyleValue(expression) {
875
- const inline = expression.attributes.filter((attribute) => attribute.name.startsWith("style:"));
876
- if (inline.length === 0)
877
- return null;
878
- const properties = inline.map((attribute) => {
879
- const property = cssPropertyName(attribute.name.slice("style:".length));
880
- const value = attribute.value === null ? "null"
881
- : typeof attribute.value === "string" ? JSON.stringify(attribute.value)
882
- : this.emitMappedExpression(attribute.value);
883
- return `${JSON.stringify(property)}: ${value}`;
884
- });
885
- return `{ ${properties.join(", ")} }`;
886
- }
887
- prepareLooks(program) {
888
- const rules = new Map();
889
- const keyframeRules = new Map();
890
- const keyframeCanonicals = new Map();
891
- this.keyframeNames.clear();
892
- this.lookKeywordProperties.clear();
893
- // A token's stylesheet position used to be wherever it first appeared
894
- // anywhere in the module, because a Map keeps first-insertion order. The
895
- // sequence records that first appearance explicitly so emission can sort by
896
- // condition rank first and fall back to declaration order, rather than
897
- // letting an unrelated earlier look decide a later one's winner (LOK-U8).
898
- let sequence = 0;
899
- const addRule = (token, property, target, staticAtoms) => {
900
- if (rules.has(token))
901
- return;
902
- rules.set(token, { token, property, target, staticAtoms, sequence: sequence += 1 });
903
- };
904
- const noteKeywordProperty = (name) => {
905
- if (LOOK_PROPERTY_VALUE_KINDS.get(name) === "keyword")
906
- this.lookKeywordProperties.add(name);
907
- };
908
- const visit = (value) => {
909
- if (!value || typeof value !== "object")
910
- return;
911
- const record = value;
912
- if (record.kind === "ExtensionExpression:web:jsx") {
913
- const element = record;
914
- for (const attribute of element.attributes) {
915
- if (!attribute.name.startsWith("look:") && !attribute.name.startsWith("style:"))
916
- continue;
917
- const name = attribute.name.slice(attribute.name.indexOf(":") + 1);
918
- if (!LOOK_PROPERTIES.has(name))
919
- continue;
920
- noteKeywordProperty(name);
921
- if (!attribute.name.startsWith("look:"))
922
- continue;
923
- const property = cssPropertyName(name);
924
- addRule(lookToken([], "", property), property, "", []);
925
- }
926
- }
927
- if (record.kind === "ExtensionExpression:web:look") {
928
- const collect = (entries, contexts = [EMPTY_LOOK_TERM], target = "") => {
929
- for (const entry of entries) {
930
- if (entry.kind === "LookProperty") {
931
- const property = cssPropertyName(entry.name);
932
- noteKeywordProperty(entry.name);
933
- for (const context of contexts) {
934
- addRule(lookToken(context.staticAtoms, target, property), property, target, context.staticAtoms);
935
- }
936
- }
937
- else if (entry.kind === "LookIf") {
938
- collect(entry.thenEntries, combineLookTerms(contexts, lookConditionTerms(entry.condition, false, this.lookStaticValues)), target);
939
- collect(entry.elseEntries, combineLookTerms(contexts, lookConditionTerms(entry.condition, true, this.lookStaticValues)), target);
940
- }
941
- else if (entry.kind === "LookTarget") {
942
- collect(entry.entries, contexts, entry.name);
943
- }
944
- }
945
- };
946
- collect(record.entries);
947
- }
948
- if (record.kind === "ExtensionExpression:web:keyframes") {
949
- const expression = record;
950
- const canonical = keyframesCanonical(expression, this.lookStaticValues);
951
- const name = keyframesName(canonical);
952
- this.keyframeNames.set(spanIdentity(expression.span), name);
953
- const reused = keyframeCanonicals.get(name);
954
- // The name is a promise that equal structures share one rule. Reusing
955
- // it for a structure that is not equal would make one animation play
956
- // another's motion, so the reuse path proves the identity rather than
957
- // trusting the digest (LOK-U11).
958
- if (reused !== undefined && reused !== canonical) {
959
- throw new Error(`Generated keyframes name ${name} collides between two different keyframe structures`);
960
- }
961
- if (reused === undefined) {
962
- keyframeCanonicals.set(name, canonical);
963
- const stops = [...expression.stops]
964
- .sort((left, right) => Math.min(...left.offsets) - Math.min(...right.offsets))
965
- .map((stop) => {
966
- const selectors = [...stop.offsets].sort((left, right) => left - right)
967
- .map((offset) => offset === 0 ? "from" : offset === 100 ? "to" : `${offset}%`)
968
- .join(",");
969
- const declarations = stop.entries.map((entry) => {
970
- const css = keyframeCssValue(entry.value, this.lookStaticValues);
971
- // A value the lowering could not prove is one balanced
972
- // declaration never reaches the concatenation: `}` in a stop
973
- // closed the at-rule and turned the rest into author-owned CSS
974
- // in the compiler-owned segment (LOK-U9). The analyzer already
975
- // reports the same null as a diagnostic, so emission only has
976
- // to stay structurally incapable of writing the escape.
977
- return css === null || !isCssDeclarationValue(css) ? "" : `${cssPropertyName(entry.name)}:${css}`;
978
- }).filter(Boolean).join(";");
979
- return `${selectors}{${declarations}}`;
980
- }).join("");
981
- keyframeRules.set(name, `@keyframes ${name}{${stops}}`);
982
- }
983
- }
984
- for (const child of Object.values(record)) {
985
- if (Array.isArray(child))
986
- child.forEach(visit);
987
- else
988
- visit(child);
989
- }
990
- };
991
- visit(program);
992
- const lookCss = [...rules.values()]
993
- .map((rule) => ({ rule, depth: lookConditionDepth(rule.staticAtoms) }))
994
- // Rank decides, and declaration order only separates rules that share a
995
- // rank. Emission used to follow the Map, so the sheet's byte order — and
996
- // through it the per-module concatenation order the CLI sorts by
997
- // filename — could pick the winner of a tie (LOK-U8, LOK-U10).
998
- .sort((left, right) => left.depth - right.depth || left.rule.sequence - right.rule.sequence)
999
- .map(({ rule, depth }) => {
1000
- const hookAtoms = rule.staticAtoms.filter((atom) => atom.kind === "hook");
1001
- const mediaAtoms = rule.staticAtoms.filter((atom) => atom.kind === "media" || atom.kind === "scheme" || atom.kind === "motion");
1002
- const base = `[data-velar-look~=${JSON.stringify(rule.token)}]${"[data-velar-look]".repeat(depth)}`;
1003
- const selectors = lookSelectors(base, hookAtoms, rule.target);
1004
- const css = `${selectors.join(",")}{${lookDeclaration(rule.token, rule.property)}}`;
1005
- const query = mediaAtoms.map(lookMediaQuery).join(" and ");
1006
- return query ? `@media ${query}{${css}}` : css;
1007
- });
1008
- const before = [];
1009
- const after = [];
1010
- for (const statement of program.body) {
1011
- if (!isWebStatement(statement) || statement.kind !== "ExtensionStatement:web:unsafe-css")
1012
- continue;
1013
- const source = statement.source.kind === "inline"
1014
- ? statement.source.css
1015
- : this.resourceContents.get(statement.source.path) ?? "";
1016
- (statement.placement === "after" ? after : before).push(source.trim());
1017
- }
1018
- this.cssSegments = {
1019
- before: before.filter(Boolean).join("\n\n"),
1020
- controlled: [...keyframeRules.values(), ...lookCss].filter(Boolean).join("\n\n"),
1021
- after: after.filter(Boolean).join("\n\n"),
343
+ emitHost() {
344
+ const emitter = this;
345
+ return {
346
+ get currentJsxNamespace() { return emitter.currentJsxNamespace; },
347
+ set currentJsxNamespace(value) { emitter.currentJsxNamespace = value; },
348
+ get currentScope() { return emitter.currentScope; },
349
+ set currentScope(value) { emitter.currentScope = value; },
350
+ get cssOutput() { return emitter.cssOutput; },
351
+ set cssOutput(value) { emitter.cssOutput = value; },
352
+ get cssSegments() { return emitter.cssSegments; },
353
+ set cssSegments(value) { emitter.cssSegments = value; },
354
+ get hints() { return emitter.hints; },
355
+ get importedLookStaticValues() { return emitter.importedLookStaticValues; },
356
+ get jsxId() { return emitter.jsxId; },
357
+ set jsxId(value) { emitter.jsxId = value; },
358
+ get keyframeNames() { return emitter.keyframeNames; },
359
+ get lookKeywordProperties() { return emitter.lookKeywordProperties; },
360
+ get lookStaticValues() { return emitter.lookStaticValues; },
361
+ set lookStaticValues(value) { emitter.lookStaticValues = value; },
362
+ get moduleEvaluation() { return emitter.moduleEvaluation; },
363
+ get needsFileTypeHelper() { return emitter.needsFileTypeHelper; },
364
+ set needsFileTypeHelper(value) { emitter.needsFileTypeHelper = value; },
365
+ get needsLookArithmeticRuntime() { return emitter.needsLookArithmeticRuntime; },
366
+ get resourceContents() { return emitter.resourceContents; },
367
+ get webOutput() { return emitter.webOutput; },
368
+ baseDetachedTaskHelpers: () => super.detachedTaskHelpers(),
369
+ baseIsCheck: (type, value) => super.emitIsCheck(type, value),
370
+ baseReactiveBridgeHelpers: (needsJavaScriptCallBoundary, needsCollections, usedIdentifiers) => super.reactiveBridgeHelpers(needsJavaScriptCallBoundary, needsCollections, usedIdentifiers),
371
+ baseTypeCheck: (type, value, state) => super.emitTypeCheck(type, value, state),
372
+ blockAlwaysReturns: (statements) => emitter.blockAlwaysReturns(statements),
373
+ emitCondition: (expression) => emitter.emitCondition(expression),
374
+ emitMappedExpression: (expression) => emitter.emitMappedExpression(expression),
375
+ emitMappedJavaScript: (sourceSpan, render) => emitter.emitMappedJavaScript(sourceSpan, render),
376
+ emitMappedStatement: (statement, depth) => emitter.emitMappedStatement(statement, depth),
377
+ emitObjectKey: (name) => emitter.emitObjectKey(name),
378
+ emitParameter: (name, defaultValue, rest) => emitter.emitParameter(name, defaultValue, rest),
379
+ emitStatement: (statement, depth) => emitter.emitStatement(statement, depth),
380
+ emitStatementLines: (statements, depth) => emitter.emitStatementLines(statements, depth),
381
+ requireRuntimeModule: (source) => emitter.requireRuntimeModule(source),
382
+ usesSharedRuntimeModules: () => emitter.usesSharedRuntimeModules(),
1022
383
  };
1023
- this.cssOutput = [this.cssSegments.before, this.cssSegments.controlled, this.cssSegments.after].filter(Boolean).join("\n\n");
1024
- if (this.cssOutput)
1025
- this.cssOutput += "\n";
1026
- }
1027
- }
1028
- function normalizeJsxText(value) {
1029
- const normalized = value.replace(/\s+/gu, " ");
1030
- if (!value.includes("\n"))
1031
- return normalized;
1032
- return (/^\s*\n/u.test(value) ? normalized.trimStart() : normalized).replace(/\n\s*$/u.test(value) ? /\s+$/u : /$^/u, "");
1033
- }
1034
- function hasMeaningfulChildren(children) {
1035
- return children.some((child) => child.kind !== "JSXText" || child.value.trim().length > 0);
1036
- }
1037
- // The keyed-children fast path is syntactic: an interpolation leaf must be
1038
- // exactly `source.map(single-parameter arrow returning JSX)`, keyed when the
1039
- // arrow's root element carries a `key` attribute. The analyzer mirrors this
1040
- // recognizer through dynamicChildLeaves, so anything the emitter demotes to a
1041
- // rebuild-all dynamic region is diagnosed rather than silently forfeited.
1042
- export function jsxKeyedList(expression) {
1043
- if (expression.kind !== "CallExpression" || expression.callee.kind !== "MemberExpression" || expression.callee.property !== "map")
1044
- return null;
1045
- const callback = expression.arguments[0];
1046
- if (!callback || callback.kind !== "ArrowFunctionExpression" || callback.asynchronous || callback.parameters.length !== 1 || callback.body.kind !== "ExtensionExpression:web:jsx")
1047
- return null;
1048
- const arrow = callback;
1049
- const key = arrow.body.attributes.find((attribute) => attribute.name === "key") ?? null;
1050
- return { source: expression.callee.object, arrow, key };
1051
- }
1052
- /**
1053
- * F1: the analyzer's verdict that an interpolation's checked type renders as
1054
- * exactly one text node. The emitter cannot re-derive it — the checked type is
1055
- * gone by lowering time — so the analyzer stamps the child expression's span
1056
- * and the emitter reads it back through the extension-hint channel that
1057
- * `LOOK_ARITHMETIC_HINT` already uses.
1058
- */
1059
- export const JSX_SCALAR_TEXT_HINT = "@velarscript/web:jsx-scalar-text";
1060
- /**
1061
- * The one thing a scalar interpolation must not contain. `__velarText` owns no
1062
- * child scope, so a nested element inside the expression — legal where a
1063
- * function takes a `WebNode` and answers text — would have nothing to register
1064
- * its observers and cleanups against. The type says one text node; this says
1065
- * nothing was built to make it.
1066
- */
1067
- function containsJsxExpression(value) {
1068
- if (!value || typeof value !== "object")
1069
- return false;
1070
- const record = value;
1071
- if (record.kind === "ExtensionExpression:web:jsx")
1072
- return true;
1073
- return Object.values(record).some((child) => Array.isArray(child) ? child.some(containsJsxExpression) : containsJsxExpression(child));
1074
- }
1075
- // Flattens an interpolation into render leaves. A conditional contributes its
1076
- // branch leaves, each remembering the chain of branch conditions that keeps it
1077
- // active, so an empty-state ternary around a keyed list still reaches the
1078
- // keyed fast path instead of demoting every child to rebuild-all updates.
1079
- export function dynamicChildLeaves(expression, guards = []) {
1080
- const list = jsxKeyedList(expression);
1081
- if (list)
1082
- return [{ expression, list, guards }];
1083
- if (expression.kind === "ConditionalExpression") {
1084
- return [
1085
- ...dynamicChildLeaves(expression.thenValue, [...guards, { condition: expression.condition, thenBranch: true }]),
1086
- ...dynamicChildLeaves(expression.elseValue, [...guards, { condition: expression.condition, thenBranch: false }]),
1087
- ];
1088
- }
1089
- return [{ expression, list: null, guards }];
1090
- }
1091
- const EMPTY_LOOK_TERM = Object.freeze({ staticAtoms: [], runtimeAtoms: [] });
1092
- const LOOK_CONDITION_TERM_LIMIT = 32;
1093
- function lookConditionTerms(expression, negated = false, staticValues = new Map()) {
1094
- if (expression.kind === "UnaryExpression" && expression.operator === "not")
1095
- return lookConditionTerms(expression.operand, !negated, staticValues);
1096
- if (expression.kind === "BinaryExpression" && (expression.operator === "and" || expression.operator === "or")) {
1097
- const conjunction = (expression.operator === "and") !== negated;
1098
- const left = lookConditionTerms(expression.left, negated, staticValues);
1099
- const right = lookConditionTerms(expression.right, negated, staticValues);
1100
- return conjunction ? combineLookTerms(left, right) : [...left, ...right].slice(0, LOOK_CONDITION_TERM_LIMIT);
1101
- }
1102
- if (isWebExpression(expression) && expression.kind === "ExtensionExpression:web:look-hook") {
1103
- return [{ staticAtoms: [{ kind: "hook", name: expression.name, negated }], runtimeAtoms: [] }];
1104
- }
1105
- const media = viewportAtom(expression, negated, staticValues) ?? schemeAtom(expression, negated);
1106
- if (media)
1107
- return [{ staticAtoms: [media], runtimeAtoms: [] }];
1108
- return [{ staticAtoms: [], runtimeAtoms: [{ expression, negated }] }];
1109
- }
1110
- // A breakpoint is complementary the way the schemes and the motion preference
1111
- // are: `not (width <= X)` is `width > X`, one condition with one media query.
1112
- // The atom therefore folds the negation into its operator at construction, so
1113
- // the two spellings reach `lookToken` as the same token instead of as two
1114
- // rules that tie on specificity and are separated by source order.
1115
- const LOOK_NEGATED_MEDIA_OPERATORS = new Map([
1116
- ["<", ">="], ["<=", ">"], [">", "<="], [">=", "<"],
1117
- ]);
1118
- function viewportAtom(expression, negated, staticValues) {
1119
- if (expression.kind !== "BinaryExpression" || !["<", "<=", ">", ">="].includes(expression.operator))
1120
- return null;
1121
- if (expression.left.kind !== "MemberExpression" || expression.left.object.kind !== "IdentifierExpression" || expression.left.object.name !== "viewport")
1122
- return null;
1123
- if (expression.left.property !== "width" && expression.left.property !== "height")
1124
- return null;
1125
- const threshold = evaluateLookStaticExpression(expression.right, staticValues);
1126
- if (threshold?.kind !== "unit" || !LOOK_MEDIA_LENGTH_UNITS.has(threshold.unit))
1127
- return null;
1128
- const written = expression.operator;
1129
- return {
1130
- kind: "media",
1131
- name: expression.left.property,
1132
- operator: negated ? LOOK_NEGATED_MEDIA_OPERATORS.get(written) : written,
1133
- value: lookStaticCss(threshold),
1134
- negated: false,
1135
- };
1136
- }
1137
- // 'scheme.dark' / 'scheme.light' lower to prefers-color-scheme media atoms.
1138
- // The two subjects are complementary, so negation flips to the other scheme
1139
- // and the atom itself stays canonical.
1140
- function schemeAtom(expression, negated) {
1141
- if (expression.kind !== "MemberExpression" || expression.object.kind !== "IdentifierExpression")
1142
- return null;
1143
- // LOK-U3: 'motion.reduced' joins the media subjects. prefers-reduced-motion is
1144
- // complementary in the same way the schemes are, so negation names the other
1145
- // side of the query rather than wrapping it.
1146
- if (expression.object.name === "motion") {
1147
- return expression.property === "reduced" ? { kind: "motion", name: negated ? "no-preference" : "reduce", negated: false } : null;
1148
- }
1149
- if (expression.object.name !== "scheme")
1150
- return null;
1151
- if (expression.property !== "dark" && expression.property !== "light")
1152
- return null;
1153
- const scheme = negated ? (expression.property === "dark" ? "light" : "dark") : expression.property;
1154
- return { kind: "scheme", name: scheme, negated: false };
1155
- }
1156
- function combineLookTerms(left, right) {
1157
- const combined = [];
1158
- for (const first of left) {
1159
- for (const second of right) {
1160
- combined.push({
1161
- staticAtoms: [...first.staticAtoms, ...second.staticAtoms],
1162
- runtimeAtoms: [...first.runtimeAtoms, ...second.runtimeAtoms],
1163
- });
1164
- if (combined.length >= LOOK_CONDITION_TERM_LIMIT)
1165
- return combined;
1166
- }
1167
- }
1168
- return combined;
1169
- }
1170
- function lookToken(atoms, target, property) {
1171
- const conditions = atoms.map((atom) => {
1172
- if (atom.kind === "hook")
1173
- return `${atom.negated ? "not-" : ""}${kebab(atom.name)}`;
1174
- if (atom.kind === "scheme")
1175
- return `scheme-${atom.name}`;
1176
- if (atom.kind === "motion")
1177
- return `motion-${atom.name}`;
1178
- return `viewport-${atom.name}-${lookOperatorName(atom.operator)}-${atom.value}`;
1179
- }).sort();
1180
- const prefix = [target ? kebab(target) : "", conditions.length > 0 ? conditions.join("+") : "base"].filter(Boolean).join(":");
1181
- return `${prefix}:${property}`;
1182
- }
1183
- /**
1184
- * How many extra `[data-velar-look]` selectors a rule carries, so that the
1185
- * winner between two Look rules is decided by the conditions they name rather
1186
- * than by their position in the sheet.
1187
- *
1188
- * The bump used to be a single flat `+1` for any non-empty condition set, which
1189
- * made every conditional rule specificity `(0,2,0)`: a state rule tied with a
1190
- * media rule, and a two-condition refinement tied with the one-condition
1191
- * fallback it refines. Ties then fell through to source order, and source order
1192
- * is per-module concatenation order, which the CLI sorts by filename — so the
1193
- * rendered colour could change when a file was renamed (LOK-U8, LOK-U10,
1194
- * LOK-U12).
1195
- *
1196
- * The rank is base < media < state < media+state, and within a rank a rule that
1197
- * names more conditions outranks one that names fewer. The per-rank span is
1198
- * bounded so a pathological condition count cannot cross a rank boundary; rules
1199
- * that saturate it fall back to declaration order, which is stable.
1200
- */
1201
- const LOOK_RANK_SPAN = 3;
1202
- function lookConditionDepth(atoms) {
1203
- if (atoms.length === 0)
1204
- return 0;
1205
- const hooks = atoms.filter((atom) => atom.kind === "hook").length;
1206
- const media = atoms.length - hooks;
1207
- const rank = hooks > 0 ? (media > 0 ? 2 : 1) : 0;
1208
- return rank * LOOK_RANK_SPAN + Math.min(atoms.length, LOOK_RANK_SPAN);
1209
- }
1210
- function lookVariable(token) {
1211
- return `--velar-look-${token.replace(/[^A-Za-z0-9_-]+/gu, "-")}`;
1212
- }
1213
- function lookDeclaration(token, property) {
1214
- const value = `var(${lookVariable(token)})`;
1215
- return `${property}:${value}`;
1216
- }
1217
- function lookOperatorName(operator) {
1218
- return operator === "<" ? "lt" : operator === "<=" ? "lte" : operator === ">" ? "gt" : "gte";
1219
- }
1220
- function lookMediaQuery(atom) {
1221
- if (atom.kind === "scheme")
1222
- return `(prefers-color-scheme: ${atom.name})`;
1223
- if (atom.kind === "motion")
1224
- return `(prefers-reduced-motion: ${atom.name})`;
1225
- return `(${atom.name} ${atom.operator} ${atom.value})`;
1226
- }
1227
- function lookSelectors(base, atoms, target) {
1228
- let selectors = [base];
1229
- for (const atom of atoms) {
1230
- const states = lookHookSelectors(atom.name);
1231
- if (atom.negated) {
1232
- const condition = states.map((state) => `:not(${state})`).join("");
1233
- selectors = selectors.map((selector) => `${selector}:where(${condition})`);
1234
- }
1235
- else {
1236
- selectors = selectors.flatMap((selector) => states.map((state) => `${selector}:where(${state})`));
1237
- }
1238
384
  }
1239
- const suffix = target ? LOOK_TARGET_SELECTORS.get(target) ?? `::${kebab(target)}` : "";
1240
- return selectors.map((selector) => `${selector}${suffix}`);
1241
- }
1242
- function lookHookSelectors(name) {
1243
- if (name === "focusVisible")
1244
- return [":focus-visible"];
1245
- if (name === "current")
1246
- return ["[aria-current=\"page\"]"];
1247
- if (name === "disabled")
1248
- return [":disabled", "[aria-disabled=\"true\"]"];
1249
- if (name === "checked")
1250
- return [":checked", "[aria-checked=\"true\"]"];
1251
- if (name === "invalid")
1252
- return [":invalid", "[aria-invalid=\"true\"]"];
1253
- if (name === "open")
1254
- return [":open", "[open]", "[aria-expanded=\"true\"]"];
1255
- return [`:${kebab(name)}`];
1256
- }
1257
- const LOOK_TARGET_SELECTORS = new Map([
1258
- ["before", "::before"], ["after", "::after"], ["backdrop", "::backdrop"], ["placeholder", "::placeholder"], ["selection", "::selection"],
1259
- ["marker", "::marker"], ["fileSelectorButton", "::file-selector-button"],
1260
- ]);
1261
- function kebab(value) {
1262
- return value.replace(/[A-Z]/gu, (character) => `-${character.toLowerCase()}`);
1263
- }
1264
- function visitLookExpressions(entries, visit) {
1265
- for (const entry of entries) {
1266
- if (entry.kind === "LookProperty" || entry.kind === "LookSpread")
1267
- visit(entry.value);
1268
- else if (entry.kind === "LookIf") {
1269
- visit(entry.condition);
1270
- visitLookExpressions(entry.thenEntries, visit);
1271
- visitLookExpressions(entry.elseEntries, visit);
1272
- }
1273
- else
1274
- visitLookExpressions(entry.entries, visit);
1275
- }
1276
- }
1277
- function containsUnitLiteral(value) {
1278
- if (!value || typeof value !== "object")
1279
- return false;
1280
- const record = value;
1281
- if (record.kind === "ExtensionExpression:web:unit")
1282
- return true;
1283
- for (const child of Object.values(record)) {
1284
- if (Array.isArray(child)) {
1285
- if (child.some(containsUnitLiteral))
1286
- return true;
1287
- }
1288
- else if (containsUnitLiteral(child))
1289
- return true;
1290
- }
1291
- return false;
1292
- }
1293
- function containsWebSyntax(value) {
1294
- if (!value || typeof value !== "object")
1295
- return false;
1296
- const record = value;
1297
- if (record.kind === "ExtensionStatement:web:component" || record.kind === "ExtensionStatement:web:expose" || record.kind === "ExtensionStatement:web:unsafe-css" || record.kind === "ExtensionExpression:web:look" || record.kind === "ExtensionExpression:web:keyframes" || record.kind === "ExtensionExpression:web:jsx"
1298
- || record.kind === "ExtensionStatement:web:state" || record.kind === "ExtensionStatement:web:computed" || record.kind === "ExtensionStatement:web:resource" || record.kind === "ExtensionStatement:web:action" || record.kind === "ExtensionStatement:web:watch")
1299
- return true;
1300
- if (record.kind === "IdentifierExpression" && (record.name === "mount" || record.name === "tick"))
1301
- return true;
1302
- return Object.values(record).some((child) => Array.isArray(child) ? child.some(containsWebSyntax) : containsWebSyntax(child));
1303
- }
1304
- /**
1305
- * The runtime an emitted Web program carries inside itself: the foundation it
1306
- * installs, the CSS string serializer, the closed keyword sets of the Look
1307
- * properties *this* module styles, and the runtime body. Only the keyword table
1308
- * differs per compilation, which is why it is the one hole
1309
- * `runtime/manifest.json` records as an assembly (LOK-U13 keeps the serializer
1310
- * the one css-string.ts publishes rather than a second spelling of it).
1311
- */
1312
- function webRuntime(foundation, lookKeywords) {
1313
- return `${foundation}\n${CSS_STRING_RUNTIME_BODY}${lookKeywords}\n${WEB_RUNTIME_BODY}`;
1314
385
  }
1315
386
  //# sourceMappingURL=emitter.js.map