@gyral/core 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/NOTICE +19 -0
  3. package/README.md +36 -8
  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 +190 -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 +90 -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 +12 -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 +7 -4
  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 +21 -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 +42 -20
  140. package/dist/intent.js +145 -107
  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 +9 -3
  184. package/dist/server.js +12 -3
  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.d.ts +2 -6
  207. package/dist/store.js +36 -8
  208. package/dist/store.js.map +1 -1
  209. package/dist/subscription.d.ts +35 -0
  210. package/dist/subscription.js +74 -0
  211. package/dist/subscription.js.map +1 -0
  212. package/dist/subscriptions.d.ts +26 -0
  213. package/dist/subscriptions.js +98 -0
  214. package/dist/subscriptions.js.map +1 -0
  215. package/dist/transitions.d.ts +4 -5
  216. package/dist/transitions.js +10 -4
  217. package/dist/transitions.js.map +1 -1
  218. package/dist/types.d.ts +141 -32
  219. package/dist/types.js.map +1 -1
  220. package/dist/use-dialogs.d.ts +2 -0
  221. package/dist/use-dialogs.js +9 -0
  222. package/dist/use-dialogs.js.map +1 -0
  223. package/dist/use-disposal.d.ts +2 -0
  224. package/dist/use-disposal.js +9 -0
  225. package/dist/use-disposal.js.map +1 -0
  226. package/dist/use-error-view.d.ts +2 -0
  227. package/dist/use-error-view.js +9 -0
  228. package/dist/use-error-view.js.map +1 -0
  229. package/dist/use-errored.d.ts +2 -0
  230. package/dist/use-errored.js +9 -0
  231. package/dist/use-errored.js.map +1 -0
  232. package/dist/use-form-associated.d.ts +2 -0
  233. package/dist/use-form-associated.js +7 -0
  234. package/dist/use-form-associated.js.map +1 -0
  235. package/dist/use-frame-lane.d.ts +2 -0
  236. package/dist/use-frame-lane.js +10 -0
  237. package/dist/use-frame-lane.js.map +1 -0
  238. package/dist/use-invokers.d.ts +2 -0
  239. package/dist/use-invokers.js +10 -0
  240. package/dist/use-invokers.js.map +1 -0
  241. package/dist/use-states.d.ts +2 -0
  242. package/dist/use-states.js +10 -0
  243. package/dist/use-states.js.map +1 -0
  244. package/dist/use-subscriptions.d.ts +2 -0
  245. package/dist/use-subscriptions.js +10 -0
  246. package/dist/use-subscriptions.js.map +1 -0
  247. package/dist/use-transitions.d.ts +2 -0
  248. package/dist/use-transitions.js +10 -0
  249. package/dist/use-transitions.js.map +1 -0
  250. package/dist/view/attributes.d.ts +5 -0
  251. package/dist/view/attributes.js +5 -0
  252. package/dist/view/attributes.js.map +1 -1
  253. package/dist/view/compiled.d.ts +1 -1
  254. package/dist/view/compiled.js +1 -1
  255. package/dist/view/compiled.js.map +1 -1
  256. package/dist/view/index.d.ts +9 -4
  257. package/dist/view/index.js +9 -3
  258. package/dist/view/index.js.map +1 -1
  259. package/dist/view/loc.d.ts +9 -0
  260. package/dist/view/loc.js +50 -0
  261. package/dist/view/loc.js.map +1 -0
  262. package/dist/view/message.d.ts +17 -0
  263. package/dist/view/message.js +40 -0
  264. package/dist/view/message.js.map +1 -0
  265. package/dist/view/messages.d.ts +43 -0
  266. package/dist/view/messages.js +84 -0
  267. package/dist/view/messages.js.map +1 -0
  268. package/dist/view/normalize/check.d.ts +5 -2
  269. package/dist/view/normalize/check.js +6 -3
  270. package/dist/view/normalize/check.js.map +1 -1
  271. package/dist/view/normalize/emit.d.ts +2 -0
  272. package/dist/view/normalize/emit.js +40 -11
  273. package/dist/view/normalize/emit.js.map +1 -1
  274. package/dist/view/normalize/errors.js +1 -1
  275. package/dist/view/normalize/errors.js.map +1 -1
  276. package/dist/view/normalize/id.d.ts +5 -2
  277. package/dist/view/normalize/id.js +9 -2
  278. package/dist/view/normalize/id.js.map +1 -1
  279. package/dist/view/normalize/normalize.d.ts +7 -4
  280. package/dist/view/normalize/normalize.js +15 -9
  281. package/dist/view/normalize/normalize.js.map +1 -1
  282. package/dist/view/normalize/rules.d.ts +9 -0
  283. package/dist/view/normalize/rules.js +35 -5
  284. package/dist/view/normalize/rules.js.map +1 -1
  285. package/dist/view/normalize/svg.d.ts +14 -0
  286. package/dist/view/normalize/svg.js +40 -0
  287. package/dist/view/normalize/svg.js.map +1 -0
  288. package/dist/view/normalize/tokens.d.ts +5 -1
  289. package/dist/view/normalize/tokens.js.map +1 -1
  290. package/dist/view/normalize/tree.d.ts +8 -2
  291. package/dist/view/normalize/tree.js +58 -13
  292. package/dist/view/normalize/tree.js.map +1 -1
  293. package/dist/view/normalize/types.d.ts +24 -4
  294. package/dist/view/normalize/types.js +4 -1
  295. package/dist/view/normalize/types.js.map +1 -1
  296. package/dist/view/normalize/whitespace.js +4 -3
  297. package/dist/view/normalize/whitespace.js.map +1 -1
  298. package/dist/view/prepare-stub.js +2 -2
  299. package/dist/view/prepare-stub.js.map +1 -1
  300. package/dist/view/prepare.d.ts +5 -2
  301. package/dist/view/prepare.js +9 -3
  302. package/dist/view/prepare.js.map +1 -1
  303. package/dist/view/registry.d.ts +15 -0
  304. package/dist/view/registry.js +10 -2
  305. package/dist/view/registry.js.map +1 -1
  306. package/dist/view/render/adopt-attr.js +7 -1
  307. package/dist/view/render/adopt-attr.js.map +1 -1
  308. package/dist/view/render/adopt.js +21 -4
  309. package/dist/view/render/adopt.js.map +1 -1
  310. package/dist/view/render/attr-parts.d.ts +12 -1
  311. package/dist/view/render/attr-parts.js +38 -5
  312. package/dist/view/render/attr-parts.js.map +1 -1
  313. package/dist/view/render/child-part.js +5 -2
  314. package/dist/view/render/child-part.js.map +1 -1
  315. package/dist/view/render/dispose.d.ts +3 -0
  316. package/dist/view/render/dispose.js +76 -0
  317. package/dist/view/render/dispose.js.map +1 -0
  318. package/dist/view/render/hook-part.d.ts +3 -1
  319. package/dist/view/render/hook-part.js +21 -5
  320. package/dist/view/render/hook-part.js.map +1 -1
  321. package/dist/view/render/hook-run.d.ts +2 -0
  322. package/dist/view/render/hook-run.js +72 -0
  323. package/dist/view/render/hook-run.js.map +1 -0
  324. package/dist/view/render/hooks.d.ts +74 -6
  325. package/dist/view/render/hooks.js +79 -17
  326. package/dist/view/render/hooks.js.map +1 -1
  327. package/dist/view/render/hydrate.js +2 -2
  328. package/dist/view/render/hydrate.js.map +1 -1
  329. package/dist/view/render/keyed.d.ts +6 -0
  330. package/dist/view/render/keyed.js +15 -0
  331. package/dist/view/render/keyed.js.map +1 -0
  332. package/dist/view/render/list.d.ts +1 -1
  333. package/dist/view/render/list.js.map +1 -1
  334. package/dist/view/render/mismatch.js +5 -3
  335. package/dist/view/render/mismatch.js.map +1 -1
  336. package/dist/view/render/modal.d.ts +3 -0
  337. package/dist/view/render/modal.js +39 -0
  338. package/dist/view/render/modal.js.map +1 -0
  339. package/dist/view/render/raw.d.ts +4 -1
  340. package/dist/view/render/raw.js +6 -2
  341. package/dist/view/render/raw.js.map +1 -1
  342. package/dist/view/render/render.d.ts +4 -1
  343. package/dist/view/render/render.js +17 -12
  344. package/dist/view/render/render.js.map +1 -1
  345. package/dist/view/render/toggles.d.ts +6 -0
  346. package/dist/view/render/toggles.js +6 -0
  347. package/dist/view/render/toggles.js.map +1 -0
  348. package/dist/view/render/values.d.ts +1 -1
  349. package/dist/view/render/values.js.map +1 -1
  350. package/dist/view/render/warn.d.ts +14 -0
  351. package/dist/view/render/warn.js +45 -0
  352. package/dist/view/render/warn.js.map +1 -1
  353. package/dist/view/server/component.d.ts +6 -3
  354. package/dist/view/server/component.js +29 -7
  355. package/dist/view/server/component.js.map +1 -1
  356. package/dist/view/server/index.d.ts +20 -0
  357. package/dist/view/server/index.js +12 -4
  358. package/dist/view/server/index.js.map +1 -1
  359. package/dist/view/server/tags.d.ts +13 -2
  360. package/dist/view/server/tags.js +13 -2
  361. package/dist/view/server/tags.js.map +1 -1
  362. package/dist/view/server/values.d.ts +2 -0
  363. package/dist/view/server/values.js +8 -0
  364. package/dist/view/server/values.js.map +1 -1
  365. package/dist/view/server/writer.d.ts +9 -4
  366. package/dist/view/server/writer.js +33 -18
  367. package/dist/view/server/writer.js.map +1 -1
  368. package/dist/view/template-element.d.ts +7 -0
  369. package/dist/view/template-element.js +25 -5
  370. package/dist/view/template-element.js.map +1 -1
  371. package/dist/view/template.d.ts +9 -2
  372. package/dist/view/template.js +61 -8
  373. package/dist/view/template.js.map +1 -1
  374. package/dist/view/trusted-html.d.ts +6 -0
  375. package/dist/view/trusted-html.js +34 -0
  376. package/dist/view/trusted-html.js.map +1 -0
  377. package/dist/vite.d.ts +38 -31
  378. package/dist/vite.js +206 -31
  379. package/dist/vite.js.map +1 -1
  380. package/package.json +34 -3
  381. package/dist/hooks/labelled-by.d.ts +0 -13
  382. package/dist/hooks/labelled-by.js +0 -51
  383. package/dist/hooks/labelled-by.js.map +0 -1
  384. package/dist/random.d.ts +0 -13
  385. package/dist/random.js +0 -19
  386. package/dist/random.js.map +0 -1
