@gyral/core 0.3.0 → 0.3.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 (381) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/NOTICE +19 -0
  3. package/README.md +30 -5
  4. package/dist/call.d.ts +32 -0
  5. package/dist/call.js +63 -0
  6. package/dist/call.js.map +1 -0
  7. package/dist/children.d.ts +25 -3
  8. package/dist/children.js +18 -1
  9. package/dist/children.js.map +1 -1
  10. package/dist/cli/gyral-types.d.ts +2 -0
  11. package/dist/cli/gyral-types.js +23 -0
  12. package/dist/cli/gyral-types.js.map +1 -0
  13. package/dist/command.d.ts +54 -12
  14. package/dist/command.js +25 -11
  15. package/dist/command.js.map +1 -1
  16. package/dist/compiler/ast.d.ts +2 -0
  17. package/dist/compiler/ast.js +5 -1
  18. package/dist/compiler/ast.js.map +1 -1
  19. package/dist/compiler/compile.d.ts +5 -2
  20. package/dist/compiler/compile.js +36 -17
  21. package/dist/compiler/compile.js.map +1 -1
  22. package/dist/compiler/component-entries.d.ts +7 -0
  23. package/dist/compiler/component-entries.js +42 -0
  24. package/dist/compiler/component-entries.js.map +1 -0
  25. package/dist/compiler/components.d.ts +4 -0
  26. package/dist/compiler/components.js +182 -0
  27. package/dist/compiler/components.js.map +1 -0
  28. package/dist/compiler/facts.d.ts +31 -0
  29. package/dist/compiler/facts.js +285 -0
  30. package/dist/compiler/facts.js.map +1 -0
  31. package/dist/compiler/features.d.ts +34 -0
  32. package/dist/compiler/features.js +158 -0
  33. package/dist/compiler/features.js.map +1 -0
  34. package/dist/compiler/hooks.d.ts +4 -0
  35. package/dist/compiler/hooks.js +144 -89
  36. package/dist/compiler/hooks.js.map +1 -1
  37. package/dist/compiler/loader-source.d.ts +14 -0
  38. package/dist/compiler/loader-source.js +86 -0
  39. package/dist/compiler/loader-source.js.map +1 -0
  40. package/dist/compiler/locate.d.ts +14 -0
  41. package/dist/compiler/locate.js +78 -0
  42. package/dist/compiler/locate.js.map +1 -0
  43. package/dist/compiler/parse5-check.d.ts +1 -1
  44. package/dist/compiler/parse5-check.js +8 -3
  45. package/dist/compiler/parse5-check.js.map +1 -1
  46. package/dist/compiler/prop-schemas.d.ts +4 -0
  47. package/dist/compiler/prop-schemas.js +108 -0
  48. package/dist/compiler/prop-schemas.js.map +1 -0
  49. package/dist/compiler/scan.d.ts +13 -3
  50. package/dist/compiler/scan.js +21 -13
  51. package/dist/compiler/scan.js.map +1 -1
  52. package/dist/compiler/scope.d.ts +8 -0
  53. package/dist/compiler/scope.js +116 -0
  54. package/dist/compiler/scope.js.map +1 -0
  55. package/dist/compiler/tag-map.d.ts +41 -0
  56. package/dist/compiler/tag-map.js +126 -0
  57. package/dist/compiler/tag-map.js.map +1 -0
  58. package/dist/components-ready.d.ts +7 -0
  59. package/dist/components-ready.js +19 -0
  60. package/dist/components-ready.js.map +1 -0
  61. package/dist/define.d.ts +13 -4
  62. package/dist/define.js +8 -12
  63. package/dist/define.js.map +1 -1
  64. package/dist/devtools-events.d.ts +8 -0
  65. package/dist/devtools-events.js.map +1 -1
  66. package/dist/devtools-off.d.ts +1 -0
  67. package/dist/devtools-off.js +1 -0
  68. package/dist/devtools-off.js.map +1 -1
  69. package/dist/devtools.d.ts +3 -0
  70. package/dist/devtools.js +14 -0
  71. package/dist/devtools.js.map +1 -1
  72. package/dist/drivers-scope.js.map +1 -1
  73. package/dist/element-internals.d.ts +1 -0
  74. package/dist/element-internals.js +11 -0
  75. package/dist/element-internals.js.map +1 -0
  76. package/dist/element-types.d.ts +6 -2
  77. package/dist/element-types.js.map +1 -1
  78. package/dist/element.js +80 -27
  79. package/dist/element.js.map +1 -1
  80. package/dist/error-view.d.ts +10 -0
  81. package/dist/error-view.js +30 -0
  82. package/dist/error-view.js.map +1 -0
  83. package/dist/errors.d.ts +21 -0
  84. package/dist/errors.js +47 -0
  85. package/dist/errors.js.map +1 -0
  86. package/dist/errors.json +289 -0
  87. package/dist/eslint/imports.d.ts +2 -0
  88. package/dist/eslint/imports.js +2 -2
  89. package/dist/eslint/imports.js.map +1 -1
  90. package/dist/eslint/index.d.ts +2 -1
  91. package/dist/eslint/index.js +11 -3
  92. package/dist/eslint/index.js.map +1 -1
  93. package/dist/eslint/template-rule.d.ts +1 -0
  94. package/dist/eslint/template-rule.js +15 -5
  95. package/dist/eslint/template-rule.js.map +1 -1
  96. package/dist/eslint/unused-intent-rule.d.ts +2 -0
  97. package/dist/eslint/unused-intent-rule.js +186 -0
  98. package/dist/eslint/unused-intent-rule.js.map +1 -0
  99. package/dist/features.d.ts +2 -2
  100. package/dist/features.js.map +1 -1
  101. package/dist/focus.d.ts +6 -0
  102. package/dist/focus.js +32 -2
  103. package/dist/focus.js.map +1 -1
  104. package/dist/form-associated.d.ts +46 -0
  105. package/dist/form-associated.js +77 -0
  106. package/dist/form-associated.js.map +1 -0
  107. package/dist/forms.d.ts +42 -30
  108. package/dist/forms.js +85 -41
  109. package/dist/forms.js.map +1 -1
  110. package/dist/frame-lane.d.ts +11 -0
  111. package/dist/frame-lane.js +28 -0
  112. package/dist/frame-lane.js.map +1 -0
  113. package/dist/head.d.ts +61 -0
  114. package/dist/head.js +85 -0
  115. package/dist/head.js.map +1 -0
  116. package/dist/host-model.d.ts +34 -5
  117. package/dist/host-model.js +146 -23
  118. package/dist/host-model.js.map +1 -1
  119. package/dist/hydration-client.js +2 -2
  120. package/dist/hydration-client.js.map +1 -1
  121. package/dist/hydration-loader.d.ts +13 -0
  122. package/dist/hydration-loader.js +58 -0
  123. package/dist/hydration-loader.js.map +1 -0
  124. package/dist/hydration-off.d.ts +8 -0
  125. package/dist/hydration-off.js +25 -0
  126. package/dist/hydration-off.js.map +1 -0
  127. package/dist/hydration.d.ts +0 -12
  128. package/dist/hydration.js +3 -52
  129. package/dist/hydration.js.map +1 -1
  130. package/dist/index.d.ts +20 -24
  131. package/dist/index.js +10 -19
  132. package/dist/index.js.map +1 -1
  133. package/dist/indexeddb-types.d.ts +97 -0
  134. package/dist/indexeddb-types.js +2 -0
  135. package/dist/indexeddb-types.js.map +1 -0
  136. package/dist/indexeddb.d.ts +5 -0
  137. package/dist/indexeddb.js +118 -0
  138. package/dist/indexeddb.js.map +1 -0
  139. package/dist/intent.d.ts +41 -19
  140. package/dist/intent.js +144 -106
  141. package/dist/intent.js.map +1 -1
  142. package/dist/internal/indexeddb-open.d.ts +8 -0
  143. package/dist/internal/indexeddb-open.js +96 -0
  144. package/dist/internal/indexeddb-open.js.map +1 -0
  145. package/dist/internal/indexeddb-transaction.d.ts +4 -0
  146. package/dist/internal/indexeddb-transaction.js +134 -0
  147. package/dist/internal/indexeddb-transaction.js.map +1 -0
  148. package/dist/internal/interpreter.d.ts +12 -4
  149. package/dist/internal/interpreter.js +36 -48
  150. package/dist/internal/interpreter.js.map +1 -1
  151. package/dist/internal/token.d.ts +1 -0
  152. package/dist/internal/token.js +7 -0
  153. package/dist/internal/token.js.map +1 -0
  154. package/dist/internal.d.ts +20 -0
  155. package/dist/internal.js +22 -0
  156. package/dist/internal.js.map +1 -0
  157. package/dist/invoker-fallback-used.d.ts +4 -0
  158. package/dist/invoker-fallback-used.js +10 -0
  159. package/dist/invoker-fallback-used.js.map +1 -0
  160. package/dist/invoker-fallback.d.ts +4 -0
  161. package/dist/invoker-fallback.js +15 -0
  162. package/dist/invoker-fallback.js.map +1 -0
  163. package/dist/light-dom.d.ts +1 -1
  164. package/dist/light-dom.js.map +1 -1
  165. package/dist/prop.d.ts +30 -7
  166. package/dist/prop.js +19 -0
  167. package/dist/prop.js.map +1 -1
  168. package/dist/props.d.ts +8 -3
  169. package/dist/props.js +22 -15
  170. package/dist/props.js.map +1 -1
  171. package/dist/retry.d.ts +15 -0
  172. package/dist/retry.js +48 -0
  173. package/dist/retry.js.map +1 -0
  174. package/dist/scheduler.d.ts +7 -3
  175. package/dist/scheduler.js +38 -56
  176. package/dist/scheduler.js.map +1 -1
  177. package/dist/script-json.d.ts +2 -0
  178. package/dist/script-json.js +13 -0
  179. package/dist/script-json.js.map +1 -0
  180. package/dist/server-component.d.ts +1 -1
  181. package/dist/server-component.js +45 -14
  182. package/dist/server-component.js.map +1 -1
  183. package/dist/server.d.ts +8 -2
  184. package/dist/server.js +11 -2
  185. package/dist/server.js.map +1 -1
  186. package/dist/settled.d.ts +4 -3
  187. package/dist/settled.js +48 -26
  188. package/dist/settled.js.map +1 -1
  189. package/dist/spec-features-used.d.ts +21 -0
  190. package/dist/spec-features-used.js +50 -0
  191. package/dist/spec-features-used.js.map +1 -0
  192. package/dist/spec-features.d.ts +28 -0
  193. package/dist/spec-features.js +42 -0
  194. package/dist/spec-features.js.map +1 -0
  195. package/dist/states.d.ts +3 -5
  196. package/dist/states.js +22 -8
  197. package/dist/states.js.map +1 -1
  198. package/dist/storage.d.ts +69 -0
  199. package/dist/storage.js +158 -0
  200. package/dist/storage.js.map +1 -0
  201. package/dist/store-binding.js +2 -2
  202. package/dist/store-binding.js.map +1 -1
  203. package/dist/store-scope.d.ts +2 -4
  204. package/dist/store-scope.js +6 -16
  205. package/dist/store-scope.js.map +1 -1
  206. package/dist/store.js +36 -8
  207. package/dist/store.js.map +1 -1
  208. package/dist/subscription.d.ts +35 -0
  209. package/dist/subscription.js +74 -0
  210. package/dist/subscription.js.map +1 -0
  211. package/dist/subscriptions.d.ts +26 -0
  212. package/dist/subscriptions.js +98 -0
  213. package/dist/subscriptions.js.map +1 -0
  214. package/dist/transitions.d.ts +4 -5
  215. package/dist/transitions.js +10 -4
  216. package/dist/transitions.js.map +1 -1
  217. package/dist/types.d.ts +124 -27
  218. package/dist/types.js.map +1 -1
  219. package/dist/use-dialogs.d.ts +2 -0
  220. package/dist/use-dialogs.js +9 -0
  221. package/dist/use-dialogs.js.map +1 -0
  222. package/dist/use-disposal.d.ts +2 -0
  223. package/dist/use-disposal.js +9 -0
  224. package/dist/use-disposal.js.map +1 -0
  225. package/dist/use-error-view.d.ts +2 -0
  226. package/dist/use-error-view.js +9 -0
  227. package/dist/use-error-view.js.map +1 -0
  228. package/dist/use-errored.d.ts +2 -0
  229. package/dist/use-errored.js +9 -0
  230. package/dist/use-errored.js.map +1 -0
  231. package/dist/use-form-associated.d.ts +2 -0
  232. package/dist/use-form-associated.js +7 -0
  233. package/dist/use-form-associated.js.map +1 -0
  234. package/dist/use-frame-lane.d.ts +2 -0
  235. package/dist/use-frame-lane.js +10 -0
  236. package/dist/use-frame-lane.js.map +1 -0
  237. package/dist/use-invokers.d.ts +2 -0
  238. package/dist/use-invokers.js +10 -0
  239. package/dist/use-invokers.js.map +1 -0
  240. package/dist/use-states.d.ts +2 -0
  241. package/dist/use-states.js +10 -0
  242. package/dist/use-states.js.map +1 -0
  243. package/dist/use-subscriptions.d.ts +2 -0
  244. package/dist/use-subscriptions.js +10 -0
  245. package/dist/use-subscriptions.js.map +1 -0
  246. package/dist/use-transitions.d.ts +2 -0
  247. package/dist/use-transitions.js +10 -0
  248. package/dist/use-transitions.js.map +1 -0
  249. package/dist/view/attributes.d.ts +5 -0
  250. package/dist/view/attributes.js +5 -0
  251. package/dist/view/attributes.js.map +1 -1
  252. package/dist/view/compiled.d.ts +1 -1
  253. package/dist/view/compiled.js +1 -1
  254. package/dist/view/compiled.js.map +1 -1
  255. package/dist/view/index.d.ts +9 -4
  256. package/dist/view/index.js +9 -3
  257. package/dist/view/index.js.map +1 -1
  258. package/dist/view/loc.d.ts +9 -0
  259. package/dist/view/loc.js +50 -0
  260. package/dist/view/loc.js.map +1 -0
  261. package/dist/view/message.d.ts +17 -0
  262. package/dist/view/message.js +40 -0
  263. package/dist/view/message.js.map +1 -0
  264. package/dist/view/messages.d.ts +43 -0
  265. package/dist/view/messages.js +84 -0
  266. package/dist/view/messages.js.map +1 -0
  267. package/dist/view/normalize/check.d.ts +5 -2
  268. package/dist/view/normalize/check.js +6 -3
  269. package/dist/view/normalize/check.js.map +1 -1
  270. package/dist/view/normalize/emit.d.ts +2 -0
  271. package/dist/view/normalize/emit.js +40 -11
  272. package/dist/view/normalize/emit.js.map +1 -1
  273. package/dist/view/normalize/errors.js +1 -1
  274. package/dist/view/normalize/errors.js.map +1 -1
  275. package/dist/view/normalize/id.d.ts +5 -2
  276. package/dist/view/normalize/id.js +9 -2
  277. package/dist/view/normalize/id.js.map +1 -1
  278. package/dist/view/normalize/normalize.d.ts +7 -4
  279. package/dist/view/normalize/normalize.js +15 -9
  280. package/dist/view/normalize/normalize.js.map +1 -1
  281. package/dist/view/normalize/rules.d.ts +9 -0
  282. package/dist/view/normalize/rules.js +35 -5
  283. package/dist/view/normalize/rules.js.map +1 -1
  284. package/dist/view/normalize/svg.d.ts +14 -0
  285. package/dist/view/normalize/svg.js +40 -0
  286. package/dist/view/normalize/svg.js.map +1 -0
  287. package/dist/view/normalize/tokens.d.ts +5 -1
  288. package/dist/view/normalize/tokens.js.map +1 -1
  289. package/dist/view/normalize/tree.d.ts +8 -2
  290. package/dist/view/normalize/tree.js +58 -13
  291. package/dist/view/normalize/tree.js.map +1 -1
  292. package/dist/view/normalize/types.d.ts +24 -4
  293. package/dist/view/normalize/types.js +4 -1
  294. package/dist/view/normalize/types.js.map +1 -1
  295. package/dist/view/normalize/whitespace.js +4 -3
  296. package/dist/view/normalize/whitespace.js.map +1 -1
  297. package/dist/view/prepare-stub.js +2 -2
  298. package/dist/view/prepare-stub.js.map +1 -1
  299. package/dist/view/prepare.d.ts +5 -2
  300. package/dist/view/prepare.js +9 -3
  301. package/dist/view/prepare.js.map +1 -1
  302. package/dist/view/registry.d.ts +15 -0
  303. package/dist/view/registry.js +10 -2
  304. package/dist/view/registry.js.map +1 -1
  305. package/dist/view/render/adopt-attr.js +7 -1
  306. package/dist/view/render/adopt-attr.js.map +1 -1
  307. package/dist/view/render/adopt.js +21 -4
  308. package/dist/view/render/adopt.js.map +1 -1
  309. package/dist/view/render/attr-parts.d.ts +12 -1
  310. package/dist/view/render/attr-parts.js +38 -5
  311. package/dist/view/render/attr-parts.js.map +1 -1
  312. package/dist/view/render/child-part.js +5 -2
  313. package/dist/view/render/child-part.js.map +1 -1
  314. package/dist/view/render/dispose.d.ts +3 -0
  315. package/dist/view/render/dispose.js +76 -0
  316. package/dist/view/render/dispose.js.map +1 -0
  317. package/dist/view/render/hook-part.d.ts +3 -1
  318. package/dist/view/render/hook-part.js +21 -5
  319. package/dist/view/render/hook-part.js.map +1 -1
  320. package/dist/view/render/hook-run.d.ts +2 -0
  321. package/dist/view/render/hook-run.js +72 -0
  322. package/dist/view/render/hook-run.js.map +1 -0
  323. package/dist/view/render/hooks.d.ts +73 -5
  324. package/dist/view/render/hooks.js +79 -17
  325. package/dist/view/render/hooks.js.map +1 -1
  326. package/dist/view/render/hydrate.js +2 -2
  327. package/dist/view/render/hydrate.js.map +1 -1
  328. package/dist/view/render/keyed.d.ts +6 -0
  329. package/dist/view/render/keyed.js +15 -0
  330. package/dist/view/render/keyed.js.map +1 -0
  331. package/dist/view/render/mismatch.js +5 -3
  332. package/dist/view/render/mismatch.js.map +1 -1
  333. package/dist/view/render/modal.d.ts +3 -0
  334. package/dist/view/render/modal.js +39 -0
  335. package/dist/view/render/modal.js.map +1 -0
  336. package/dist/view/render/raw.d.ts +4 -1
  337. package/dist/view/render/raw.js +6 -2
  338. package/dist/view/render/raw.js.map +1 -1
  339. package/dist/view/render/render.d.ts +4 -1
  340. package/dist/view/render/render.js +17 -12
  341. package/dist/view/render/render.js.map +1 -1
  342. package/dist/view/render/toggles.d.ts +6 -0
  343. package/dist/view/render/toggles.js +6 -0
  344. package/dist/view/render/toggles.js.map +1 -0
  345. package/dist/view/render/warn.d.ts +14 -0
  346. package/dist/view/render/warn.js +45 -0
  347. package/dist/view/render/warn.js.map +1 -1
  348. package/dist/view/server/component.d.ts +6 -3
  349. package/dist/view/server/component.js +29 -7
  350. package/dist/view/server/component.js.map +1 -1
  351. package/dist/view/server/index.d.ts +20 -0
  352. package/dist/view/server/index.js +12 -4
  353. package/dist/view/server/index.js.map +1 -1
  354. package/dist/view/server/tags.d.ts +13 -2
  355. package/dist/view/server/tags.js +13 -2
  356. package/dist/view/server/tags.js.map +1 -1
  357. package/dist/view/server/values.d.ts +2 -0
  358. package/dist/view/server/values.js +8 -0
  359. package/dist/view/server/values.js.map +1 -1
  360. package/dist/view/server/writer.d.ts +9 -4
  361. package/dist/view/server/writer.js +33 -18
  362. package/dist/view/server/writer.js.map +1 -1
  363. package/dist/view/template-element.d.ts +7 -0
  364. package/dist/view/template-element.js +25 -5
  365. package/dist/view/template-element.js.map +1 -1
  366. package/dist/view/template.d.ts +10 -2
  367. package/dist/view/template.js +62 -8
  368. package/dist/view/template.js.map +1 -1
  369. package/dist/view/trusted-html.d.ts +6 -0
  370. package/dist/view/trusted-html.js +34 -0
  371. package/dist/view/trusted-html.js.map +1 -0
  372. package/dist/vite.d.ts +38 -31
  373. package/dist/vite.js +198 -31
  374. package/dist/vite.js.map +1 -1
  375. package/package.json +34 -3
  376. package/dist/hooks/labelled-by.d.ts +0 -13
  377. package/dist/hooks/labelled-by.js +0 -51
  378. package/dist/hooks/labelled-by.js.map +0 -1
  379. package/dist/random.d.ts +0 -13
  380. package/dist/random.js +0 -19
  381. package/dist/random.js.map +0 -1