@@ -3,7 +3,7 @@
3
3
  export const RULES_DOC = 'docs/design-docs/view/09-template-rules.md';
4
4
  /** Rule 11's message, here so the client's template cache needn't load the rule messages. */
5
5
  export const SERVER_ONLY = 'This template has document-level tags (<!doctype>, <html>, <head> or <body>): it is a page ' +
6
- 'shell, and only the server renders those. Render it with @gyral/core/server, and render ' +
6
+ 'shell, and only the server renders those. Render it with @gyral/ssr (renderPage, renderToString), and render ' +
7
7
  'components (not the page) in the browser.';
8
8
  /** A template breaks rule `rule` of view/09-template-rules.md. */
9
9
  export class TemplateError extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/view/normalize/errors.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,mFAAmF;AAEnF,MAAM,CAAC,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAEtE,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GACtB,6FAA6F;IAC7F,0FAA0F;IAC1F,2CAA2C,CAAC;AAE9C,kEAAkE;AAClE,MAAM,OAAO,aAAc,SAAQ,KAAK;IAItC,YAAY,IAAY,EAAE,OAAe,EAAE,GAAY,EAAE,IAAa;QACpE,MAAM,GAAG,GAAG,KAAK,SAAS,UAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACpD,MAAM,OAAO,GACX,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;QAC/F,KAAK,CAAC,wBAAwB,MAAM,CAAC,IAAI,CAAC,KAAK,OAAO,GAAG,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF","sourcesContent":["// TemplateError: what the template rules (view/09-template-rules.md) throw. Kept apart from the\n// rule checks so code that only needs the class (template-element.ts) stays small.\n\nexport const RULES_DOC = 'docs/design-docs/view/09-template-rules.md';\n\n/** Rule 11's message, here so the client's template cache needn't load the rule messages. */\nexport const SERVER_ONLY =\n 'This template has document-level tags (<!doctype>, <html>, <head> or <body>): it is a page ' +\n 'shell, and only the server renders those. Render it with @gyral/core/server, and render ' +\n 'components (not the page) in the browser.';\n\n/** A template breaks rule `rule` of view/09-template-rules.md. */\nexport class TemplateError extends Error {\n readonly rule: number;\n readonly loc: string | undefined;\n\n constructor(rule: number, message: string, loc?: string, near?: string) {\n const doc = ` (${RULES_DOC}, rule ${String(rule)})`;\n const context =\n (near === undefined ? '' : `\\n near: ${near}`) + (loc === undefined ? '' : `\\n at ${loc}`);\n super(`[gyral template rule ${String(rule)}] ${message}${doc}${context}`);\n this.name = 'TemplateError';\n this.rule = rule;\n this.loc = loc;\n }\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/view/normalize/errors.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,mFAAmF;AAEnF,MAAM,CAAC,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAEtE,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GACtB,6FAA6F;IAC7F,+GAA+G;IAC/G,2CAA2C,CAAC;AAE9C,kEAAkE;AAClE,MAAM,OAAO,aAAc,SAAQ,KAAK;IAItC,YAAY,IAAY,EAAE,OAAe,EAAE,GAAY,EAAE,IAAa;QACpE,MAAM,GAAG,GAAG,KAAK,SAAS,UAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACpD,MAAM,OAAO,GACX,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;QAC/F,KAAK,CAAC,wBAAwB,MAAM,CAAC,IAAI,CAAC,KAAK,OAAO,GAAG,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF","sourcesContent":["// TemplateError: what the template rules (view/09-template-rules.md) throw. Kept apart from the\n// rule checks so code that only needs the class (template-element.ts) stays small.\n\nexport const RULES_DOC = 'docs/design-docs/view/09-template-rules.md';\n\n/** Rule 11's message, here so the client's template cache needn't load the rule messages. */\nexport const SERVER_ONLY =\n 'This template has document-level tags (<!doctype>, <html>, <head> or <body>): it is a page ' +\n 'shell, and only the server renders those. Render it with @gyral/ssr (renderPage, renderToString), and render ' +\n 'components (not the page) in the browser.';\n\n/** A template breaks rule `rule` of view/09-template-rules.md. */\nexport class TemplateError extends Error {\n readonly rule: number;\n readonly loc: string | undefined;\n\n constructor(rule: number, message: string, loc?: string, near?: string) {\n const doc = ` (${RULES_DOC}, rule ${String(rule)})`;\n const context =\n (near === undefined ? '' : `\\n near: ${near}`) + (loc === undefined ? '' : `\\n at ${loc}`);\n super(`[gyral template rule ${String(rule)}] ${message}${doc}${context}`);\n this.name = 'TemplateError';\n this.rule = rule;\n this.loc = loc;\n }\n}\n"]}
@@ -1,5 +1,8 @@
1
- /** The id of a template's normalized strings. */
2
- export declare function templateId(strings: readonly string[]): string;
1
+ /**
2
+ * The id of a template's normalized strings. `svg`: an svg template's (01 "svg templates"),
3
+ * whose DOM differs from an html template's with the same strings, so its id does too.
4
+ */
5
+ export declare function templateId(strings: readonly string[], svg?: boolean): string;
3
6
  /**
4
7
  * Development: records `id` → strings and warns once when two different normalized templates
5
8
  * share an id (the compiler fails the build instead).
@@ -11,10 +11,17 @@ function avalanche(h, a, b) {
11
11
  x = Math.imul(x ^ (x >>> 13), b);
12
12
  return x ^ (x >>> 16);
13
13
  }
14
- /** The id of a template's normalized strings. */
15
- export function templateId(strings) {
14
+ /**
15
+ * The id of a template's normalized strings. `svg`: an svg template's (01 "svg templates"),
16
+ * whose DOM differs from an html template's with the same strings, so its id does too.
17
+ */
18
+ export function templateId(strings, svg = false) {
16
19
  let h1 = 0x9e3779b9 ^ strings.length;
17
20
  let h2 = 0x85ebca6b ^ strings.length;
21
+ if (svg) {
22
+ h1 = mix(h1, 0x737667, 0x2d51);
23
+ h2 = mix(h2, 0x737667, 0x1b873593);
24
+ }
18
25
  for (const s of strings) {
19
26
  h1 = mix(h1, s.length, 0x2d51);
20
27
  h2 = mix(h2, s.length, 0x1b873593);
@@ -1 +1 @@
1
- {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/view/normalize/id.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,8FAA8F;AAC9F,2FAA2F;AAC3F,8FAA8F;AAC9F,mEAAmE;AAEnE,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,SAAS,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS;IAChD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,IAAI,EAAE,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1B,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;YAC5B,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IACnF,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IACjE,OAAO,CAAC,EAAE,GAAG,WAAW,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU,EAAE,OAA0B;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3B,IAAI,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;SACtC,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CACV,+CAA+C,EAAE,oCAAoC;YACnF,gFAAgF;YAChF,iBAAiB,KAAK,OAAO,GAAG,EAAE,CACrC,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACpB,CAAC;AACH,CAAC","sourcesContent":["// Template ids (view/01-templates.md \"Template ids\"): a deterministic 53-bit hash of the\n// normalized strings, printed in base 36. Two independent 32-bit multiply-xorshift lanes over\n// the UTF-16 code units, with each string's length mixed in first so [\"a\", \"b\"] and [\"ab\"]\n// differ; a final avalanche, then 21 bits of one lane and 32 of the other. Only Math.imul and\n// integer ops: the same result in Node, browsers and the compiler.\n\nfunction mix(h: number, k: number, m: number): number {\n return Math.imul(h ^ k, m);\n}\n\nfunction avalanche(h: number, a: number, b: number): number {\n let x = Math.imul(h ^ (h >>> 16), a);\n x = Math.imul(x ^ (x >>> 13), b);\n return x ^ (x >>> 16);\n}\n\n/** The id of a template's normalized strings. */\nexport function templateId(strings: readonly string[]): string {\n let h1 = 0x9e3779b9 ^ strings.length;\n let h2 = 0x85ebca6b ^ strings.length;\n for (const s of strings) {\n h1 = mix(h1, s.length, 0x2d51);\n h2 = mix(h2, s.length, 0x1b873593);\n for (let k = 0; k < s.length; k++) {\n const c = s.charCodeAt(k);\n h1 = mix(h1, c, 0x9e3779b1);\n h2 = mix(h2, c, 0x5bd1e995);\n }\n }\n const lo = avalanche(h1 ^ Math.imul(h2, 0x27d4eb2f), 0x85ebca6b, 0xc2b2ae35) >>> 0;\n const hi = avalanche(h2 ^ lo, 0x2c1b3c6d, 0x297a2d39) & 0x1fffff;\n return (hi * 0x100000000 + lo).toString(36);\n}\n\nconst seen = new Map<string, string>();\n\n/**\n * Development: records `id` → strings and warns once when two different normalized templates\n * share an id (the compiler fails the build instead).\n */\nexport function recordTemplateId(id: string, strings: readonly string[]): void {\n const key = JSON.stringify(strings);\n const known = seen.get(id);\n if (known === undefined) seen.set(id, key);\n else if (known !== key) {\n console.warn(\n `gyral: two different templates share the id ${id}; server output and hydration may ` +\n `confuse them. Change one template slightly (e.g. add a class) and report this ` +\n `collision.\\n ${known}\\n ${key}`,\n );\n seen.set(id, key);\n }\n}\n"]}
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/view/normalize/id.ts"],"names":[],"mappings":"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","sourcesContent":["// Template ids (view/01-templates.md \"Template ids\"): a deterministic 53-bit hash of the\n// normalized strings, printed in base 36. Two independent 32-bit multiply-xorshift lanes over\n// the UTF-16 code units, with each string's length mixed in first so [\"a\", \"b\"] and [\"ab\"]\n// differ; a final avalanche, then 21 bits of one lane and 32 of the other. Only Math.imul and\n// integer ops: the same result in Node, browsers and the compiler.\n\nfunction mix(h: number, k: number, m: number): number {\n return Math.imul(h ^ k, m);\n}\n\nfunction avalanche(h: number, a: number, b: number): number {\n let x = Math.imul(h ^ (h >>> 16), a);\n x = Math.imul(x ^ (x >>> 13), b);\n return x ^ (x >>> 16);\n}\n\n/**\n * The id of a template's normalized strings. `svg`: an svg template's (01 \"svg templates\"),\n * whose DOM differs from an html template's with the same strings, so its id does too.\n */\nexport function templateId(strings: readonly string[], svg = false): string {\n let h1 = 0x9e3779b9 ^ strings.length;\n let h2 = 0x85ebca6b ^ strings.length;\n if (svg) {\n h1 = mix(h1, 0x737667, 0x2d51);\n h2 = mix(h2, 0x737667, 0x1b873593);\n }\n for (const s of strings) {\n h1 = mix(h1, s.length, 0x2d51);\n h2 = mix(h2, s.length, 0x1b873593);\n for (let k = 0; k < s.length; k++) {\n const c = s.charCodeAt(k);\n h1 = mix(h1, c, 0x9e3779b1);\n h2 = mix(h2, c, 0x5bd1e995);\n }\n }\n const lo = avalanche(h1 ^ Math.imul(h2, 0x27d4eb2f), 0x85ebca6b, 0xc2b2ae35) >>> 0;\n const hi = avalanche(h2 ^ lo, 0x2c1b3c6d, 0x297a2d39) & 0x1fffff;\n return (hi * 0x100000000 + lo).toString(36);\n}\n\nconst seen = new Map<string, string>();\n\n/**\n * Development: records `id` → strings and warns once when two different normalized templates\n * share an id (the compiler fails the build instead).\n */\nexport function recordTemplateId(id: string, strings: readonly string[]): void {\n const key = JSON.stringify(strings);\n const known = seen.get(id);\n if (known === undefined) seen.set(id, key);\n else if (known !== key) {\n console.warn(\n `gyral: two different templates share the id ${id}; server output and hydration may ` +\n `confuse them. Change one template slightly (e.g. add a class) and report this ` +\n `collision.\\n ${known}\\n ${key}`,\n );\n seen.set(id, key);\n }\n}\n"]}
@@ -6,10 +6,13 @@ export interface Analysis {
6
6
  /** The DOM the browser must build from `template.html` (checked by the runtime preparer). */
7
7
  readonly shape: Shape;
8
8
  }
9
- /** The template object plus what the runtime preparer checks it against. */
10
- export declare function analyze(strings: readonly string[], loc?: string): Analysis;
9
+ /**
10
+ * The template object plus what the runtime preparer checks it against. `svg`: the strings are
11
+ * an svg template's (`` svg`…` ``), whose top level is SVG content.
12
+ */
13
+ export declare function analyze(strings: readonly string[], loc?: string, svg?: boolean): Analysis;
11
14
  /**
12
15
  * Normalizes a template's static strings into its template object (JSON data). Throws a
13
- * TemplateError for markup that breaks a template rule.
16
+ * TemplateError for markup that breaks a template rule. `svg`: an svg template's strings.
14
17
  */
15
- export declare function normalize(strings: readonly string[], loc?: string): NormalizedTemplate;
18
+ export declare function normalize(strings: readonly string[], loc?: string, svg?: boolean): NormalizedTemplate;
@@ -2,35 +2,41 @@
2
2
  // static strings to its template object, shared by the Vite compiler, the browser's runtime
3
3
  // preparer and the server renderer. Steps: minify whitespace (holes never move), tokenize and
4
4
  // build the tree (rules of view/09-template-rules.md), emit HTML, segments and parts, and hash
5
- // the normalized strings into the id. No DOM: it runs in Node and in the browser.
5
+ // the normalized strings into the id. No DOM: it runs in Node and in the browser. An svg
6
+ // template (01 "svg templates") is built as SVG content from its top level, and is flagged.
6
7
  import { emit } from './emit.js';
7
8
  import { templateId } from './id.js';
8
9
  import { Source } from './source.js';
9
10
  import { tokenize } from './tokenizer.js';
10
11
  import { TreeBuilder } from './tree.js';
11
12
  import { minifyStrings } from './whitespace.js';
12
- /** The template object plus what the runtime preparer checks it against. */
13
- export function analyze(strings, loc) {
13
+ /**
14
+ * The template object plus what the runtime preparer checks it against. `svg`: the strings are
15
+ * an svg template's (`` svg`…` ``), whose top level is SVG content.
16
+ */
17
+ export function analyze(strings, loc, svg = false) {
14
18
  const normalized = minifyStrings(strings);
15
19
  const src = new Source(normalized, loc);
16
- const tree = new TreeBuilder(src);
20
+ const tree = new TreeBuilder(src, svg);
17
21
  tokenize(src, tree);
18
- const { html, parts, segments, shape } = emit(tree.root, tree.server);
22
+ const { html, parts, segments, shape, staticStyles } = emit(tree.root, tree.server);
19
23
  const template = {
20
- id: templateId(normalized),
24
+ id: templateId(normalized, svg),
21
25
  html,
22
26
  parts,
23
27
  ...(tree.server ? { server: true } : {}),
28
+ ...(svg ? { svg: true } : {}),
24
29
  segments,
30
+ ...(staticStyles.length === 0 ? {} : { staticStyles }),
25
31
  ...(loc === undefined ? {} : { loc }),
26
32
  };
27
33
  return { template, strings: normalized, shape };
28
34
  }
29
35
  /**
30
36
  * Normalizes a template's static strings into its template object (JSON data). Throws a
31
- * TemplateError for markup that breaks a template rule.
37
+ * TemplateError for markup that breaks a template rule. `svg`: an svg template's strings.
32
38
  */
33
- export function normalize(strings, loc) {
34
- return analyze(strings, loc).template;
39
+ export function normalize(strings, loc, svg = false) {
40
+ return analyze(strings, loc, svg).template;
35
41
  }
36
42
  //# sourceMappingURL=normalize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../src/view/normalize/normalize.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,kFAAkF;AAClF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD,4EAA4E;AAC5E,MAAM,UAAU,OAAO,CAAC,OAA0B,EAAE,GAAY;IAC9D,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAuB;QACnC,EAAE,EAAE,UAAU,CAAC,UAAU,CAAC;QAC1B,IAAI;QACJ,KAAK;QACL,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,QAAQ;QACR,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;KACtC,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAA0B,EAAE,GAAY;IAChE,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC;AACxC,CAAC","sourcesContent":["// The normalizer (view/01-templates.md \"Normalization\"): one pure function from a call site's\n// static strings to its template object, shared by the Vite compiler, the browser's runtime\n// preparer and the server renderer. Steps: minify whitespace (holes never move), tokenize and\n// build the tree (rules of view/09-template-rules.md), emit HTML, segments and parts, and hash\n// the normalized strings into the id. No DOM: it runs in Node and in the browser.\nimport { emit } from './emit.js';\nimport { templateId } from './id.js';\nimport { Source } from './source.js';\nimport { tokenize } from './tokenizer.js';\nimport { TreeBuilder } from './tree.js';\nimport type { NormalizedTemplate, Shape } from './types.js';\nimport { minifyStrings } from './whitespace.js';\n\nexport interface Analysis {\n readonly template: NormalizedTemplate;\n /** The whitespace-normalized strings the id was computed from. */\n readonly strings: readonly string[];\n /** The DOM the browser must build from `template.html` (checked by the runtime preparer). */\n readonly shape: Shape;\n}\n\n/** The template object plus what the runtime preparer checks it against. */\nexport function analyze(strings: readonly string[], loc?: string): Analysis {\n const normalized = minifyStrings(strings);\n const src = new Source(normalized, loc);\n const tree = new TreeBuilder(src);\n tokenize(src, tree);\n const { html, parts, segments, shape } = emit(tree.root, tree.server);\n const template: NormalizedTemplate = {\n id: templateId(normalized),\n html,\n parts,\n ...(tree.server ? { server: true as const } : {}),\n segments,\n ...(loc === undefined ? {} : { loc }),\n };\n return { template, strings: normalized, shape };\n}\n\n/**\n * Normalizes a template's static strings into its template object (JSON data). Throws a\n * TemplateError for markup that breaks a template rule.\n */\nexport function normalize(strings: readonly string[], loc?: string): NormalizedTemplate {\n return analyze(strings, loc).template;\n}\n"]}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../src/view/normalize/normalize.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,yFAAyF;AACzF,4FAA4F;AAC5F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,OAA0B,EAAE,GAAY,EAAE,GAAG,GAAG,KAAK;IAC3E,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpF,MAAM,QAAQ,GAAuB;QACnC,EAAE,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC;QAC/B,IAAI;QACJ,KAAK;QACL,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,QAAQ;QACR,GAAG,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;QACtD,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;KACtC,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CACvB,OAA0B,EAC1B,GAAY,EACZ,GAAG,GAAG,KAAK;IAEX,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC7C,CAAC","sourcesContent":["// The normalizer (view/01-templates.md \"Normalization\"): one pure function from a call site's\n// static strings to its template object, shared by the Vite compiler, the browser's runtime\n// preparer and the server renderer. Steps: minify whitespace (holes never move), tokenize and\n// build the tree (rules of view/09-template-rules.md), emit HTML, segments and parts, and hash\n// the normalized strings into the id. No DOM: it runs in Node and in the browser. An svg\n// template (01 \"svg templates\") is built as SVG content from its top level, and is flagged.\nimport { emit } from './emit.js';\nimport { templateId } from './id.js';\nimport { Source } from './source.js';\nimport { tokenize } from './tokenizer.js';\nimport { TreeBuilder } from './tree.js';\nimport type { NormalizedTemplate, Shape } from './types.js';\nimport { minifyStrings } from './whitespace.js';\n\nexport interface Analysis {\n readonly template: NormalizedTemplate;\n /** The whitespace-normalized strings the id was computed from. */\n readonly strings: readonly string[];\n /** The DOM the browser must build from `template.html` (checked by the runtime preparer). */\n readonly shape: Shape;\n}\n\n/**\n * The template object plus what the runtime preparer checks it against. `svg`: the strings are\n * an svg template's (`` svg`…` ``), whose top level is SVG content.\n */\nexport function analyze(strings: readonly string[], loc?: string, svg = false): Analysis {\n const normalized = minifyStrings(strings);\n const src = new Source(normalized, loc);\n const tree = new TreeBuilder(src, svg);\n tokenize(src, tree);\n const { html, parts, segments, shape, staticStyles } = emit(tree.root, tree.server);\n const template: NormalizedTemplate = {\n id: templateId(normalized, svg),\n html,\n parts,\n ...(tree.server ? { server: true as const } : {}),\n ...(svg ? { svg: true as const } : {}),\n segments,\n ...(staticStyles.length === 0 ? {} : { staticStyles }),\n ...(loc === undefined ? {} : { loc }),\n };\n return { template, strings: normalized, shape };\n}\n\n/**\n * Normalizes a template's static strings into its template object (JSON data). Throws a\n * TemplateError for markup that breaks a template rule. `svg`: an svg template's strings.\n */\nexport function normalize(\n strings: readonly string[],\n loc?: string,\n svg = false,\n): NormalizedTemplate {\n return analyze(strings, loc, svg).template;\n}\n"]}
@@ -8,6 +8,7 @@ export declare const msg: {
8
8
  inDoctype: () => string;
9
9
  inTemplate: () => string;
10
10
  formState: (tag: string, name: string, write: string) => string;
11
+ toggle: (tag: string, name: string) => string;
11
12
  unquoted: (name: string) => string;
12
13
  notSingle: (name: string) => string;
13
14
  selfClosing: (tag: string) => string;
@@ -15,8 +16,11 @@ export declare const msg: {
15
16
  badEndTag: () => string;
16
17
  unterminated: (what: "comment" | "tag") => string;
17
18
  svgOnly: (tag: string) => string;
19
+ htmlInSvg: (tag: string, top: boolean) => string;
20
+ namespacedAttr: (name: string) => string;
18
21
  serverOnly: () => string;
19
22
  textContent: (tag: string) => string;
23
+ booleanAttr: (tag: string, name: string) => string;
20
24
  charRef: (ref: string) => string;
21
25
  };
22
26
  /**
@@ -24,6 +28,11 @@ export declare const msg: {
24
28
  * Returns the spelling to use instead, or undefined when the binding is fine.
25
29
  */
26
30
  export declare function formStateFix(tag: string, name: string): string | undefined;
31
+ /**
32
+ * Rule 14: HTML boolean attributes (present means true). `hidden` is left out because
33
+ * hidden="until-found" is a real string value.
34
+ */
35
+ export declare const BOOLEAN_ATTRS: Set<string>;
27
36
  /** Rule 10: SVG element names that HTML doesn't share (lower case). */
28
37
  export declare const SVG_ONLY: Set<string>;
29
38
  /** HTML void elements: no end tag, no content. */
@@ -30,6 +30,13 @@ export const msg = {
30
30
  formState: (tag, name, write) => `.${name}=${H} on <${tag}> binds form state as a property, which never reaches the ` +
31
31
  `server and has a second spelling. Write ${write} instead: Gyral keeps it live ` +
32
32
  `(view/02-bindings.md, "Live form state").`,
33
+ toggle: (tag, name) => name === 'modal'
34
+ ? `modal on <${tag}>: only a <dialog> opens as a modal, and only from ?modal=${H}, which ` +
35
+ `calls showModal() and close() as the value changes (view/02-bindings.md, "Dialogs and ` +
36
+ `popovers"). Write <dialog ?modal=${H}>.`
37
+ : `popover-open on <${tag}>: write ?popover-open=${H} on an element with a popover ` +
38
+ `attribute; it calls showPopover() and hidePopover() as the value changes ` +
39
+ `(view/02-bindings.md, "Dialogs and popovers").`,
33
40
  // 5
34
41
  unquoted: (name) => `${name}=… mixes static text and holes without quotes, which is ambiguous. Quote the ` +
35
42
  `whole value: ${name}="a ${H}".`,
@@ -46,14 +53,29 @@ export const msg = {
46
53
  ? `The template ends inside a comment or <!…> declaration. Close it with -->.`
47
54
  : `The template ends inside a tag, so the parser would drop it. Close the tag with ">".`,
48
55
  // 10
49
- svgOnly: (tag) => `<${tag}> is an SVG element outside an <svg>: there is no svg tag, and the HTML parser ` +
50
- `creates SVG elements only inside <svg>. Wrap it: <svg viewBox="…"><${tag} …></${tag}></svg>.`,
56
+ svgOnly: (tag) => `<${tag}> is an SVG element outside an <svg>: in an html template the parser creates SVG ` +
57
+ `elements only inside <svg>. For an SVG fragment of its own, write it with the svg tag ` +
58
+ `(import { svg } from '@gyral/core'): svg\`<${tag} …></${tag}>\`, rendered inside an <svg>. ` +
59
+ `Or wrap it: <svg viewBox="…"><${tag} …></${tag}></svg>.`,
60
+ htmlInSvg: (tag, top) => (top
61
+ ? `<${tag}> is HTML, but this is an svg template: its top level is SVG content (it renders ` +
62
+ `inside an <svg>), where the parser `
63
+ : `<${tag}> is an HTML element inside SVG content, where the parser `) +
64
+ `would not create an HTML <${tag}>. Write HTML with html\`…\`, or put it inside ` +
65
+ `<foreignObject>.`,
66
+ namespacedAttr: (name) => `${name}=${H} binds a namespaced attribute: the parser puts ${name} in its own namespace, ` +
67
+ `and a bound value can't be. Bind the plain attribute instead (SVG 2): href=${H} for ` +
68
+ `xlink:href, lang=${H} for xml:lang; write xmlns statically, if at all.`,
51
69
  // 11
52
70
  serverOnly: () => SERVER_ONLY,
53
- // 12 (proposed)
71
+ // 12
54
72
  textContent: (tag) => `A hole in <${tag}> must be its whole content. Write <${tag}>${H}</${tag}> and build the ` +
55
73
  `text in the value: <${tag}>\${\`\${page} | Site\`}</${tag}>.`,
56
- // 13 (proposed)
74
+ // 14
75
+ booleanAttr: (tag, name) => `${name}=${H} on <${tag}> sets a boolean attribute to a string: any value, even "false", ` +
76
+ `turns it on. Write ?${name}=${H} to add the attribute when the value is truthy and ` +
77
+ `remove it otherwise.`,
78
+ // 13
57
79
  charRef: (ref) => `&${ref}; in the static text of a bound or custom-element attribute is a named character ` +
58
80
  `reference the normalizer doesn't decode (it knows &amp; &lt; &gt; &quot; &apos; &nbsp;). ` +
59
81
  `Write the character itself, or a numeric reference such as &#169;.`,
@@ -68,7 +90,7 @@ const FORM_STATE = {
68
90
  select: { value: `?selected=${H} on the chosen <option>` },
69
91
  option: { selected: `?selected=${H}`, value: `value=${H}` },
70
92
  details: { open: `?open=${H}` },
71
- dialog: { open: `?open=${H}` },
93
+ dialog: { open: `?open=${H}`, modal: `?modal=${H}` },
72
94
  };
73
95
  /**
74
96
  * Rule 4: property bindings that would be form state (view/02-bindings.md "Live form state").
@@ -77,6 +99,14 @@ const FORM_STATE = {
77
99
  export function formStateFix(tag, name) {
78
100
  return FORM_STATE[tag]?.[name];
79
101
  }
102
+ /**
103
+ * Rule 14: HTML boolean attributes (present means true). `hidden` is left out because
104
+ * hidden="until-found" is a real string value.
105
+ */
106
+ export const BOOLEAN_ATTRS = new Set(('allowfullscreen async autofocus autoplay checked controls default defer disabled ' +
107
+ 'disablepictureinpicture disableremoteplayback formnovalidate inert ismap itemscope loop ' +
108
+ 'multiple muted nomodule novalidate open playsinline readonly required reversed selected ' +
109
+ 'shadowrootclonable shadowrootdelegatesfocus shadowrootserializable').split(' '));
80
110
  /** Rule 10: SVG element names that HTML doesn't share (lower case). */
81
111
  export const SVG_ONLY = new Set(('animate animatemotion animatetransform circle clippath defs desc ellipse feblend ' +
82
112
  'fecolormatrix fecomponenttransfer fecomposite feconvolvematrix fediffuselighting ' +
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/view/normalize/rules.ts"],"names":[],"mappings":"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","sourcesContent":["// The template rules of view/09-template-rules.md that one template's strings reveal: every\n// message says what is wrong and what to write instead (core belief 7). The tokenizer\n// (rules 1, 2, 3, 5), the tree builder (3, 4, 6, 7, 10, 12, 13) and repairs.ts (7) throw them\n// through Source.fail; the browser's own parse (prepare.ts) backs rule 7 up, and\n// template-element.ts throws rule 11 when a server template reaches the browser.\n\nimport { SERVER_ONLY } from './errors.js';\n\nconst H = '${…}';\n\n/** Messages, by rule. Each names the fix. */\nexport const msg = {\n // 1\n eventBinding: (name: string): string =>\n `${name}=${H} is an event binding, and Gyral has none: views never attach listeners. ` +\n `Name the intent instead, data-intent=\\${i.Name}, and parse the event in the component's ` +\n `intent (ADR 0001).`,\n // 2\n dynamicTag: (): string =>\n `A hole can't be (part of) a tag name: <${H}> and </${H}> are not supported. Choose ` +\n `between whole templates instead: \\${cond ? html\\`<a>…</a>\\` : html\\`<b>…</b>\\`}. ` +\n `For a literal \"<\" next to a value, write &lt;.`,\n dynamicName: (): string =>\n `A hole can't be (part of) an attribute name. Write the name statically (name=${H}), ` +\n `use ?name=${H} to add or remove it, or choose between whole templates.`,\n // 3\n inRawText: (tag: string): string =>\n `A hole can't sit inside <${tag}>: no part can live there, and values in it are an ` +\n `injection risk. Pass data through an attribute, styles through a CSS custom property ` +\n `(style=\\${\\`--x: \\${v}\\`}), or trusted markup through raw().`,\n inComment: (): string =>\n `A hole can't sit inside an HTML comment: no part can live there. Move the value out of ` +\n `the comment, or drop the comment.`,\n inDoctype: (): string =>\n `A hole can't sit inside <!doctype>. Write the doctype statically: <!doctype html>.`,\n inTemplate: (): string =>\n `A hole can't sit inside a <template> element: its content is inert and no part can live ` +\n `there. Render the content with a nested html\\`…\\` template in a child hole instead.`,\n // 4\n formState: (tag: string, name: string, write: string): string =>\n `.${name}=${H} on <${tag}> binds form state as a property, which never reaches the ` +\n `server and has a second spelling. Write ${write} instead: Gyral keeps it live ` +\n `(view/02-bindings.md, \"Live form state\").`,\n // 5\n unquoted: (name: string): string =>\n `${name}=… mixes static text and holes without quotes, which is ambiguous. Quote the ` +\n `whole value: ${name}=\"a ${H}\".`,\n notSingle: (name: string): string =>\n `${name} takes exactly one value and no static text. Write ${name}=${H}, and build the ` +\n `value in the expression.`,\n // 6\n selfClosing: (tag: string): string =>\n `<${tag} /> is not self-closing in HTML: the parser ignores the \"/\", so <${tag}> would ` +\n `swallow the siblings that follow it. Write <${tag}></${tag}>.`,\n // 7\n repaired: (what: string, write: string): string =>\n `${what}. The HTML parser repairs this markup, so the DOM would differ from the template ` +\n `and part paths would shift. ${write}`,\n badEndTag: (): string =>\n `\"</\" must start an end tag such as </p>. For a literal \"</\" in text, write &lt;/.`,\n unterminated: (what: 'comment' | 'tag'): string =>\n what === 'comment'\n ? `The template ends inside a comment or <!…> declaration. Close it with -->.`\n : `The template ends inside a tag, so the parser would drop it. Close the tag with \">\".`,\n // 10\n svgOnly: (tag: string): string =>\n `<${tag}> is an SVG element outside an <svg>: there is no svg tag, and the HTML parser ` +\n `creates SVG elements only inside <svg>. Wrap it: <svg viewBox=\"…\"><${tag} …></${tag}></svg>.`,\n // 11\n serverOnly: (): string => SERVER_ONLY,\n // 12 (proposed)\n textContent: (tag: string): string =>\n `A hole in <${tag}> must be its whole content. Write <${tag}>${H}</${tag}> and build the ` +\n `text in the value: <${tag}>\\${\\`\\${page} | Site\\`}</${tag}>.`,\n // 13 (proposed)\n charRef: (ref: string): string =>\n `&${ref}; in the static text of a bound or custom-element attribute is a named character ` +\n `reference the normalizer doesn't decode (it knows &amp; &lt; &gt; &quot; &apos; &nbsp;). ` +\n `Write the character itself, or a numeric reference such as &#169;.`,\n};\n\n/**\n * Rule 4: property bindings that would be form state (view/02-bindings.md \"Live form state\").\n * Returns the spelling to use instead, or undefined when the binding is fine.\n */\nconst FORM_STATE: Record<string, Record<string, string> | undefined> = {\n input: { value: `value=${H}`, checked: `?checked=${H}`, indeterminate: `?indeterminate=${H}` },\n textarea: { value: `<textarea>${H}</textarea>` },\n select: { value: `?selected=${H} on the chosen <option>` },\n option: { selected: `?selected=${H}`, value: `value=${H}` },\n details: { open: `?open=${H}` },\n dialog: { open: `?open=${H}` },\n};\n\n/**\n * Rule 4: property bindings that would be form state (view/02-bindings.md \"Live form state\").\n * Returns the spelling to use instead, or undefined when the binding is fine.\n */\nexport function formStateFix(tag: string, name: string): string | undefined {\n return FORM_STATE[tag]?.[name];\n}\n\n/** Rule 10: SVG element names that HTML doesn't share (lower case). */\nexport const SVG_ONLY = new Set(\n (\n 'animate animatemotion animatetransform circle clippath defs desc ellipse feblend ' +\n 'fecolormatrix fecomponenttransfer fecomposite feconvolvematrix fediffuselighting ' +\n 'fedisplacementmap fedropshadow feflood fegaussianblur feimage femerge femergenode ' +\n 'femorphology feoffset fespecularlighting fetile feturbulence filter foreignobject g line ' +\n 'lineargradient marker mask metadata mpath path pattern polygon polyline radialgradient ' +\n 'rect stop symbol text textpath tspan use'\n ).split(' '),\n);\n\n/** HTML void elements: no end tag, no content. */\nexport const VOID = new Set(\n (\n 'area base basefont bgsound br col embed frame hr img input keygen link meta param source ' +\n 'track wbr'\n ).split(' '),\n);\n"]}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/view/normalize/rules.ts"],"names":[],"mappings":"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","sourcesContent":["// The template rules of view/09-template-rules.md that one template's strings reveal: every\n// message says what is wrong and what to write instead (core belief 7). The tokenizer\n// (rules 1, 2, 3, 5), the tree builder (3, 4, 6, 7, 10, 12, 13) and repairs.ts (7) throw them\n// through Source.fail; the browser's own parse (prepare.ts) backs rule 7 up, and\n// template-element.ts throws rule 11 when a server template reaches the browser.\n\nimport { SERVER_ONLY } from './errors.js';\n\nconst H = '${…}';\n\n/** Messages, by rule. Each names the fix. */\nexport const msg = {\n // 1\n eventBinding: (name: string): string =>\n `${name}=${H} is an event binding, and Gyral has none: views never attach listeners. ` +\n `Name the intent instead, data-intent=\\${i.Name}, and parse the event in the component's ` +\n `intent (ADR 0001).`,\n // 2\n dynamicTag: (): string =>\n `A hole can't be (part of) a tag name: <${H}> and </${H}> are not supported. Choose ` +\n `between whole templates instead: \\${cond ? html\\`<a>…</a>\\` : html\\`<b>…</b>\\`}. ` +\n `For a literal \"<\" next to a value, write &lt;.`,\n dynamicName: (): string =>\n `A hole can't be (part of) an attribute name. Write the name statically (name=${H}), ` +\n `use ?name=${H} to add or remove it, or choose between whole templates.`,\n // 3\n inRawText: (tag: string): string =>\n `A hole can't sit inside <${tag}>: no part can live there, and values in it are an ` +\n `injection risk. Pass data through an attribute, styles through a CSS custom property ` +\n `(style=\\${\\`--x: \\${v}\\`}), or trusted markup through raw().`,\n inComment: (): string =>\n `A hole can't sit inside an HTML comment: no part can live there. Move the value out of ` +\n `the comment, or drop the comment.`,\n inDoctype: (): string =>\n `A hole can't sit inside <!doctype>. Write the doctype statically: <!doctype html>.`,\n inTemplate: (): string =>\n `A hole can't sit inside a <template> element: its content is inert and no part can live ` +\n `there. Render the content with a nested html\\`…\\` template in a child hole instead.`,\n // 4\n formState: (tag: string, name: string, write: string): string =>\n `.${name}=${H} on <${tag}> binds form state as a property, which never reaches the ` +\n `server and has a second spelling. Write ${write} instead: Gyral keeps it live ` +\n `(view/02-bindings.md, \"Live form state\").`,\n toggle: (tag: string, name: string): string =>\n name === 'modal'\n ? `modal on <${tag}>: only a <dialog> opens as a modal, and only from ?modal=${H}, which ` +\n `calls showModal() and close() as the value changes (view/02-bindings.md, \"Dialogs and ` +\n `popovers\"). Write <dialog ?modal=${H}>.`\n : `popover-open on <${tag}>: write ?popover-open=${H} on an element with a popover ` +\n `attribute; it calls showPopover() and hidePopover() as the value changes ` +\n `(view/02-bindings.md, \"Dialogs and popovers\").`,\n // 5\n unquoted: (name: string): string =>\n `${name}=… mixes static text and holes without quotes, which is ambiguous. Quote the ` +\n `whole value: ${name}=\"a ${H}\".`,\n notSingle: (name: string): string =>\n `${name} takes exactly one value and no static text. Write ${name}=${H}, and build the ` +\n `value in the expression.`,\n // 6\n selfClosing: (tag: string): string =>\n `<${tag} /> is not self-closing in HTML: the parser ignores the \"/\", so <${tag}> would ` +\n `swallow the siblings that follow it. Write <${tag}></${tag}>.`,\n // 7\n repaired: (what: string, write: string): string =>\n `${what}. The HTML parser repairs this markup, so the DOM would differ from the template ` +\n `and part paths would shift. ${write}`,\n badEndTag: (): string =>\n `\"</\" must start an end tag such as </p>. For a literal \"</\" in text, write &lt;/.`,\n unterminated: (what: 'comment' | 'tag'): string =>\n what === 'comment'\n ? `The template ends inside a comment or <!…> declaration. Close it with -->.`\n : `The template ends inside a tag, so the parser would drop it. Close the tag with \">\".`,\n // 10\n svgOnly: (tag: string): string =>\n `<${tag}> is an SVG element outside an <svg>: in an html template the parser creates SVG ` +\n `elements only inside <svg>. For an SVG fragment of its own, write it with the svg tag ` +\n `(import { svg } from '@gyral/core'): svg\\`<${tag} …></${tag}>\\`, rendered inside an <svg>. ` +\n `Or wrap it: <svg viewBox=\"…\"><${tag} …></${tag}></svg>.`,\n htmlInSvg: (tag: string, top: boolean): string =>\n (top\n ? `<${tag}> is HTML, but this is an svg template: its top level is SVG content (it renders ` +\n `inside an <svg>), where the parser `\n : `<${tag}> is an HTML element inside SVG content, where the parser `) +\n `would not create an HTML <${tag}>. Write HTML with html\\`…\\`, or put it inside ` +\n `<foreignObject>.`,\n namespacedAttr: (name: string): string =>\n `${name}=${H} binds a namespaced attribute: the parser puts ${name} in its own namespace, ` +\n `and a bound value can't be. Bind the plain attribute instead (SVG 2): href=${H} for ` +\n `xlink:href, lang=${H} for xml:lang; write xmlns statically, if at all.`,\n // 11\n serverOnly: (): string => SERVER_ONLY,\n // 12\n textContent: (tag: string): string =>\n `A hole in <${tag}> must be its whole content. Write <${tag}>${H}</${tag}> and build the ` +\n `text in the value: <${tag}>\\${\\`\\${page} | Site\\`}</${tag}>.`,\n // 14\n booleanAttr: (tag: string, name: string): string =>\n `${name}=${H} on <${tag}> sets a boolean attribute to a string: any value, even \"false\", ` +\n `turns it on. Write ?${name}=${H} to add the attribute when the value is truthy and ` +\n `remove it otherwise.`,\n // 13\n charRef: (ref: string): string =>\n `&${ref}; in the static text of a bound or custom-element attribute is a named character ` +\n `reference the normalizer doesn't decode (it knows &amp; &lt; &gt; &quot; &apos; &nbsp;). ` +\n `Write the character itself, or a numeric reference such as &#169;.`,\n};\n\n/**\n * Rule 4: property bindings that would be form state (view/02-bindings.md \"Live form state\").\n * Returns the spelling to use instead, or undefined when the binding is fine.\n */\nconst FORM_STATE: Record<string, Record<string, string> | undefined> = {\n input: { value: `value=${H}`, checked: `?checked=${H}`, indeterminate: `?indeterminate=${H}` },\n textarea: { value: `<textarea>${H}</textarea>` },\n select: { value: `?selected=${H} on the chosen <option>` },\n option: { selected: `?selected=${H}`, value: `value=${H}` },\n details: { open: `?open=${H}` },\n dialog: { open: `?open=${H}`, modal: `?modal=${H}` },\n};\n\n/**\n * Rule 4: property bindings that would be form state (view/02-bindings.md \"Live form state\").\n * Returns the spelling to use instead, or undefined when the binding is fine.\n */\nexport function formStateFix(tag: string, name: string): string | undefined {\n return FORM_STATE[tag]?.[name];\n}\n\n/**\n * Rule 14: HTML boolean attributes (present means true). `hidden` is left out because\n * hidden=\"until-found\" is a real string value.\n */\nexport const BOOLEAN_ATTRS = new Set(\n (\n 'allowfullscreen async autofocus autoplay checked controls default defer disabled ' +\n 'disablepictureinpicture disableremoteplayback formnovalidate inert ismap itemscope loop ' +\n 'multiple muted nomodule novalidate open playsinline readonly required reversed selected ' +\n 'shadowrootclonable shadowrootdelegatesfocus shadowrootserializable'\n ).split(' '),\n);\n\n/** Rule 10: SVG element names that HTML doesn't share (lower case). */\nexport const SVG_ONLY = new Set(\n (\n 'animate animatemotion animatetransform circle clippath defs desc ellipse feblend ' +\n 'fecolormatrix fecomponenttransfer fecomposite feconvolvematrix fediffuselighting ' +\n 'fedisplacementmap fedropshadow feflood fegaussianblur feimage femerge femergenode ' +\n 'femorphology feoffset fespecularlighting fetile feturbulence filter foreignobject g line ' +\n 'lineargradient marker mask metadata mpath path pattern polygon polyline radialgradient ' +\n 'rect stop symbol text textpath tspan use'\n ).split(' '),\n);\n\n/** HTML void elements: no end tag, no content. */\nexport const VOID = new Set(\n (\n 'area base basefont bgsound br col embed frame hr img input keygen link meta param source ' +\n 'track wbr'\n ).split(' '),\n);\n"]}
@@ -0,0 +1,14 @@
1
+ /** A bound attribute's name on an SVG element, as the parser spells it. */
2
+ export declare const svgAttr: (name: string) => string;
3
+ /**
4
+ * HTML elements that are not SVG elements, and that don't end SVG content either (those are
5
+ * repairs.ts's BREAKOUT): inside SVG content the parser creates an unknown SVG element.
6
+ */
7
+ export declare const HTML_ONLY: Set<string>;
8
+ /** HTML integration points in SVG: their content is HTML (WHATWG HTML, tree construction). */
9
+ export declare const SVG_HTML_POINT: RegExp;
10
+ /**
11
+ * A bound attribute the renderer can't set with `setAttribute` the way the parser would: the
12
+ * parser puts xlink:*, xml:* and xmlns* attributes in their own namespaces.
13
+ */
14
+ export declare const namespacedAttr: (name: string) => boolean;
@@ -0,0 +1,40 @@
1
+ // SVG content in the normalizer (view/01-templates.md "svg templates", view/09-template-rules.md
2
+ // rule 10), from WHATWG HTML "Parsing main inside foreign content" and "adjust SVG attributes":
3
+ // the HTML tokenizer lower-cases attribute names, then the tree builder restores the camelCase
4
+ // of SVG's own attributes. Bound attribute names on SVG elements are spelled the same way, so
5
+ // `viewbox=${v}` binds viewBox, as the parser does for the server's markup. HTML elements that
6
+ // are not SVG elements, inside SVG content, are rule 10 (they would be created as unknown SVG
7
+ // elements that render nothing); the ones that end the SVG element are in repairs.ts.
8
+ /** WHATWG HTML's "adjust SVG attributes" table: lower case → the SVG spelling. */
9
+ const CAMEL = 'attributeName attributeType baseFrequency baseProfile calcMode clipPathUnits ' +
10
+ 'diffuseConstant edgeMode filterUnits glyphRef gradientTransform gradientUnits kernelMatrix ' +
11
+ 'kernelUnitLength keyPoints keySplines keyTimes lengthAdjust limitingConeAngle markerHeight ' +
12
+ 'markerUnits markerWidth maskContentUnits maskUnits numOctaves pathLength ' +
13
+ 'patternContentUnits patternTransform patternUnits pointsAtX pointsAtY pointsAtZ ' +
14
+ 'preserveAlpha preserveAspectRatio primitiveUnits refX refY repeatCount repeatDur ' +
15
+ 'requiredExtensions requiredFeatures specularConstant specularExponent spreadMethod ' +
16
+ 'startOffset stdDeviation stitchTiles surfaceScale systemLanguage tableValues targetX ' +
17
+ 'targetY textLength viewBox viewTarget xChannelSelector yChannelSelector zoomAndPan';
18
+ const ATTRS = new Map(CAMEL.split(' ').map((name) => [name.toLowerCase(), name]));
19
+ /** A bound attribute's name on an SVG element, as the parser spells it. */
20
+ export const svgAttr = (name) => {
21
+ const lower = name.toLowerCase();
22
+ return ATTRS.get(lower) ?? lower;
23
+ };
24
+ /**
25
+ * HTML elements that are not SVG elements, and that don't end SVG content either (those are
26
+ * repairs.ts's BREAKOUT): inside SVG content the parser creates an unknown SVG element.
27
+ */
28
+ export const HTML_ONLY = new Set(('abbr address area article aside audio bdi bdo button canvas caption cite col colgroup ' +
29
+ 'data datalist del details dfn dialog fieldset figcaption figure footer form header hgroup ' +
30
+ 'html iframe input ins kbd label legend main map mark meter nav noscript object optgroup ' +
31
+ 'option output picture progress q rp rt samp search section select slot source summary ' +
32
+ 'tbody td template textarea tfoot th thead time tr track video wbr').split(' '));
33
+ /** HTML integration points in SVG: their content is HTML (WHATWG HTML, tree construction). */
34
+ export const SVG_HTML_POINT = /^(foreignobject|desc|title)$/;
35
+ /**
36
+ * A bound attribute the renderer can't set with `setAttribute` the way the parser would: the
37
+ * parser puts xlink:*, xml:* and xmlns* attributes in their own namespaces.
38
+ */
39
+ export const namespacedAttr = (name) => /^(xlink:|xml:|xmlns)/i.test(name);
40
+ //# sourceMappingURL=svg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.js","sourceRoot":"","sources":["../../../src/view/normalize/svg.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,gGAAgG;AAChG,+FAA+F;AAC/F,8FAA8F;AAC9F,+FAA+F;AAC/F,8FAA8F;AAC9F,sFAAsF;AAEtF,kFAAkF;AAClF,MAAM,KAAK,GACT,+EAA+E;IAC/E,6FAA6F;IAC7F,6FAA6F;IAC7F,2EAA2E;IAC3E,kFAAkF;IAClF,mFAAmF;IACnF,qFAAqF;IACrF,uFAAuF;IACvF,oFAAoF,CAAC;AACvF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAElF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;AACnC,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAC9B,CACE,wFAAwF;IACxF,4FAA4F;IAC5F,0FAA0F;IAC1F,wFAAwF;IACxF,mEAAmE,CACpE,CAAC,KAAK,CAAC,GAAG,CAAC,CACb,CAAC;AAEF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAE7D;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["// SVG content in the normalizer (view/01-templates.md \"svg templates\", view/09-template-rules.md\n// rule 10), from WHATWG HTML \"Parsing main inside foreign content\" and \"adjust SVG attributes\":\n// the HTML tokenizer lower-cases attribute names, then the tree builder restores the camelCase\n// of SVG's own attributes. Bound attribute names on SVG elements are spelled the same way, so\n// `viewbox=${v}` binds viewBox, as the parser does for the server's markup. HTML elements that\n// are not SVG elements, inside SVG content, are rule 10 (they would be created as unknown SVG\n// elements that render nothing); the ones that end the SVG element are in repairs.ts.\n\n/** WHATWG HTML's \"adjust SVG attributes\" table: lower case → the SVG spelling. */\nconst CAMEL =\n 'attributeName attributeType baseFrequency baseProfile calcMode clipPathUnits ' +\n 'diffuseConstant edgeMode filterUnits glyphRef gradientTransform gradientUnits kernelMatrix ' +\n 'kernelUnitLength keyPoints keySplines keyTimes lengthAdjust limitingConeAngle markerHeight ' +\n 'markerUnits markerWidth maskContentUnits maskUnits numOctaves pathLength ' +\n 'patternContentUnits patternTransform patternUnits pointsAtX pointsAtY pointsAtZ ' +\n 'preserveAlpha preserveAspectRatio primitiveUnits refX refY repeatCount repeatDur ' +\n 'requiredExtensions requiredFeatures specularConstant specularExponent spreadMethod ' +\n 'startOffset stdDeviation stitchTiles surfaceScale systemLanguage tableValues targetX ' +\n 'targetY textLength viewBox viewTarget xChannelSelector yChannelSelector zoomAndPan';\nconst ATTRS = new Map(CAMEL.split(' ').map((name) => [name.toLowerCase(), name]));\n\n/** A bound attribute's name on an SVG element, as the parser spells it. */\nexport const svgAttr = (name: string): string => {\n const lower = name.toLowerCase();\n return ATTRS.get(lower) ?? lower;\n};\n\n/**\n * HTML elements that are not SVG elements, and that don't end SVG content either (those are\n * repairs.ts's BREAKOUT): inside SVG content the parser creates an unknown SVG element.\n */\nexport const HTML_ONLY = new Set(\n (\n 'abbr address area article aside audio bdi bdo button canvas caption cite col colgroup ' +\n 'data datalist del details dfn dialog fieldset figcaption figure footer form header hgroup ' +\n 'html iframe input ins kbd label legend main map mark meter nav noscript object optgroup ' +\n 'option output picture progress q rp rt samp search section select slot source summary ' +\n 'tbody td template textarea tfoot th thead time tr track video wbr'\n ).split(' '),\n);\n\n/** HTML integration points in SVG: their content is HTML (WHATWG HTML, tree construction). */\nexport const SVG_HTML_POINT = /^(foreignobject|desc|title)$/;\n\n/**\n * A bound attribute the renderer can't set with `setAttribute` the way the parser would: the\n * parser puts xlink:*, xml:* and xmlns* attributes in their own namespaces.\n */\nexport const namespacedAttr = (name: string): boolean => /^(xlink:|xml:|xmlns)/i.test(name);\n"]}
@@ -1,9 +1,13 @@
1
1
  export type ContentMode = 'data' | 'rawtext' | 'rcdata';
2
- /** A static attribute as written: `value` is the raw source, quotes included, or null. */
2
+ /**
3
+ * A static attribute as written: `value` is the raw source, quotes included, or null. `css`:
4
+ * a `style` attribute's decoded value, set by the tree builder (01 "Normalization", step 3).
5
+ */
3
6
  export interface StaticAttr {
4
7
  readonly kind: 'static';
5
8
  readonly name: string;
6
9
  readonly value: string | null;
10
+ readonly css?: string;
7
11
  }
8
12
  /** A bound attribute. `strings` (raw static pieces) only for multi-attributes. */
9
13
  export interface BoundAttr {
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../src/view/normalize/tokens.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,iGAAiG;AAsCjG,MAAM,CAAC,MAAM,CAAC,GAAG;IACf,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,SAAS,EAAE,CAAC;IACZ,WAAW,EAAE,CAAC;IACd,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,MAAM,EAAE,EAAE;CACF,CAAC;AAGX,MAAM,EAAE,GAAG,eAAe,CAAC;AAC3B,MAAM,CAAC,MAAM,QAAQ,GAAG,0BAA0B,CAAC;AACnD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAqB,EAAW,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC","sourcesContent":["// Token types shared by the tokenizer (tokenizer.ts, tag-states.ts) and the tree builder\n// (tree.ts), plus the tokenizer's states (WHATWG HTML \"Tokenization\", the subset templates use).\n\nexport type ContentMode = 'data' | 'rawtext' | 'rcdata';\n\n/** A static attribute as written: `value` is the raw source, quotes included, or null. */\nexport interface StaticAttr {\n readonly kind: 'static';\n readonly name: string;\n readonly value: string | null;\n}\n\n/** A bound attribute. `strings` (raw static pieces) only for multi-attributes. */\nexport interface BoundAttr {\n readonly kind: 'attr' | 'bool' | 'prop' | 'hook';\n readonly name: string;\n readonly strings?: readonly string[];\n}\n\nexport type AttrToken = StaticAttr | BoundAttr;\n\nexport interface StartTag {\n /** Lower-case name, and the name as written. */\n readonly name: string;\n readonly raw: string;\n readonly attrs: AttrToken[];\n selfClosing: boolean;\n}\n\nexport interface Sink {\n text(raw: string): void;\n comment(raw: string): void;\n doctype(raw: string): void;\n start(tag: StartTag): ContentMode;\n end(name: string): void;\n hole(kind: 'child' | 'text'): void;\n finish(): void;\n}\n\nexport const S = {\n Data: 0,\n RawText: 1,\n RcData: 2,\n Comment: 3,\n Bogus: 4,\n Doctype: 5,\n BeforeName: 6,\n Name: 7,\n AfterName: 8,\n BeforeValue: 9,\n ValueDq: 10,\n ValueSq: 11,\n ValueUnq: 12,\n AfterValueQ: 13,\n SelfClosing: 14,\n EndTag: 15,\n} as const;\nexport type State = (typeof S)[keyof typeof S];\n\nconst WS = /^[\\t\\n\\f\\r ]$/;\nexport const TAG_NAME = /^[A-Za-z][^\\t\\n\\f\\r />]*/;\nexport const isWs = (c: string | undefined): boolean => c !== undefined && WS.test(c);\n"]}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../src/view/normalize/tokens.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,iGAAiG;AA0CjG,MAAM,CAAC,MAAM,CAAC,GAAG;IACf,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,SAAS,EAAE,CAAC;IACZ,WAAW,EAAE,CAAC;IACd,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,MAAM,EAAE,EAAE;CACF,CAAC;AAGX,MAAM,EAAE,GAAG,eAAe,CAAC;AAC3B,MAAM,CAAC,MAAM,QAAQ,GAAG,0BAA0B,CAAC;AACnD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAqB,EAAW,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC","sourcesContent":["// Token types shared by the tokenizer (tokenizer.ts, tag-states.ts) and the tree builder\n// (tree.ts), plus the tokenizer's states (WHATWG HTML \"Tokenization\", the subset templates use).\n\nexport type ContentMode = 'data' | 'rawtext' | 'rcdata';\n\n/**\n * A static attribute as written: `value` is the raw source, quotes included, or null. `css`:\n * a `style` attribute's decoded value, set by the tree builder (01 \"Normalization\", step 3).\n */\nexport interface StaticAttr {\n readonly kind: 'static';\n readonly name: string;\n readonly value: string | null;\n readonly css?: string;\n}\n\n/** A bound attribute. `strings` (raw static pieces) only for multi-attributes. */\nexport interface BoundAttr {\n readonly kind: 'attr' | 'bool' | 'prop' | 'hook';\n readonly name: string;\n readonly strings?: readonly string[];\n}\n\nexport type AttrToken = StaticAttr | BoundAttr;\n\nexport interface StartTag {\n /** Lower-case name, and the name as written. */\n readonly name: string;\n readonly raw: string;\n readonly attrs: AttrToken[];\n selfClosing: boolean;\n}\n\nexport interface Sink {\n text(raw: string): void;\n comment(raw: string): void;\n doctype(raw: string): void;\n start(tag: StartTag): ContentMode;\n end(name: string): void;\n hole(kind: 'child' | 'text'): void;\n finish(): void;\n}\n\nexport const S = {\n Data: 0,\n RawText: 1,\n RcData: 2,\n Comment: 3,\n Bogus: 4,\n Doctype: 5,\n BeforeName: 6,\n Name: 7,\n AfterName: 8,\n BeforeValue: 9,\n ValueDq: 10,\n ValueSq: 11,\n ValueUnq: 12,\n AfterValueQ: 13,\n SelfClosing: 14,\n EndTag: 15,\n} as const;\nexport type State = (typeof S)[keyof typeof S];\n\nconst WS = /^[\\t\\n\\f\\r ]$/;\nexport const TAG_NAME = /^[A-Za-z][^\\t\\n\\f\\r />]*/;\nexport const isWs = (c: string | undefined): boolean => c !== undefined && WS.test(c);\n"]}
@@ -32,13 +32,15 @@ export type TreeNode = ElementNode | {
32
32
  };
33
33
  export declare class TreeBuilder implements Sink {
34
34
  private readonly src;
35
+ private readonly svg;
35
36
  readonly root: TreeNode[];
36
37
  server: boolean;
37
38
  private readonly stack;
38
39
  private rootCtx;
39
40
  /** The <pre>/<listing>/<textarea> whose first newline the parser drops, if just opened. */
40
41
  private fresh;
41
- constructor(src: Source);
42
+ /** `svg`: an svg template, whose top level is SVG content (01 "svg templates"). */
43
+ constructor(src: Source, svg?: boolean);
42
44
  private get children();
43
45
  private context;
44
46
  private inTemplate;
@@ -49,7 +51,11 @@ export declare class TreeBuilder implements Sink {
49
51
  start(tag: StartTag): ContentMode;
50
52
  private namespace;
51
53
  private checkHtml;
52
- /** Bound names lower-cased on HTML elements (not properties); rules 4, 7 (duplicates), 13. */
54
+ /**
55
+ * Bound names as the parser spells them (not properties): lower case on HTML elements, SVG's
56
+ * camelCase on SVG elements (svg.ts); rules 4, 7 (duplicates), 10 (namespaced), 13, 14 (boolean attributes). A
57
+ * static `style` gets its decoded value (`css`): the client applies it as a part (emit.ts).
58
+ */
53
59
  private attributes;
54
60
  private props;
55
61
  private decode;
@@ -2,22 +2,26 @@
2
2
  // tokens into the tree the HTML parser builds for valid markup (WHATWG "tree construction":
3
3
  // namespaces, void elements, raw text, the leading newline of <pre>/<listing>/<textarea>), so
4
4
  // part paths match the browser's DOM. Markup the parser would repair is an error instead of
5
- // being modelled (rule 7, repairs.ts), as are rules 3, 4, 6, 10, 12 and 13.
5
+ // being modelled (rule 7, repairs.ts), as are rules 3, 4, 6, 10, 12 and 13. An svg template's
6
+ // top level is SVG content, as if inside an <svg> (01 "svg templates", svg.ts).
6
7
  import { decodeRefs, unquote } from './entities.js';
7
8
  import { breaksOutOfForeign, contextOf, rootContext, startRepair, textRepair, } from './repairs.js';
8
- import { formStateFix, msg, SVG_ONLY, VOID } from './rules.js';
9
+ import { BOOLEAN_ATTRS, formStateFix, msg, SVG_ONLY, VOID } from './rules.js';
10
+ import { HTML_ONLY, namespacedAttr, SVG_HTML_POINT, svgAttr } from './svg.js';
9
11
  const RAWTEXT = new Set('script style xmp iframe noembed noframes noscript plaintext'.split(' '));
10
12
  const RCDATA = new Set(['textarea', 'title']);
11
13
  const LEADING_NEWLINE = new Set(['pre', 'listing', 'textarea']);
12
14
  const DOCUMENT = new Set(['html', 'head', 'body']);
13
15
  function integrationPoint(el) {
14
16
  if (el.ns === 'svg')
15
- return /^(foreignobject|desc|title)$/.test(el.name);
17
+ return SVG_HTML_POINT.test(el.name);
16
18
  return el.ns === 'math' && /^(mi|mo|mn|ms|mtext)$/.test(el.name);
17
19
  }
18
20
  export class TreeBuilder {
19
- constructor(src) {
21
+ /** `svg`: an svg template, whose top level is SVG content (01 "svg templates"). */
22
+ constructor(src, svg = false) {
20
23
  this.src = src;
24
+ this.svg = svg;
21
25
  this.root = [];
22
26
  this.server = false;
23
27
  this.stack = [];
@@ -55,6 +59,8 @@ export class TreeBuilder {
55
59
  }
56
60
  doctype(raw) {
57
61
  this.fresh = undefined;
62
+ if (this.svg)
63
+ this.src.fail(10, msg.htmlInSvg('!doctype', true));
58
64
  this.server = true;
59
65
  this.children.push({ type: 'doctype', raw });
60
66
  }
@@ -97,11 +103,22 @@ export class TreeBuilder {
97
103
  }
98
104
  namespace(tag) {
99
105
  const parent = this.stack.at(-1);
100
- if (parent === undefined || parent.ns === 'html' || integrationPoint(parent)) {
106
+ if (parent === undefined ? !this.svg : parent.ns === 'html' || integrationPoint(parent)) {
101
107
  return tag.name === 'svg' ? 'svg' : tag.name === 'math' ? 'math' : 'html';
102
108
  }
109
+ // An svg template's top level: SVG content, as inside the <svg> it renders in.
110
+ if (parent === undefined) {
111
+ const fontAttr = tag.attrs.some((a) => /^(color|face|size)$/i.test(a.name));
112
+ if (breaksOutOfForeign(tag.name, fontAttr) || HTML_ONLY.has(tag.name)) {
113
+ this.src.fail(10, msg.htmlInSvg(tag.raw, true));
114
+ }
115
+ return 'svg';
116
+ }
103
117
  if (parent.name === 'annotation-xml' && tag.name === 'svg')
104
118
  return 'svg';
119
+ if (parent.ns === 'svg' && HTML_ONLY.has(tag.name)) {
120
+ this.src.fail(10, msg.htmlInSvg(tag.raw, false));
121
+ }
105
122
  const fontAttr = tag.attrs.some((a) => /^(color|face|size)$/i.test(a.name));
106
123
  if (breaksOutOfForeign(tag.name, fontAttr)) {
107
124
  this.src.fail(7, msg.repaired(`<${tag.name}> inside <${parent.ns}> ends the <${parent.ns}> element`, `Put HTML inside <foreignObject>, or move it out of the <${parent.ns}>.`));
@@ -129,29 +146,57 @@ export class TreeBuilder {
129
146
  if (repair !== undefined)
130
147
  this.src.fail(7, repair);
131
148
  }
132
- /** Bound names lower-cased on HTML elements (not properties); rules 4, 7 (duplicates), 13. */
149
+ /**
150
+ * Bound names as the parser spells them (not properties): lower case on HTML elements, SVG's
151
+ * camelCase on SVG elements (svg.ts); rules 4, 7 (duplicates), 10 (namespaced), 13, 14 (boolean attributes). A
152
+ * static `style` gets its decoded value (`css`): the client applies it as a part (emit.ts).
153
+ */
133
154
  attributes(tag, ns) {
134
155
  const seen = new Set();
156
+ // A nested <template>'s content is out of the parts' reach: its static styles stay.
157
+ const reach = !this.inTemplate();
135
158
  return tag.attrs.map((a) => {
136
- const lower = ns === 'html' && a.kind !== 'prop' ? a.name.toLowerCase() : a.name;
159
+ const name = a.kind === 'prop' || ns === 'math'
160
+ ? a.name
161
+ : ns === 'html'
162
+ ? a.name.toLowerCase()
163
+ : svgAttr(a.name);
137
164
  if (a.kind === 'prop' && ns === 'html') {
138
165
  const fix = formStateFix(tag.name, a.name);
139
166
  if (fix !== undefined)
140
167
  this.src.fail(4, msg.formState(tag.name, a.name, fix));
141
168
  }
169
+ // Dialog and popover state is bound with `?`, on the element that can open (02).
170
+ if (ns === 'html' && (name === 'modal' || name === 'popover-open') && a.kind !== 'prop') {
171
+ const fits = name === 'modal'
172
+ ? tag.name === 'dialog'
173
+ : tag.attrs.some((b) => b.name.toLowerCase() === 'popover');
174
+ if (a.kind !== 'bool' || !fits)
175
+ this.src.fail(4, msg.toggle(tag.name, name));
176
+ }
177
+ if (a.kind === 'attr' &&
178
+ ns === 'html' &&
179
+ !tag.name.includes('-') &&
180
+ BOOLEAN_ATTRS.has(name)) {
181
+ this.src.fail(14, msg.booleanAttr(tag.name, name));
182
+ }
183
+ if ((a.kind === 'attr' || a.kind === 'bool') && ns !== 'html' && namespacedAttr(a.name)) {
184
+ this.src.fail(10, msg.namespacedAttr(a.name));
185
+ }
142
186
  if (a.kind !== 'prop' && a.kind !== 'hook') {
143
- const key = ns === 'html' ? lower : a.name;
187
+ const key = ns === 'math' ? a.name : a.name.toLowerCase();
144
188
  if (seen.has(key)) {
145
189
  this.src.fail(7, msg.repaired(`${key} appears twice on <${tag.raw}>, and the parser keeps only the first`, `Write it once; to mix static and dynamic text, quote one value: ${key}="a \${…}".`));
146
190
  }
147
191
  seen.add(key);
148
192
  }
149
- if (a.kind === 'static')
150
- return a;
193
+ if (a.kind === 'static') {
194
+ if (!reach || a.name.toLowerCase() !== 'style')
195
+ return a;
196
+ return { ...a, css: a.value === null ? '' : this.decode(unquote(a.value)) };
197
+ }
151
198
  const strings = a.strings?.map((s) => this.decode(s));
152
- return strings === undefined
153
- ? { kind: a.kind, name: lower }
154
- : { kind: a.kind, name: lower, strings };
199
+ return strings === undefined ? { kind: a.kind, name } : { kind: a.kind, name, strings };
155
200
  });
156
201
  }
157
202
  props(tag) {