@@ -0,0 +1,285 @@
1
+ // What one module may use, for the build-time feature scan (features.ts, view/05-element.md
2
+ // "Features register themselves"), read from its AST (Rolldown's `this.parse`, the author's
3
+ // source: both plugins that scan run before other transforms). Comments are not in the AST,
4
+ // and type-only code is skipped (ast.ts `children`), so neither counts. What does:
5
+ // - spec fields (`viewTransition`, `renderOnFrame`, `states`, `subscriptions`) and the hook
6
+ // spec key `dispose`: the name as an identifier
7
+ // anywhere in runtime code (a property key, `spec.states = …`, `{ states }`, a binding a
8
+ // namespace import may spread, `export { f as states }`), or a string that is exactly the
9
+ // name (`Object.defineProperty(spec, 'states', …)`). A word inside a longer string doesn't;
10
+ // - command intents: a string or template whose markup has a `data-intent-command` attribute,
11
+ // `data-intent-on="command"` or a bound `data-intent-on`, or a string that is exactly "command" (`events: ['command']`, a
12
+ // `setAttribute`);
13
+ // - dialog and popover bindings: a template whose markup binds `?modal=` or `?popover-open=`;
14
+ // - `raw` (its markup is read at run time, so it may hold `data-intent-on="command"`): the
15
+ // module lists the specifiers through which it may reach a `raw` export, and features.ts
16
+ // counts it when one of them is a module of `@gyral/core`. Through: a named import of `raw` (any
17
+ // alias) that the module references; a namespace import read other than as `ns.<name>`
18
+ // (`ns.raw`, `ns[key]`, the namespace passed on); a re-export of `raw`, `export *`; a
19
+ // dynamic `import()`. A module that re-exports core's `raw` counts itself, so `raw`
20
+ // imported through a re-exporting module (the app's, a design system's) is still seen there.
21
+ import { children, nodeAt, nodesAt } from './ast.js';
22
+ /** The spec field each spec-field feature is reached through (04, 05). */
23
+ export const FIELDS = {
24
+ transitions: 'viewTransition',
25
+ frame: 'renderOnFrame',
26
+ states: 'states',
27
+ forms: 'formAssociated',
28
+ subscriptions: 'subscriptions',
29
+ disposal: 'dispose',
30
+ errorView: 'error',
31
+ errored: 'Errored',
32
+ };
33
+ /** Markup that binds the dialog or popover state (`?modal=`, `?popover-open=`, view/02). */
34
+ const TOGGLE_BINDING = /\?(?:modal|popover-open)\s*=/i;
35
+ /**
36
+ * Markup that makes a root listen for `command` (05 "Intent events"): a `data-intent-command`
37
+ * attribute (static or bound; a string that is exactly its name, as `setAttribute` takes it), a
38
+ * static `data-intent-on="command"` (quoted or not, alone or in a quoted list), or a bound
39
+ * `data-intent-on` (all intent events), which a template's text shows as `${}` where its
40
+ * expression is, and a string as an unfinished value at its end. The attribute's name is matched in any case, as the runtime reads it.
41
+ */
42
+ const INTENT_ON_COMMAND = /data-intent-command(?:\s*=|$)|data-intent-on\s*=\s*(?:["'][^"'>]*?(?:(?<![\w-])command(?![\w-])|\$\{\}|$)|command(?![\w-])|[^"'\s>]*(?:\$\{\}|$))/i;
43
+ const stringOf = (node) => {
44
+ if (node?.type === 'Literal')
45
+ return typeof node['value'] === 'string' ? node['value'] : undefined;
46
+ if (node?.type !== 'TemplateLiteral' || nodesAt(node, 'expressions').length > 0)
47
+ return undefined;
48
+ return templateText(node);
49
+ };
50
+ /** A template literal's text (cooked where valid), `${}` standing for each expression. */
51
+ function templateText(node) {
52
+ return nodesAt(node, 'quasis')
53
+ .map((q) => {
54
+ const value = q['value'];
55
+ return value?.cooked ?? value?.raw ?? '';
56
+ })
57
+ .join('${}');
58
+ }
59
+ /** An identifier's name, or a string literal's value (`import { 'raw' as r }`). */
60
+ const nameOf = (node) => node?.type === 'Identifier' ? node['name'] : stringOf(node);
61
+ const isValue = (node) => node['importKind'] !== 'type' && node['exportKind'] !== 'type';
62
+ const bump = (counts, name) => {
63
+ counts.set(name, (counts.get(name) ?? 0) + 1);
64
+ };
65
+ const FUNCTION = new Set(['ArrowFunctionExpression', 'FunctionExpression']);
66
+ /** A callee named `define` (`define`, `ns.define`), or the inner call of `define<…>()(…)`. */
67
+ function isDefine(callee) {
68
+ if (callee?.type === 'CallExpression')
69
+ return isDefine(nodeAt(callee, 'callee'));
70
+ if (callee?.type === 'Identifier')
71
+ return callee['name'] === 'define';
72
+ if (callee?.type === 'MemberExpression' && callee['computed'] !== true)
73
+ return nameOf(nodeAt(callee, 'property')) === 'define';
74
+ return false;
75
+ }
76
+ /**
77
+ * The `error` spec field (ADR 0024) by its position, not its name, because `error` is also a
78
+ * common state field, `catch (error)` binding and message name (gyral-1zd.29). It counts:
79
+ * - an `error` key (any value) in a spec object passed to `define()`, inline or through a
80
+ * `const` in the same module, spreads of such consts included;
81
+ * - anywhere else, an `error` key whose value is a function (`error: (failure, s) => …`,
82
+ * `error(failure, s) { … }`) or a shorthand `{ error }`, and an assignment of a function to
83
+ * a member `x.error` (a spec built elsewhere and passed in).
84
+ * What it misses: a spec object built in another module whose `error` value isn't written as a
85
+ * function there (`export const spec = { error: someView }`); view/05 says to write the error
86
+ * view as a function in the spec.
87
+ */
88
+ function specError(program) {
89
+ const objects = new Map();
90
+ let found = false;
91
+ const keyOf = (prop) => prop['computed'] === true ? undefined : nameOf(nodeAt(prop, 'key'));
92
+ const specHasError = (node, depth = 0) => {
93
+ if (node?.type === 'Identifier' && depth < 3) {
94
+ return specHasError(objects.get(node['name']), depth + 1);
95
+ }
96
+ if (node?.type !== 'ObjectExpression')
97
+ return false;
98
+ return nodesAt(node, 'properties').some((p) => p.type === 'SpreadElement'
99
+ ? specHasError(nodeAt(p, 'argument'), depth + 1)
100
+ : keyOf(p) === 'error');
101
+ };
102
+ const collect = (node) => {
103
+ if (node.type === 'VariableDeclarator') {
104
+ const id = nodeAt(node, 'id');
105
+ const init = nodeAt(node, 'init');
106
+ if (id?.type === 'Identifier' && init?.type === 'ObjectExpression')
107
+ objects.set(id['name'], init);
108
+ }
109
+ for (const child of children(node))
110
+ collect(child);
111
+ };
112
+ const visit = (node) => {
113
+ if (found)
114
+ return;
115
+ switch (node.type) {
116
+ case 'CallExpression':
117
+ if (isDefine(nodeAt(node, 'callee'))) {
118
+ const args = nodesAt(node, 'arguments');
119
+ if (args.some((a) => specHasError(a)))
120
+ found = true;
121
+ }
122
+ break;
123
+ case 'Property':
124
+ case 'MethodDefinition':
125
+ case 'PropertyDefinition':
126
+ if (keyOf(node) === 'error') {
127
+ const value = nodeAt(node, 'value');
128
+ if (node['shorthand'] === true ||
129
+ node['method'] === true ||
130
+ node.type === 'MethodDefinition' ||
131
+ (value !== undefined && FUNCTION.has(value.type))) {
132
+ found = true;
133
+ }
134
+ }
135
+ break;
136
+ case 'AssignmentExpression': {
137
+ const left = nodeAt(node, 'left');
138
+ const right = nodeAt(node, 'right');
139
+ if (left?.type === 'MemberExpression' &&
140
+ left['computed'] !== true &&
141
+ nameOf(nodeAt(left, 'property')) === 'error' &&
142
+ right !== undefined &&
143
+ FUNCTION.has(right.type)) {
144
+ found = true;
145
+ }
146
+ break;
147
+ }
148
+ }
149
+ for (const child of children(node))
150
+ visit(child);
151
+ };
152
+ for (const statement of nodesAt(program, 'body'))
153
+ collect(statement);
154
+ for (const statement of nodesAt(program, 'body'))
155
+ visit(statement);
156
+ return found;
157
+ }
158
+ /** The facts the scan needs about a module (`program`, from `this.parse`). */
159
+ export function factsOf(program) {
160
+ /** Every identifier name, and how often each is referenced (property names left out). */
161
+ const names = new Set();
162
+ const refs = new Map();
163
+ const texts = [];
164
+ const reached = [];
165
+ /** Imports of `raw` (local name → specifier), and namespace imports. */
166
+ const rawImports = new Map();
167
+ const namespaces = new Map();
168
+ /** Per namespace, the reads `ns.<name other than raw>`: they can't reach `raw`. */
169
+ const safe = new Map();
170
+ for (const statement of nodesAt(program, 'body')) {
171
+ const specifier = stringOf(nodeAt(statement, 'source'));
172
+ if (specifier === undefined || !isValue(statement))
173
+ continue;
174
+ if (statement.type === 'ImportDeclaration') {
175
+ for (const s of nodesAt(statement, 'specifiers')) {
176
+ const local = nameOf(nodeAt(s, 'local'));
177
+ if (local === undefined || !isValue(s))
178
+ continue;
179
+ if (s.type === 'ImportNamespaceSpecifier')
180
+ namespaces.set(local, specifier);
181
+ else if (s.type === 'ImportSpecifier' && nameOf(nodeAt(s, 'imported')) === 'raw')
182
+ rawImports.set(local, specifier);
183
+ }
184
+ }
185
+ else if (statement.type === 'ExportAllDeclaration') {
186
+ reached.push(specifier);
187
+ }
188
+ else if (statement.type === 'ExportNamedDeclaration') {
189
+ const specifiers = nodesAt(statement, 'specifiers');
190
+ if (specifiers.some((s) => isValue(s) && nameOf(nodeAt(s, 'local')) === 'raw'))
191
+ reached.push(specifier);
192
+ }
193
+ }
194
+ /** A non-computed property name (`{ key: … }`, `a.key`, a class member): not a reference. */
195
+ const key = (node) => {
196
+ if (node?.type === 'Identifier')
197
+ names.add(node['name']);
198
+ else if (node !== undefined)
199
+ visit(node);
200
+ };
201
+ const visit = (node) => {
202
+ switch (node.type) {
203
+ case 'ImportDeclaration':
204
+ return;
205
+ case 'Identifier':
206
+ case 'JSXIdentifier':
207
+ names.add(node['name']);
208
+ bump(refs, node['name']);
209
+ return;
210
+ case 'Literal':
211
+ if (typeof node['value'] === 'string')
212
+ texts.push(node['value']);
213
+ return;
214
+ case 'TemplateLiteral':
215
+ texts.push(templateText(node));
216
+ break;
217
+ case 'ImportExpression': {
218
+ const specifier = stringOf(nodeAt(node, 'source'));
219
+ if (specifier !== undefined)
220
+ reached.push(specifier);
221
+ break;
222
+ }
223
+ case 'MemberExpression': {
224
+ const object = nodeAt(node, 'object');
225
+ const property = nodeAt(node, 'property');
226
+ const computed = node['computed'] === true;
227
+ const ns = object?.type === 'Identifier' ? object['name'] : undefined;
228
+ if (ns !== undefined && namespaces.has(ns)) {
229
+ const name = computed ? stringOf(property) : nameOf(property);
230
+ if (name !== undefined && name !== 'raw')
231
+ bump(safe, ns);
232
+ }
233
+ if (object !== undefined)
234
+ visit(object);
235
+ if (computed) {
236
+ if (property !== undefined)
237
+ visit(property);
238
+ }
239
+ else
240
+ key(property);
241
+ return;
242
+ }
243
+ case 'Property':
244
+ case 'MethodDefinition':
245
+ case 'PropertyDefinition':
246
+ case 'AccessorProperty':
247
+ if (node['computed'] === true || node['shorthand'] === true)
248
+ break;
249
+ key(nodeAt(node, 'key'));
250
+ for (const child of children(node))
251
+ if (child !== nodeAt(node, 'key'))
252
+ visit(child);
253
+ return;
254
+ }
255
+ for (const child of children(node))
256
+ visit(child);
257
+ };
258
+ for (const statement of nodesAt(program, 'body'))
259
+ visit(statement);
260
+ for (const [local, specifier] of rawImports) {
261
+ if ((refs.get(local) ?? 0) > 0)
262
+ reached.push(specifier);
263
+ }
264
+ for (const [local, specifier] of namespaces) {
265
+ if ((refs.get(local) ?? 0) > (safe.get(local) ?? 0))
266
+ reached.push(specifier);
267
+ }
268
+ return { names, texts, rawSources: [...new Set(reached)], errorView: specError(program) };
269
+ }
270
+ /**
271
+ * Whether the module may use `feature` by what it writes itself. For `invokers` that is the
272
+ * markup and strings; `raw` needs resolving `rawSources` (features.ts).
273
+ */
274
+ export function writes(facts, feature) {
275
+ if (feature === 'invokers') {
276
+ return facts.texts.some((text) => text === 'command' || INTENT_ON_COMMAND.test(text));
277
+ }
278
+ if (feature === 'dialogs')
279
+ return facts.texts.some((text) => TOGGLE_BINDING.test(text));
280
+ if (feature === 'errorView')
281
+ return facts.errorView;
282
+ const name = FIELDS[feature];
283
+ return facts.names.has(name) || facts.texts.includes(name);
284
+ }
285
+ //# sourceMappingURL=facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facts.js","sourceRoot":"","sources":["../../src/compiler/facts.ts"],"names":[],"mappings":"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","sourcesContent":["// What one module may use, for the build-time feature scan (features.ts, view/05-element.md\n// \"Features register themselves\"), read from its AST (Rolldown's `this.parse`, the author's\n// source: both plugins that scan run before other transforms). Comments are not in the AST,\n// and type-only code is skipped (ast.ts `children`), so neither counts. What does:\n// - spec fields (`viewTransition`, `renderOnFrame`, `states`, `subscriptions`) and the hook\n// spec key `dispose`: the name as an identifier\n// anywhere in runtime code (a property key, `spec.states = …`, `{ states }`, a binding a\n// namespace import may spread, `export { f as states }`), or a string that is exactly the\n// name (`Object.defineProperty(spec, 'states', …)`). A word inside a longer string doesn't;\n// - command intents: a string or template whose markup has a `data-intent-command` attribute,\n// `data-intent-on=\"command\"` or a bound `data-intent-on`, or a string that is exactly \"command\" (`events: ['command']`, a\n// `setAttribute`);\n// - dialog and popover bindings: a template whose markup binds `?modal=` or `?popover-open=`;\n// - `raw` (its markup is read at run time, so it may hold `data-intent-on=\"command\"`): the\n// module lists the specifiers through which it may reach a `raw` export, and features.ts\n// counts it when one of them is a module of `@gyral/core`. Through: a named import of `raw` (any\n// alias) that the module references; a namespace import read other than as `ns.<name>`\n// (`ns.raw`, `ns[key]`, the namespace passed on); a re-export of `raw`, `export *`; a\n// dynamic `import()`. A module that re-exports core's `raw` counts itself, so `raw`\n// imported through a re-exporting module (the app's, a design system's) is still seen there.\nimport { children, nodeAt, nodesAt, type Node } from './ast.js';\n\n/** Optional machinery the build adds when a module may use it. */\nexport type Feature =\n | 'invokers'\n | 'transitions'\n | 'frame'\n | 'states'\n | 'forms'\n | 'subscriptions'\n | 'dialogs'\n | 'disposal'\n | 'errorView'\n | 'errored';\n\n/** The spec field each spec-field feature is reached through (04, 05). */\nexport const FIELDS = {\n transitions: 'viewTransition',\n frame: 'renderOnFrame',\n states: 'states',\n forms: 'formAssociated',\n subscriptions: 'subscriptions',\n disposal: 'dispose',\n errorView: 'error',\n errored: 'Errored',\n} as const satisfies Readonly<Record<Exclude<Feature, 'invokers' | 'dialogs'>, string>>;\n\n/** Markup that binds the dialog or popover state (`?modal=`, `?popover-open=`, view/02). */\nconst TOGGLE_BINDING = /\\?(?:modal|popover-open)\\s*=/i;\n\n/**\n * Markup that makes a root listen for `command` (05 \"Intent events\"): a `data-intent-command`\n * attribute (static or bound; a string that is exactly its name, as `setAttribute` takes it), a\n * static `data-intent-on=\"command\"` (quoted or not, alone or in a quoted list), or a bound\n * `data-intent-on` (all intent events), which a template's text shows as `${}` where its\n * expression is, and a string as an unfinished value at its end. The attribute's name is matched in any case, as the runtime reads it.\n */\nconst INTENT_ON_COMMAND =\n /data-intent-command(?:\\s*=|$)|data-intent-on\\s*=\\s*(?:[\"'][^\"'>]*?(?:(?<![\\w-])command(?![\\w-])|\\$\\{\\}|$)|command(?![\\w-])|[^\"'\\s>]*(?:\\$\\{\\}|$))/i;\n\nexport interface ModuleFacts {\n /** Identifier names in runtime code, import declarations left out. */\n readonly names: ReadonlySet<string>;\n /** String literal values, and template literal texts with `${}` for each expression. */\n readonly texts: readonly string[];\n /** Specifiers through which the module may reach a `raw` export (see the header). */\n readonly rawSources: readonly string[];\n /** Whether the module may give a component an error view (see `specError`). */\n readonly errorView: boolean;\n}\n\nconst stringOf = (node: Node | undefined): string | undefined => {\n if (node?.type === 'Literal')\n return typeof node['value'] === 'string' ? node['value'] : undefined;\n if (node?.type !== 'TemplateLiteral' || nodesAt(node, 'expressions').length > 0) return undefined;\n return templateText(node);\n};\n\n/** A template literal's text (cooked where valid), `${}` standing for each expression. */\nfunction templateText(node: Node): string {\n return nodesAt(node, 'quasis')\n .map((q) => {\n const value = q['value'] as { cooked?: string | null; raw?: string } | undefined;\n return value?.cooked ?? value?.raw ?? '';\n })\n .join('${}');\n}\n\n/** An identifier's name, or a string literal's value (`import { 'raw' as r }`). */\nconst nameOf = (node: Node | undefined): string | undefined =>\n node?.type === 'Identifier' ? (node['name'] as string) : stringOf(node);\n\nconst isValue = (node: Node): boolean =>\n node['importKind'] !== 'type' && node['exportKind'] !== 'type';\n\nconst bump = (counts: Map<string, number>, name: string): void => {\n counts.set(name, (counts.get(name) ?? 0) + 1);\n};\n\nconst FUNCTION = new Set(['ArrowFunctionExpression', 'FunctionExpression']);\n\n/** A callee named `define` (`define`, `ns.define`), or the inner call of `define<…>()(…)`. */\nfunction isDefine(callee: Node | undefined): boolean {\n if (callee?.type === 'CallExpression') return isDefine(nodeAt(callee, 'callee'));\n if (callee?.type === 'Identifier') return callee['name'] === 'define';\n if (callee?.type === 'MemberExpression' && callee['computed'] !== true)\n return nameOf(nodeAt(callee, 'property')) === 'define';\n return false;\n}\n\n/**\n * The `error` spec field (ADR 0024) by its position, not its name, because `error` is also a\n * common state field, `catch (error)` binding and message name (gyral-1zd.29). It counts:\n * - an `error` key (any value) in a spec object passed to `define()`, inline or through a\n * `const` in the same module, spreads of such consts included;\n * - anywhere else, an `error` key whose value is a function (`error: (failure, s) => …`,\n * `error(failure, s) { … }`) or a shorthand `{ error }`, and an assignment of a function to\n * a member `x.error` (a spec built elsewhere and passed in).\n * What it misses: a spec object built in another module whose `error` value isn't written as a\n * function there (`export const spec = { error: someView }`); view/05 says to write the error\n * view as a function in the spec.\n */\nfunction specError(program: Node): boolean {\n const objects = new Map<string, Node>();\n let found = false;\n const keyOf = (prop: Node): string | undefined =>\n prop['computed'] === true ? undefined : nameOf(nodeAt(prop, 'key'));\n const specHasError = (node: Node | undefined, depth = 0): boolean => {\n if (node?.type === 'Identifier' && depth < 3) {\n return specHasError(objects.get(node['name'] as string), depth + 1);\n }\n if (node?.type !== 'ObjectExpression') return false;\n return nodesAt(node, 'properties').some((p) =>\n p.type === 'SpreadElement'\n ? specHasError(nodeAt(p, 'argument'), depth + 1)\n : keyOf(p) === 'error',\n );\n };\n const collect = (node: Node): void => {\n if (node.type === 'VariableDeclarator') {\n const id = nodeAt(node, 'id');\n const init = nodeAt(node, 'init');\n if (id?.type === 'Identifier' && init?.type === 'ObjectExpression')\n objects.set(id['name'] as string, init);\n }\n for (const child of children(node)) collect(child);\n };\n const visit = (node: Node): void => {\n if (found) return;\n switch (node.type) {\n case 'CallExpression':\n if (isDefine(nodeAt(node, 'callee'))) {\n const args = nodesAt(node, 'arguments');\n if (args.some((a) => specHasError(a))) found = true;\n }\n break;\n case 'Property':\n case 'MethodDefinition':\n case 'PropertyDefinition':\n if (keyOf(node) === 'error') {\n const value = nodeAt(node, 'value');\n if (\n node['shorthand'] === true ||\n node['method'] === true ||\n node.type === 'MethodDefinition' ||\n (value !== undefined && FUNCTION.has(value.type))\n ) {\n found = true;\n }\n }\n break;\n case 'AssignmentExpression': {\n const left = nodeAt(node, 'left');\n const right = nodeAt(node, 'right');\n if (\n left?.type === 'MemberExpression' &&\n left['computed'] !== true &&\n nameOf(nodeAt(left, 'property')) === 'error' &&\n right !== undefined &&\n FUNCTION.has(right.type)\n ) {\n found = true;\n }\n break;\n }\n }\n for (const child of children(node)) visit(child);\n };\n for (const statement of nodesAt(program, 'body')) collect(statement);\n for (const statement of nodesAt(program, 'body')) visit(statement);\n return found;\n}\n\n/** The facts the scan needs about a module (`program`, from `this.parse`). */\nexport function factsOf(program: Node): ModuleFacts {\n /** Every identifier name, and how often each is referenced (property names left out). */\n const names = new Set<string>();\n const refs = new Map<string, number>();\n const texts: string[] = [];\n const reached: string[] = [];\n /** Imports of `raw` (local name → specifier), and namespace imports. */\n const rawImports = new Map<string, string>();\n const namespaces = new Map<string, string>();\n /** Per namespace, the reads `ns.<name other than raw>`: they can't reach `raw`. */\n const safe = new Map<string, number>();\n\n for (const statement of nodesAt(program, 'body')) {\n const specifier = stringOf(nodeAt(statement, 'source'));\n if (specifier === undefined || !isValue(statement)) continue;\n if (statement.type === 'ImportDeclaration') {\n for (const s of nodesAt(statement, 'specifiers')) {\n const local = nameOf(nodeAt(s, 'local'));\n if (local === undefined || !isValue(s)) continue;\n if (s.type === 'ImportNamespaceSpecifier') namespaces.set(local, specifier);\n else if (s.type === 'ImportSpecifier' && nameOf(nodeAt(s, 'imported')) === 'raw')\n rawImports.set(local, specifier);\n }\n } else if (statement.type === 'ExportAllDeclaration') {\n reached.push(specifier);\n } else if (statement.type === 'ExportNamedDeclaration') {\n const specifiers = nodesAt(statement, 'specifiers');\n if (specifiers.some((s) => isValue(s) && nameOf(nodeAt(s, 'local')) === 'raw'))\n reached.push(specifier);\n }\n }\n\n /** A non-computed property name (`{ key: … }`, `a.key`, a class member): not a reference. */\n const key = (node: Node | undefined): void => {\n if (node?.type === 'Identifier') names.add(node['name'] as string);\n else if (node !== undefined) visit(node);\n };\n\n const visit = (node: Node): void => {\n switch (node.type) {\n case 'ImportDeclaration':\n return;\n case 'Identifier':\n case 'JSXIdentifier':\n names.add(node['name'] as string);\n bump(refs, node['name'] as string);\n return;\n case 'Literal':\n if (typeof node['value'] === 'string') texts.push(node['value']);\n return;\n case 'TemplateLiteral':\n texts.push(templateText(node));\n break;\n case 'ImportExpression': {\n const specifier = stringOf(nodeAt(node, 'source'));\n if (specifier !== undefined) reached.push(specifier);\n break;\n }\n case 'MemberExpression': {\n const object = nodeAt(node, 'object');\n const property = nodeAt(node, 'property');\n const computed = node['computed'] === true;\n const ns = object?.type === 'Identifier' ? (object['name'] as string) : undefined;\n if (ns !== undefined && namespaces.has(ns)) {\n const name = computed ? stringOf(property) : nameOf(property);\n if (name !== undefined && name !== 'raw') bump(safe, ns);\n }\n if (object !== undefined) visit(object);\n if (computed) {\n if (property !== undefined) visit(property);\n } else key(property);\n return;\n }\n case 'Property':\n case 'MethodDefinition':\n case 'PropertyDefinition':\n case 'AccessorProperty':\n if (node['computed'] === true || node['shorthand'] === true) break;\n key(nodeAt(node, 'key'));\n for (const child of children(node)) if (child !== nodeAt(node, 'key')) visit(child);\n return;\n }\n for (const child of children(node)) visit(child);\n };\n for (const statement of nodesAt(program, 'body')) visit(statement);\n\n for (const [local, specifier] of rawImports) {\n if ((refs.get(local) ?? 0) > 0) reached.push(specifier);\n }\n for (const [local, specifier] of namespaces) {\n if ((refs.get(local) ?? 0) > (safe.get(local) ?? 0)) reached.push(specifier);\n }\n return { names, texts, rawSources: [...new Set(reached)], errorView: specError(program) };\n}\n\n/**\n * Whether the module may use `feature` by what it writes itself. For `invokers` that is the\n * markup and strings; `raw` needs resolving `rawSources` (features.ts).\n */\nexport function writes(facts: ModuleFacts, feature: Feature): boolean {\n if (feature === 'invokers') {\n return facts.texts.some((text) => text === 'command' || INTENT_ON_COMMAND.test(text));\n }\n if (feature === 'dialogs') return facts.texts.some((text) => TOGGLE_BINDING.test(text));\n if (feature === 'errorView') return facts.errorView;\n const name = FIELDS[feature];\n return facts.names.has(name) || facts.texts.includes(name);\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import { langOf } from './ast.js';
2
+ import { type Feature } from './facts.js';
3
+ export type { Feature } from './facts.js';
4
+ /**
5
+ * Text a module must contain to use a feature (the plugins' transform filters list the same).
6
+ * `invokers`: also any import or export, which may reach `raw`.
7
+ */
8
+ export declare const FEATURE_HINTS: Readonly<Record<Feature, RegExp>>;
9
+ /** A plugin context's `resolve`, as far as detection needs it. */
10
+ type Resolve = (source: string, importer: string) => Promise<{
11
+ readonly id: string;
12
+ } | null>;
13
+ /** What the scan needs from the transform hook's plugin context. */
14
+ export interface ScanContext {
15
+ /** `this.parse` (Rolldown's parser, TypeScript included). */
16
+ readonly parse: (code: string, lang: ReturnType<typeof langOf>) => unknown;
17
+ readonly resolve: Resolve;
18
+ }
19
+ export interface FeatureHooks {
20
+ /** Finds the core copy the app imports (its compiled entry), to register with and to skip. */
21
+ buildStart(resolve: Resolve, root: string): Promise<void>;
22
+ resolveId(source: string): {
23
+ id: string;
24
+ moduleSideEffects: true;
25
+ } | null;
26
+ load(id: string): string | null;
27
+ /** The imports to append to module `id` for the features its `code` may use; '' for none. */
28
+ inject(code: string, id: string, context: ScanContext): Promise<string>;
29
+ }
30
+ /**
31
+ * Detection for `features`. `ownEntry`: the compiled entry of the core copy running the plugin,
32
+ * used when the app's root can't resolve `@gyral/core/compiled` (fixtures, unusual layouts).
33
+ */
34
+ export declare function createFeatures(features: readonly Feature[], ownEntry: string): FeatureHooks;
@@ -0,0 +1,158 @@
1
+ // Build-time feature detection (view/05-element.md "Features register themselves",
2
+ // gyral-c5d.11, gyral-c5d.12), loaded lazily by the plugin shells in ../vite.ts. Some optional
3
+ // machinery can't register itself from an API call, because apps reach it through plain data:
4
+ // spec fields (`viewTransition`, `renderOnFrame`, `states`, `subscriptions`) and markup (`data-intent-on`
5
+ // values, `raw()` content). In builds that leave that machinery out by default (the
6
+ // `gyral-compiled` condition, and `gyral-client-only` for the invoker fallback), the modules
7
+ // that can affect Gyral components are scanned, and a module that may use a feature gets one
8
+ // import added at its end: `virtual:gyral-use/<feature>`, a side-effect module that calls
9
+ // `register()` from core's `use-<feature>` module before any module that imports it runs. The
10
+ // registration modules are reached only this way, never from an entry, so a build that doesn't
11
+ // use a feature doesn't even load its code (Rolldown emits chunks for every import() it loads,
12
+ // tree-shaken or not).
13
+ //
14
+ // Which modules (scope.ts): the app's own source, and installed packages that are Gyral's or
15
+ // depend on one, directly or through their dependencies. What counts in them (facts.ts): names
16
+ // and strings in the module's AST, never comments, and `raw` only when it comes from
17
+ // `@gyral/core`. Both over-approximate, so the scan stays sound: a field or event can only be
18
+ // set by writing its name somewhere, in a module that can reach Gyral (a name built at run
19
+ // time, such as `{ ['sta' + 'tes']: … }`, or spec data written in a package that doesn't
20
+ // depend on Gyral, are the gaps; view/05 says what then degrades). A false positive only bundles a few hundred
21
+ // bytes that weren't needed. Core's own modules are skipped (they implement it); a module that
22
+ // doesn't parse is matched on its text, comments included.
23
+ import { join } from 'node:path';
24
+ import { langOf } from './ast.js';
25
+ import { factsOf, writes } from './facts.js';
26
+ import { createScope } from './scope.js';
27
+ /** The text fallback, for a module that doesn't parse: the 0.3.1-next.0 scan. */
28
+ const TEXT_USES = {
29
+ invokers: /data-intent-command\s*=|data-intent-on\s*=\s*\\?["']?(?:[\w-]+\s+)*(?:command\b|\$\{)|(["'`])command\1|\braw\b\s*(?:\(|as\b)/i,
30
+ transitions: /\bviewTransition\b/,
31
+ frame: /\brenderOnFrame\b/,
32
+ states: /\bstates\b/,
33
+ forms: /\bformAssociated\b/,
34
+ subscriptions: /\bsubscriptions\b/,
35
+ dialogs: /\?(?:modal|popover-open)\s*=/i,
36
+ disposal: /\bdispose\b/,
37
+ errorView: /\berror\b/,
38
+ errored: /\bErrored\b/,
39
+ };
40
+ /** Each feature's registration module in core (`src/<name>.ts`, published as `dist/<name>.js`). */
41
+ const REGISTRATION = {
42
+ invokers: 'use-invokers',
43
+ transitions: 'use-transitions',
44
+ frame: 'use-frame-lane',
45
+ states: 'use-states',
46
+ forms: 'use-form-associated',
47
+ subscriptions: 'use-subscriptions',
48
+ dialogs: 'use-dialogs',
49
+ disposal: 'use-disposal',
50
+ errorView: 'use-error-view',
51
+ errored: 'use-errored',
52
+ };
53
+ /**
54
+ * Text a module must contain to use a feature (the plugins' transform filters list the same).
55
+ * `invokers`: also any import or export, which may reach `raw`.
56
+ */
57
+ export const FEATURE_HINTS = {
58
+ invokers: /data-intent-on|command|raw|import|export/i,
59
+ transitions: /viewTransition/,
60
+ frame: /renderOnFrame/,
61
+ states: /states/,
62
+ forms: /formAssociated/,
63
+ subscriptions: /subscriptions/,
64
+ dialogs: /modal|popover-open/i,
65
+ disposal: /dispose/,
66
+ errorView: /error/,
67
+ errored: /Errored/,
68
+ };
69
+ const PREFIX = 'virtual:gyral-use/';
70
+ /** The package that exports `raw`. */
71
+ const CORE = '@gyral/core';
72
+ const RESOLVED = '\0gyral-use/';
73
+ const SCRIPT = /\.[cm]?[jt]sx?$/;
74
+ /** core's compiled entry, in its source tree or its published dist/: [, dir, extension]. */
75
+ const ENTRY_FILE = /[\\/](src|dist)[\\/]view[\\/]compiled\.(ts|js)$/;
76
+ const importsOf = (features) => features.map((feature) => `\nimport ${JSON.stringify(PREFIX + feature)};`).join('');
77
+ /**
78
+ * Detection for `features`. `ownEntry`: the compiled entry of the core copy running the plugin,
79
+ * used when the app's root can't resolve `@gyral/core/compiled` (fixtures, unusual layouts).
80
+ */
81
+ export function createFeatures(features, ownEntry) {
82
+ let entry = ownEntry;
83
+ let scope = createScope();
84
+ const skipped = new Set([ownEntry.replace(ENTRY_FILE, '/')]);
85
+ /** A registration module next to the compiled entry's view/ directory. */
86
+ const moduleOf = (name) => entry.replace(ENTRY_FILE, (_, dir, ext) => `/${dir}/${name}.${ext}`);
87
+ const isCore = (id) => [...skipped].some((dir) => id.startsWith(dir));
88
+ /**
89
+ * Whether one of `specifiers`, imported by `importer`, is a module of core (where `raw` comes
90
+ * from): `@gyral/core` or one of its subpaths, or a specifier that resolves into core (an
91
+ * alias, a path). Another package that re-exports core's `raw` counts in its own module.
92
+ */
93
+ async function coreAmong(specifiers, importer, resolve) {
94
+ for (const specifier of specifiers) {
95
+ if (specifier === CORE || specifier.startsWith(`${CORE}/`))
96
+ return true;
97
+ let resolved = null;
98
+ try {
99
+ resolved = await resolve(specifier, importer);
100
+ }
101
+ catch {
102
+ // unresolvable: the bundler reports it
103
+ }
104
+ const id = resolved?.id.replace(/\?.*$/, '');
105
+ if (id !== undefined && (isCore(id) || scope.packageOf(id) === CORE))
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ return {
111
+ async buildStart(resolve, root) {
112
+ scope = createScope(); // manifests may have changed since the last build (watch mode)
113
+ const resolved = await resolve('@gyral/core/compiled', join(root, 'index.html'));
114
+ if (resolved === null || !ENTRY_FILE.test(resolved.id))
115
+ return;
116
+ entry = resolved.id;
117
+ skipped.add(entry.replace(ENTRY_FILE, '/'));
118
+ },
119
+ resolveId(source) {
120
+ if (!source.startsWith(PREFIX))
121
+ return null;
122
+ const feature = source.slice(PREFIX.length);
123
+ return features.includes(feature)
124
+ ? { id: RESOLVED + feature, moduleSideEffects: true }
125
+ : null;
126
+ },
127
+ load(id) {
128
+ if (!id.startsWith(RESOLVED))
129
+ return null;
130
+ const file = moduleOf(REGISTRATION[id.slice(RESOLVED.length)]);
131
+ return `import { register } from ${JSON.stringify(file)};\nregister();\n`;
132
+ },
133
+ async inject(code, id, context) {
134
+ const file = id.replace(/\?.*$/, '');
135
+ if (id.startsWith('\0') || !SCRIPT.test(file) || isCore(file))
136
+ return '';
137
+ const hinted = features.filter((feature) => FEATURE_HINTS[feature].test(code));
138
+ if (hinted.length === 0 || !scope.inScope(file))
139
+ return '';
140
+ let program;
141
+ try {
142
+ program = context.parse(code, langOf(file));
143
+ }
144
+ catch {
145
+ return importsOf(hinted.filter((feature) => TEXT_USES[feature].test(code)));
146
+ }
147
+ const facts = factsOf(program);
148
+ const used = [];
149
+ for (const feature of hinted) {
150
+ if (writes(facts, feature) ||
151
+ (feature === 'invokers' && (await coreAmong(facts.rawSources, id, context.resolve))))
152
+ used.push(feature);
153
+ }
154
+ return importsOf(used);
155
+ },
156
+ };
157
+ }
158
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/compiler/features.ts"],"names":[],"mappings":"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","sourcesContent":["// Build-time feature detection (view/05-element.md \"Features register themselves\",\n// gyral-c5d.11, gyral-c5d.12), loaded lazily by the plugin shells in ../vite.ts. Some optional\n// machinery can't register itself from an API call, because apps reach it through plain data:\n// spec fields (`viewTransition`, `renderOnFrame`, `states`, `subscriptions`) and markup (`data-intent-on`\n// values, `raw()` content). In builds that leave that machinery out by default (the\n// `gyral-compiled` condition, and `gyral-client-only` for the invoker fallback), the modules\n// that can affect Gyral components are scanned, and a module that may use a feature gets one\n// import added at its end: `virtual:gyral-use/<feature>`, a side-effect module that calls\n// `register()` from core's `use-<feature>` module before any module that imports it runs. The\n// registration modules are reached only this way, never from an entry, so a build that doesn't\n// use a feature doesn't even load its code (Rolldown emits chunks for every import() it loads,\n// tree-shaken or not).\n//\n// Which modules (scope.ts): the app's own source, and installed packages that are Gyral's or\n// depend on one, directly or through their dependencies. What counts in them (facts.ts): names\n// and strings in the module's AST, never comments, and `raw` only when it comes from\n// `@gyral/core`. Both over-approximate, so the scan stays sound: a field or event can only be\n// set by writing its name somewhere, in a module that can reach Gyral (a name built at run\n// time, such as `{ ['sta' + 'tes']: … }`, or spec data written in a package that doesn't\n// depend on Gyral, are the gaps; view/05 says what then degrades). A false positive only bundles a few hundred\n// bytes that weren't needed. Core's own modules are skipped (they implement it); a module that\n// doesn't parse is matched on its text, comments included.\nimport { join } from 'node:path';\nimport { langOf, type Node } from './ast.js';\nimport { factsOf, writes, type Feature } from './facts.js';\nimport { createScope, type Scope } from './scope.js';\n\nexport type { Feature } from './facts.js';\n\n/** The text fallback, for a module that doesn't parse: the 0.3.1-next.0 scan. */\nconst TEXT_USES: Readonly<Record<Feature, RegExp>> = {\n invokers:\n /data-intent-command\\s*=|data-intent-on\\s*=\\s*\\\\?[\"']?(?:[\\w-]+\\s+)*(?:command\\b|\\$\\{)|([\"'`])command\\1|\\braw\\b\\s*(?:\\(|as\\b)/i,\n transitions: /\\bviewTransition\\b/,\n frame: /\\brenderOnFrame\\b/,\n states: /\\bstates\\b/,\n forms: /\\bformAssociated\\b/,\n subscriptions: /\\bsubscriptions\\b/,\n dialogs: /\\?(?:modal|popover-open)\\s*=/i,\n disposal: /\\bdispose\\b/,\n errorView: /\\berror\\b/,\n errored: /\\bErrored\\b/,\n};\n\n/** Each feature's registration module in core (`src/<name>.ts`, published as `dist/<name>.js`). */\nconst REGISTRATION: Readonly<Record<Feature, string>> = {\n invokers: 'use-invokers',\n transitions: 'use-transitions',\n frame: 'use-frame-lane',\n states: 'use-states',\n forms: 'use-form-associated',\n subscriptions: 'use-subscriptions',\n dialogs: 'use-dialogs',\n disposal: 'use-disposal',\n errorView: 'use-error-view',\n errored: 'use-errored',\n};\n\n/**\n * Text a module must contain to use a feature (the plugins' transform filters list the same).\n * `invokers`: also any import or export, which may reach `raw`.\n */\nexport const FEATURE_HINTS: Readonly<Record<Feature, RegExp>> = {\n invokers: /data-intent-on|command|raw|import|export/i,\n transitions: /viewTransition/,\n frame: /renderOnFrame/,\n states: /states/,\n forms: /formAssociated/,\n subscriptions: /subscriptions/,\n dialogs: /modal|popover-open/i,\n disposal: /dispose/,\n errorView: /error/,\n errored: /Errored/,\n};\n\nconst PREFIX = 'virtual:gyral-use/';\n/** The package that exports `raw`. */\nconst CORE = '@gyral/core';\nconst RESOLVED = '\\0gyral-use/';\nconst SCRIPT = /\\.[cm]?[jt]sx?$/;\n/** core's compiled entry, in its source tree or its published dist/: [, dir, extension]. */\nconst ENTRY_FILE = /[\\\\/](src|dist)[\\\\/]view[\\\\/]compiled\\.(ts|js)$/;\n\n/** A plugin context's `resolve`, as far as detection needs it. */\ntype Resolve = (source: string, importer: string) => Promise<{ readonly id: string } | null>;\n\n/** What the scan needs from the transform hook's plugin context. */\nexport interface ScanContext {\n /** `this.parse` (Rolldown's parser, TypeScript included). */\n readonly parse: (code: string, lang: ReturnType<typeof langOf>) => unknown;\n readonly resolve: Resolve;\n}\n\nexport interface FeatureHooks {\n /** Finds the core copy the app imports (its compiled entry), to register with and to skip. */\n buildStart(resolve: Resolve, root: string): Promise<void>;\n resolveId(source: string): { id: string; moduleSideEffects: true } | null;\n load(id: string): string | null;\n /** The imports to append to module `id` for the features its `code` may use; '' for none. */\n inject(code: string, id: string, context: ScanContext): Promise<string>;\n}\n\nconst importsOf = (features: readonly Feature[]): string =>\n features.map((feature) => `\\nimport ${JSON.stringify(PREFIX + feature)};`).join('');\n\n/**\n * Detection for `features`. `ownEntry`: the compiled entry of the core copy running the plugin,\n * used when the app's root can't resolve `@gyral/core/compiled` (fixtures, unusual layouts).\n */\nexport function createFeatures(features: readonly Feature[], ownEntry: string): FeatureHooks {\n let entry = ownEntry;\n let scope: Scope = createScope();\n const skipped = new Set([ownEntry.replace(ENTRY_FILE, '/')]);\n /** A registration module next to the compiled entry's view/ directory. */\n const moduleOf = (name: string): string =>\n entry.replace(ENTRY_FILE, (_, dir: string, ext: string) => `/${dir}/${name}.${ext}`);\n const isCore = (id: string): boolean => [...skipped].some((dir) => id.startsWith(dir));\n\n /**\n * Whether one of `specifiers`, imported by `importer`, is a module of core (where `raw` comes\n * from): `@gyral/core` or one of its subpaths, or a specifier that resolves into core (an\n * alias, a path). Another package that re-exports core's `raw` counts in its own module.\n */\n async function coreAmong(\n specifiers: readonly string[],\n importer: string,\n resolve: Resolve,\n ): Promise<boolean> {\n for (const specifier of specifiers) {\n if (specifier === CORE || specifier.startsWith(`${CORE}/`)) return true;\n let resolved: { readonly id: string } | null = null;\n try {\n resolved = await resolve(specifier, importer);\n } catch {\n // unresolvable: the bundler reports it\n }\n const id = resolved?.id.replace(/\\?.*$/, '');\n if (id !== undefined && (isCore(id) || scope.packageOf(id) === CORE)) return true;\n }\n return false;\n }\n\n return {\n async buildStart(resolve, root) {\n scope = createScope(); // manifests may have changed since the last build (watch mode)\n const resolved = await resolve('@gyral/core/compiled', join(root, 'index.html'));\n if (resolved === null || !ENTRY_FILE.test(resolved.id)) return;\n entry = resolved.id;\n skipped.add(entry.replace(ENTRY_FILE, '/'));\n },\n resolveId(source) {\n if (!source.startsWith(PREFIX)) return null;\n const feature = source.slice(PREFIX.length) as Feature;\n return features.includes(feature)\n ? { id: RESOLVED + feature, moduleSideEffects: true }\n : null;\n },\n load(id) {\n if (!id.startsWith(RESOLVED)) return null;\n const file = moduleOf(REGISTRATION[id.slice(RESOLVED.length) as Feature]);\n return `import { register } from ${JSON.stringify(file)};\\nregister();\\n`;\n },\n async inject(code, id, context) {\n const file = id.replace(/\\?.*$/, '');\n if (id.startsWith('\\0') || !SCRIPT.test(file) || isCore(file)) return '';\n const hinted = features.filter((feature) => FEATURE_HINTS[feature].test(code));\n if (hinted.length === 0 || !scope.inScope(file)) return '';\n let program: Node;\n try {\n program = context.parse(code, langOf(file)) as Node;\n } catch {\n return importsOf(hinted.filter((feature) => TEXT_USES[feature].test(code)));\n }\n const facts = factsOf(program);\n const used: Feature[] = [];\n for (const feature of hinted) {\n if (\n writes(facts, feature) ||\n (feature === 'invokers' && (await coreAmong(facts.rawSources, id, context.resolve)))\n )\n used.push(feature);\n }\n return importsOf(used);\n },\n };\n}\n"]}
@@ -6,6 +6,8 @@ type HookFn<K extends keyof Plugin> = Fn<NonNullable<Plugin[K]>>;
6
6
  export interface CompilerHooks {
7
7
  readonly configResolved: HookFn<'configResolved'>;
8
8
  readonly buildStart: HookFn<'buildStart'>;
9
+ readonly resolveId: HookFn<'resolveId'>;
10
+ readonly load: HookFn<'load'>;
9
11
  readonly transform: HookFn<'transform'>;
10
12
  readonly generateBundle: HookFn<'generateBundle'>;
11
13
  }
@@ -13,6 +15,8 @@ export interface CompilerSettings {
13
15
  readonly sources: readonly string[];
14
16
  /** The module to load parse5 from; undefined skips the parse5 check. */
15
17
  readonly parse5: string | undefined;
18
+ /** The compiled entry of the core copy running the plugin (features.ts). */
19
+ readonly ownEntry: string;
16
20
  }
17
21
  export declare function createCompiler(settings: CompilerSettings): CompilerHooks;
18
22
  export {};