@gyral/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +7 -5
  3. package/dist/children.d.ts +5 -2
  4. package/dist/children.js +8 -3
  5. package/dist/children.js.map +1 -1
  6. package/dist/command.js +6 -0
  7. package/dist/command.js.map +1 -1
  8. package/dist/compiler/ast.d.ts +21 -0
  9. package/dist/compiler/ast.js +145 -0
  10. package/dist/compiler/ast.js.map +1 -0
  11. package/dist/compiler/compile.d.ts +38 -0
  12. package/dist/compiler/compile.js +129 -0
  13. package/dist/compiler/compile.js.map +1 -0
  14. package/dist/compiler/hooks.d.ts +18 -0
  15. package/dist/compiler/hooks.js +186 -0
  16. package/dist/compiler/hooks.js.map +1 -0
  17. package/dist/compiler/parse5-check.d.ts +21 -0
  18. package/dist/compiler/parse5-check.js +55 -0
  19. package/dist/compiler/parse5-check.js.map +1 -0
  20. package/dist/compiler/scan.d.ts +31 -0
  21. package/dist/compiler/scan.js +152 -0
  22. package/dist/compiler/scan.js.map +1 -0
  23. package/dist/compiler/source.d.ts +34 -0
  24. package/dist/compiler/source.js +114 -0
  25. package/dist/compiler/source.js.map +1 -0
  26. package/dist/define.d.ts +2 -2
  27. package/dist/define.js +35 -327
  28. package/dist/define.js.map +1 -1
  29. package/dist/devtools-events.d.ts +5 -0
  30. package/dist/devtools-events.js.map +1 -1
  31. package/dist/devtools-off.d.ts +1 -0
  32. package/dist/devtools-off.js +1 -0
  33. package/dist/devtools-off.js.map +1 -1
  34. package/dist/devtools.d.ts +1 -0
  35. package/dist/devtools.js +3 -2
  36. package/dist/devtools.js.map +1 -1
  37. package/dist/drivers-scope.d.ts +1 -1
  38. package/dist/drivers-scope.js +1 -8
  39. package/dist/drivers-scope.js.map +1 -1
  40. package/dist/element-types.d.ts +5 -3
  41. package/dist/element-types.js.map +1 -1
  42. package/dist/element.d.ts +3 -0
  43. package/dist/element.js +269 -0
  44. package/dist/element.js.map +1 -0
  45. package/dist/eslint/imports.d.ts +24 -0
  46. package/dist/eslint/imports.js +78 -0
  47. package/dist/eslint/imports.js.map +1 -0
  48. package/dist/eslint/index.d.ts +15 -0
  49. package/dist/eslint/index.js +15 -0
  50. package/dist/eslint/index.js.map +1 -0
  51. package/dist/eslint/locate.d.ts +33 -0
  52. package/dist/eslint/locate.js +132 -0
  53. package/dist/eslint/locate.js.map +1 -0
  54. package/dist/eslint/row-purity-rule.d.ts +2 -0
  55. package/dist/eslint/row-purity-rule.js +103 -0
  56. package/dist/eslint/row-purity-rule.js.map +1 -0
  57. package/dist/eslint/template-rule.d.ts +5 -0
  58. package/dist/eslint/template-rule.js +66 -0
  59. package/dist/eslint/template-rule.js.map +1 -0
  60. package/dist/features.d.ts +39 -0
  61. package/dist/features.js +2 -0
  62. package/dist/features.js.map +1 -0
  63. package/dist/focus.d.ts +7 -12
  64. package/dist/focus.js +13 -10
  65. package/dist/focus.js.map +1 -1
  66. package/dist/hooks/invalid.d.ts +14 -0
  67. package/dist/hooks/invalid.js +72 -0
  68. package/dist/hooks/invalid.js.map +1 -0
  69. package/dist/hooks/labelled-by.d.ts +13 -0
  70. package/dist/hooks/labelled-by.js +51 -0
  71. package/dist/hooks/labelled-by.js.map +1 -0
  72. package/dist/host-model.d.ts +48 -0
  73. package/dist/host-model.js +155 -0
  74. package/dist/host-model.js.map +1 -0
  75. package/dist/hydration-client.d.ts +9 -0
  76. package/dist/hydration-client.js +35 -0
  77. package/dist/hydration-client.js.map +1 -0
  78. package/dist/hydration.d.ts +13 -19
  79. package/dist/hydration.js +45 -45
  80. package/dist/hydration.js.map +1 -1
  81. package/dist/index.d.ts +9 -17
  82. package/dist/index.js +9 -18
  83. package/dist/index.js.map +1 -1
  84. package/dist/intent.d.ts +31 -8
  85. package/dist/intent.js +82 -27
  86. package/dist/intent.js.map +1 -1
  87. package/dist/internal/interpreter.d.ts +7 -1
  88. package/dist/internal/interpreter.js +11 -4
  89. package/dist/internal/interpreter.js.map +1 -1
  90. package/dist/invokers-shim.d.ts +6 -0
  91. package/dist/invokers-shim.js +32 -0
  92. package/dist/invokers-shim.js.map +1 -0
  93. package/dist/invokers.d.ts +3 -5
  94. package/dist/invokers.js +11 -51
  95. package/dist/invokers.js.map +1 -1
  96. package/dist/islands.d.ts +0 -2
  97. package/dist/islands.js +4 -11
  98. package/dist/islands.js.map +1 -1
  99. package/dist/light-dom.d.ts +3 -52
  100. package/dist/light-dom.js +5 -100
  101. package/dist/light-dom.js.map +1 -1
  102. package/dist/prop.d.ts +66 -0
  103. package/dist/prop.js +22 -0
  104. package/dist/prop.js.map +1 -0
  105. package/dist/props.d.ts +52 -21
  106. package/dist/props.js +150 -34
  107. package/dist/props.js.map +1 -1
  108. package/dist/scheduler.d.ts +39 -0
  109. package/dist/scheduler.js +230 -0
  110. package/dist/scheduler.js.map +1 -0
  111. package/dist/server-component.d.ts +10 -0
  112. package/dist/server-component.js +102 -0
  113. package/dist/server-component.js.map +1 -0
  114. package/dist/server-specs.d.ts +6 -0
  115. package/dist/server-specs.js +13 -0
  116. package/dist/server-specs.js.map +1 -0
  117. package/dist/server.d.ts +28 -0
  118. package/dist/server.js +50 -0
  119. package/dist/server.js.map +1 -0
  120. package/dist/settled.d.ts +10 -0
  121. package/dist/settled.js +40 -0
  122. package/dist/settled.js.map +1 -0
  123. package/dist/states.d.ts +3 -3
  124. package/dist/states.js +4 -7
  125. package/dist/states.js.map +1 -1
  126. package/dist/store-binding.d.ts +6 -3
  127. package/dist/store-binding.js +5 -6
  128. package/dist/store-binding.js.map +1 -1
  129. package/dist/store-scope.d.ts +6 -7
  130. package/dist/store-scope.js +11 -26
  131. package/dist/store-scope.js.map +1 -1
  132. package/dist/store.d.ts +3 -0
  133. package/dist/store.js +9 -2
  134. package/dist/store.js.map +1 -1
  135. package/dist/stores-provider.d.ts +2 -6
  136. package/dist/stores-provider.js +21 -55
  137. package/dist/stores-provider.js.map +1 -1
  138. package/dist/transitions.d.ts +5 -6
  139. package/dist/transitions.js +11 -20
  140. package/dist/transitions.js.map +1 -1
  141. package/dist/types.d.ts +19 -23
  142. package/dist/types.js.map +1 -1
  143. package/dist/view/attributes.d.ts +6 -0
  144. package/dist/view/attributes.js +10 -0
  145. package/dist/view/attributes.js.map +1 -0
  146. package/dist/view/compiled.d.ts +1 -0
  147. package/dist/view/compiled.js +6 -0
  148. package/dist/view/compiled.js.map +1 -0
  149. package/dist/view/dev-off.d.ts +1 -0
  150. package/dist/view/dev-off.js +4 -0
  151. package/dist/view/dev-off.js.map +1 -0
  152. package/dist/view/dev.d.ts +1 -0
  153. package/dist/view/dev.js +5 -0
  154. package/dist/view/dev.js.map +1 -0
  155. package/dist/view/flags.d.ts +1 -0
  156. package/dist/view/flags.js +4 -0
  157. package/dist/view/flags.js.map +1 -0
  158. package/dist/view/index.d.ts +21 -0
  159. package/dist/view/index.js +21 -0
  160. package/dist/view/index.js.map +1 -0
  161. package/dist/view/normalize/check.d.ts +20 -0
  162. package/dist/view/normalize/check.js +78 -0
  163. package/dist/view/normalize/check.js.map +1 -0
  164. package/dist/view/normalize/emit.d.ts +13 -0
  165. package/dist/view/normalize/emit.js +136 -0
  166. package/dist/view/normalize/emit.js.map +1 -0
  167. package/dist/view/normalize/entities.d.ts +4 -0
  168. package/dist/view/normalize/entities.js +38 -0
  169. package/dist/view/normalize/entities.js.map +1 -0
  170. package/dist/view/normalize/errors.d.ts +9 -0
  171. package/dist/view/normalize/errors.js +19 -0
  172. package/dist/view/normalize/errors.js.map +1 -0
  173. package/dist/view/normalize/id.d.ts +7 -0
  174. package/dist/view/normalize/id.js +48 -0
  175. package/dist/view/normalize/id.js.map +1 -0
  176. package/dist/view/normalize/normalize.d.ts +15 -0
  177. package/dist/view/normalize/normalize.js +36 -0
  178. package/dist/view/normalize/normalize.js.map +1 -0
  179. package/dist/view/normalize/repairs.d.ts +24 -0
  180. package/dist/view/normalize/repairs.js +166 -0
  181. package/dist/view/normalize/repairs.js.map +1 -0
  182. package/dist/view/normalize/rules.d.ts +30 -0
  183. package/dist/view/normalize/rules.js +90 -0
  184. package/dist/view/normalize/rules.js.map +1 -0
  185. package/dist/view/normalize/shape.d.ts +5 -0
  186. package/dist/view/normalize/shape.js +38 -0
  187. package/dist/view/normalize/shape.js.map +1 -0
  188. package/dist/view/normalize/source.d.ts +13 -0
  189. package/dist/view/normalize/source.js +34 -0
  190. package/dist/view/normalize/source.js.map +1 -0
  191. package/dist/view/normalize/tag-states.d.ts +23 -0
  192. package/dist/view/normalize/tag-states.js +192 -0
  193. package/dist/view/normalize/tag-states.js.map +1 -0
  194. package/dist/view/normalize/tokenizer.d.ts +5 -0
  195. package/dist/view/normalize/tokenizer.js +233 -0
  196. package/dist/view/normalize/tokenizer.js.map +1 -0
  197. package/dist/view/normalize/tokens.d.ts +51 -0
  198. package/dist/view/normalize/tokens.js +24 -0
  199. package/dist/view/normalize/tokens.js.map +1 -0
  200. package/dist/view/normalize/tree.d.ts +59 -0
  201. package/dist/view/normalize/tree.js +190 -0
  202. package/dist/view/normalize/tree.js.map +1 -0
  203. package/dist/view/normalize/types.d.ts +126 -0
  204. package/dist/view/normalize/types.js +26 -0
  205. package/dist/view/normalize/types.js.map +1 -0
  206. package/dist/view/normalize/whitespace.d.ts +2 -0
  207. package/dist/{template-whitespace.js → view/normalize/whitespace.js} +24 -34
  208. package/dist/view/normalize/whitespace.js.map +1 -0
  209. package/dist/view/prepare-stub.d.ts +3 -0
  210. package/dist/view/prepare-stub.js +7 -0
  211. package/dist/view/prepare-stub.js.map +1 -0
  212. package/dist/view/prepare.d.ts +8 -0
  213. package/dist/view/prepare.js +57 -0
  214. package/dist/view/prepare.js.map +1 -0
  215. package/dist/view/registry.d.ts +63 -0
  216. package/dist/view/registry.js +19 -0
  217. package/dist/view/registry.js.map +1 -0
  218. package/dist/view/render/adopt-attr.d.ts +14 -0
  219. package/dist/view/render/adopt-attr.js +77 -0
  220. package/dist/view/render/adopt-attr.js.map +1 -0
  221. package/dist/view/render/adopt-plan.d.ts +10 -0
  222. package/dist/view/render/adopt-plan.js +26 -0
  223. package/dist/view/render/adopt-plan.js.map +1 -0
  224. package/dist/view/render/adopt.d.ts +3 -0
  225. package/dist/view/render/adopt.js +269 -0
  226. package/dist/view/render/adopt.js.map +1 -0
  227. package/dist/view/render/attr-parts.d.ts +61 -0
  228. package/dist/view/render/attr-parts.js +229 -0
  229. package/dist/view/render/attr-parts.js.map +1 -0
  230. package/dist/view/render/child-part.d.ts +51 -0
  231. package/dist/view/render/child-part.js +170 -0
  232. package/dist/view/render/child-part.js.map +1 -0
  233. package/dist/view/render/dev-check.d.ts +12 -0
  234. package/dist/view/render/dev-check.js +122 -0
  235. package/dist/view/render/dev-check.js.map +1 -0
  236. package/dist/view/render/hook-part.d.ts +3 -0
  237. package/dist/view/render/hook-part.js +20 -0
  238. package/dist/view/render/hook-part.js.map +1 -0
  239. package/dist/view/render/hooks.d.ts +40 -0
  240. package/dist/view/render/hooks.js +46 -0
  241. package/dist/view/render/hooks.js.map +1 -0
  242. package/dist/view/render/hydrate.d.ts +10 -0
  243. package/dist/view/render/hydrate.js +33 -0
  244. package/dist/view/render/hydrate.js.map +1 -0
  245. package/dist/view/render/instance.d.ts +33 -0
  246. package/dist/view/render/instance.js +107 -0
  247. package/dist/view/render/instance.js.map +1 -0
  248. package/dist/view/render/list.d.ts +20 -0
  249. package/dist/view/render/list.js +156 -0
  250. package/dist/view/render/list.js.map +1 -0
  251. package/dist/view/render/mismatch.d.ts +10 -0
  252. package/dist/view/render/mismatch.js +53 -0
  253. package/dist/view/render/mismatch.js.map +1 -0
  254. package/dist/view/render/nodes.d.ts +10 -0
  255. package/dist/view/render/nodes.js +37 -0
  256. package/dist/view/render/nodes.js.map +1 -0
  257. package/dist/view/render/place.d.ts +18 -0
  258. package/dist/view/render/place.js +69 -0
  259. package/dist/view/render/place.js.map +1 -0
  260. package/dist/view/render/plan.d.ts +26 -0
  261. package/dist/view/render/plan.js +124 -0
  262. package/dist/view/render/plan.js.map +1 -0
  263. package/dist/view/render/raw.d.ts +18 -0
  264. package/dist/view/render/raw.js +68 -0
  265. package/dist/view/render/raw.js.map +1 -0
  266. package/dist/view/render/render.d.ts +12 -0
  267. package/dist/view/render/render.js +60 -0
  268. package/dist/view/render/render.js.map +1 -0
  269. package/dist/view/render/reorder.d.ts +4 -0
  270. package/dist/view/render/reorder.js +101 -0
  271. package/dist/view/render/reorder.js.map +1 -0
  272. package/dist/view/render/rows.d.ts +23 -0
  273. package/dist/view/render/rows.js +95 -0
  274. package/dist/view/render/rows.js.map +1 -0
  275. package/dist/view/render/seen.d.ts +11 -0
  276. package/dist/view/render/seen.js +17 -0
  277. package/dist/view/render/seen.js.map +1 -0
  278. package/dist/view/render/values.d.ts +29 -0
  279. package/dist/view/render/values.js +13 -0
  280. package/dist/view/render/values.js.map +1 -0
  281. package/dist/view/render/warn.d.ts +14 -0
  282. package/dist/view/render/warn.js +69 -0
  283. package/dist/view/render/warn.js.map +1 -0
  284. package/dist/view/server/component.d.ts +9 -0
  285. package/dist/view/server/component.js +42 -0
  286. package/dist/view/server/component.js.map +1 -0
  287. package/dist/view/server/escape.d.ts +10 -0
  288. package/dist/view/server/escape.js +34 -0
  289. package/dist/view/server/escape.js.map +1 -0
  290. package/dist/view/server/index.d.ts +28 -0
  291. package/dist/view/server/index.js +72 -0
  292. package/dist/view/server/index.js.map +1 -0
  293. package/dist/view/server/sha256.d.ts +2 -0
  294. package/dist/view/server/sha256.js +75 -0
  295. package/dist/view/server/sha256.js.map +1 -0
  296. package/dist/view/server/tags.d.ts +57 -0
  297. package/dist/view/server/tags.js +121 -0
  298. package/dist/view/server/tags.js.map +1 -0
  299. package/dist/view/server/values.d.ts +16 -0
  300. package/dist/view/server/values.js +86 -0
  301. package/dist/view/server/values.js.map +1 -0
  302. package/dist/view/server/writer.d.ts +16 -0
  303. package/dist/view/server/writer.js +155 -0
  304. package/dist/view/server/writer.js.map +1 -0
  305. package/dist/view/styles.d.ts +25 -0
  306. package/dist/view/styles.js +58 -0
  307. package/dist/view/styles.js.map +1 -0
  308. package/dist/view/template-element.d.ts +3 -0
  309. package/dist/view/template-element.js +25 -0
  310. package/dist/view/template-element.js.map +1 -0
  311. package/dist/view/template.d.ts +21 -0
  312. package/dist/view/template.js +30 -0
  313. package/dist/view/template.js.map +1 -0
  314. package/dist/vite.d.ts +45 -6
  315. package/dist/vite.js +150 -25
  316. package/dist/vite.js.map +1 -1
  317. package/package.json +39 -4
  318. package/dist/accessible-name.d.ts +0 -19
  319. package/dist/accessible-name.js +0 -56
  320. package/dist/accessible-name.js.map +0 -1
  321. package/dist/element-directive.d.ts +0 -20
  322. package/dist/element-directive.js +0 -31
  323. package/dist/element-directive.js.map +0 -1
  324. package/dist/invalid.d.ts +0 -21
  325. package/dist/invalid.js +0 -70
  326. package/dist/invalid.js.map +0 -1
  327. package/dist/lit-html-check.d.ts +0 -6
  328. package/dist/lit-html-check.js +0 -48
  329. package/dist/lit-html-check.js.map +0 -1
  330. package/dist/live-boolean.d.ts +0 -22
  331. package/dist/live-boolean.js +0 -34
  332. package/dist/live-boolean.js.map +0 -1
  333. package/dist/styles.d.ts +0 -12
  334. package/dist/styles.js +0 -11
  335. package/dist/styles.js.map +0 -1
  336. package/dist/template-whitespace.d.ts +0 -7
  337. package/dist/template-whitespace.js.map +0 -1
  338. package/dist/templates.d.ts +0 -5
  339. package/dist/templates.js +0 -15
  340. package/dist/templates.js.map +0 -1
  341. package/dist/textarea.d.ts +0 -26
  342. package/dist/textarea.js +0 -85
  343. package/dist/textarea.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ /** Messages, by rule. Each names the fix. */
2
+ export declare const msg: {
3
+ eventBinding: (name: string) => string;
4
+ dynamicTag: () => string;
5
+ dynamicName: () => string;
6
+ inRawText: (tag: string) => string;
7
+ inComment: () => string;
8
+ inDoctype: () => string;
9
+ inTemplate: () => string;
10
+ formState: (tag: string, name: string, write: string) => string;
11
+ unquoted: (name: string) => string;
12
+ notSingle: (name: string) => string;
13
+ selfClosing: (tag: string) => string;
14
+ repaired: (what: string, write: string) => string;
15
+ badEndTag: () => string;
16
+ unterminated: (what: "comment" | "tag") => string;
17
+ svgOnly: (tag: string) => string;
18
+ serverOnly: () => string;
19
+ textContent: (tag: string) => string;
20
+ charRef: (ref: string) => string;
21
+ };
22
+ /**
23
+ * Rule 4: property bindings that would be form state (view/02-bindings.md "Live form state").
24
+ * Returns the spelling to use instead, or undefined when the binding is fine.
25
+ */
26
+ export declare function formStateFix(tag: string, name: string): string | undefined;
27
+ /** Rule 10: SVG element names that HTML doesn't share (lower case). */
28
+ export declare const SVG_ONLY: Set<string>;
29
+ /** HTML void elements: no end tag, no content. */
30
+ export declare const VOID: Set<string>;
@@ -0,0 +1,90 @@
1
+ // The template rules of view/09-template-rules.md that one template's strings reveal: every
2
+ // message says what is wrong and what to write instead (core belief 7). The tokenizer
3
+ // (rules 1, 2, 3, 5), the tree builder (3, 4, 6, 7, 10, 12, 13) and repairs.ts (7) throw them
4
+ // through Source.fail; the browser's own parse (prepare.ts) backs rule 7 up, and
5
+ // template-element.ts throws rule 11 when a server template reaches the browser.
6
+ import { SERVER_ONLY } from './errors.js';
7
+ const H = '${…}';
8
+ /** Messages, by rule. Each names the fix. */
9
+ export const msg = {
10
+ // 1
11
+ eventBinding: (name) => `${name}=${H} is an event binding, and Gyral has none: views never attach listeners. ` +
12
+ `Name the intent instead, data-intent=\${i.Name}, and parse the event in the component's ` +
13
+ `intent (ADR 0001).`,
14
+ // 2
15
+ dynamicTag: () => `A hole can't be (part of) a tag name: <${H}> and </${H}> are not supported. Choose ` +
16
+ `between whole templates instead: \${cond ? html\`<a>…</a>\` : html\`<b>…</b>\`}. ` +
17
+ `For a literal "<" next to a value, write &lt;.`,
18
+ dynamicName: () => `A hole can't be (part of) an attribute name. Write the name statically (name=${H}), ` +
19
+ `use ?name=${H} to add or remove it, or choose between whole templates.`,
20
+ // 3
21
+ inRawText: (tag) => `A hole can't sit inside <${tag}>: no part can live there, and values in it are an ` +
22
+ `injection risk. Pass data through an attribute, styles through a CSS custom property ` +
23
+ `(style=\${\`--x: \${v}\`}), or trusted markup through raw().`,
24
+ inComment: () => `A hole can't sit inside an HTML comment: no part can live there. Move the value out of ` +
25
+ `the comment, or drop the comment.`,
26
+ inDoctype: () => `A hole can't sit inside <!doctype>. Write the doctype statically: <!doctype html>.`,
27
+ inTemplate: () => `A hole can't sit inside a <template> element: its content is inert and no part can live ` +
28
+ `there. Render the content with a nested html\`…\` template in a child hole instead.`,
29
+ // 4
30
+ formState: (tag, name, write) => `.${name}=${H} on <${tag}> binds form state as a property, which never reaches the ` +
31
+ `server and has a second spelling. Write ${write} instead: Gyral keeps it live ` +
32
+ `(view/02-bindings.md, "Live form state").`,
33
+ // 5
34
+ unquoted: (name) => `${name}=… mixes static text and holes without quotes, which is ambiguous. Quote the ` +
35
+ `whole value: ${name}="a ${H}".`,
36
+ notSingle: (name) => `${name} takes exactly one value and no static text. Write ${name}=${H}, and build the ` +
37
+ `value in the expression.`,
38
+ // 6
39
+ selfClosing: (tag) => `<${tag} /> is not self-closing in HTML: the parser ignores the "/", so <${tag}> would ` +
40
+ `swallow the siblings that follow it. Write <${tag}></${tag}>.`,
41
+ // 7
42
+ repaired: (what, write) => `${what}. The HTML parser repairs this markup, so the DOM would differ from the template ` +
43
+ `and part paths would shift. ${write}`,
44
+ badEndTag: () => `"</" must start an end tag such as </p>. For a literal "</" in text, write &lt;/.`,
45
+ unterminated: (what) => what === 'comment'
46
+ ? `The template ends inside a comment or <!…> declaration. Close it with -->.`
47
+ : `The template ends inside a tag, so the parser would drop it. Close the tag with ">".`,
48
+ // 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>.`,
51
+ // 11
52
+ serverOnly: () => SERVER_ONLY,
53
+ // 12 (proposed)
54
+ textContent: (tag) => `A hole in <${tag}> must be its whole content. Write <${tag}>${H}</${tag}> and build the ` +
55
+ `text in the value: <${tag}>\${\`\${page} | Site\`}</${tag}>.`,
56
+ // 13 (proposed)
57
+ charRef: (ref) => `&${ref}; in the static text of a bound or custom-element attribute is a named character ` +
58
+ `reference the normalizer doesn't decode (it knows &amp; &lt; &gt; &quot; &apos; &nbsp;). ` +
59
+ `Write the character itself, or a numeric reference such as &#169;.`,
60
+ };
61
+ /**
62
+ * Rule 4: property bindings that would be form state (view/02-bindings.md "Live form state").
63
+ * Returns the spelling to use instead, or undefined when the binding is fine.
64
+ */
65
+ const FORM_STATE = {
66
+ input: { value: `value=${H}`, checked: `?checked=${H}`, indeterminate: `?indeterminate=${H}` },
67
+ textarea: { value: `<textarea>${H}</textarea>` },
68
+ select: { value: `?selected=${H} on the chosen <option>` },
69
+ option: { selected: `?selected=${H}`, value: `value=${H}` },
70
+ details: { open: `?open=${H}` },
71
+ dialog: { open: `?open=${H}` },
72
+ };
73
+ /**
74
+ * Rule 4: property bindings that would be form state (view/02-bindings.md "Live form state").
75
+ * Returns the spelling to use instead, or undefined when the binding is fine.
76
+ */
77
+ export function formStateFix(tag, name) {
78
+ return FORM_STATE[tag]?.[name];
79
+ }
80
+ /** Rule 10: SVG element names that HTML doesn't share (lower case). */
81
+ export const SVG_ONLY = new Set(('animate animatemotion animatetransform circle clippath defs desc ellipse feblend ' +
82
+ 'fecolormatrix fecomponenttransfer fecomposite feconvolvematrix fediffuselighting ' +
83
+ 'fedisplacementmap fedropshadow feflood fegaussianblur feimage femerge femergenode ' +
84
+ 'femorphology feoffset fespecularlighting fetile feturbulence filter foreignobject g line ' +
85
+ 'lineargradient marker mask metadata mpath path pattern polygon polyline radialgradient ' +
86
+ 'rect stop symbol text textpath tspan use').split(' '));
87
+ /** HTML void elements: no end tag, no content. */
88
+ export const VOID = new Set(('area base basefont bgsound br col embed frame hr img input keygen link meta param source ' +
89
+ 'track wbr').split(' '));
90
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,5 @@
1
+ import type { Shape, TemplateObject } from './types.js';
2
+ /** The first place where `got` differs from `want`, as a message; undefined if none. */
3
+ export declare function shapeMismatch(want: Shape, got: Shape, path?: readonly number[]): string | undefined;
4
+ /** Rule 7's error for a parse that differs from the template's shape (`problem`). */
5
+ export declare function repairError(template: TemplateObject, parser: string, problem: string): Error;
@@ -0,0 +1,38 @@
1
+ // Rule 7 by comparison (view/09-template-rules.md "How rule 7 is checked"): the DOM an HTML
2
+ // parser built from a template's HTML, as a Shape, against the shape the normalizer computed
3
+ // the part paths for. Any difference means the parser repaired the markup. The runtime
4
+ // preparer feeds it the browser's own parse (prepare.ts); the Vite template compiler feeds it
5
+ // parse5's (src/compiler/parse5-check.ts). No DOM here: it runs in Node and in the browser.
6
+ import { TemplateError } from './errors.js';
7
+ const describe = (node) => node === undefined
8
+ ? 'nothing'
9
+ : typeof node === 'string'
10
+ ? node === '#text'
11
+ ? 'text'
12
+ : 'a comment'
13
+ : `<${node[0]}>`;
14
+ const same = (want, got) => typeof want === 'string' ? want === got : typeof got !== 'string' && want[0] === got[0];
15
+ /** The first place where `got` differs from `want`, as a message; undefined if none. */
16
+ export function shapeMismatch(want, got, path = []) {
17
+ for (let k = 0; k < Math.max(want.length, got.length); k++) {
18
+ const w = want[k];
19
+ const g = got[k];
20
+ if (w === undefined || g === undefined || !same(w, g)) {
21
+ return `at path [${[...path, k].join(', ')}]: expected ${describe(w)}, found ${describe(g)}`;
22
+ }
23
+ if (typeof w !== 'string' && typeof g !== 'string') {
24
+ const inner = shapeMismatch(w[1], g[1], [...path, k]);
25
+ if (inner !== undefined)
26
+ return inner;
27
+ }
28
+ }
29
+ return undefined;
30
+ }
31
+ /** Rule 7's error for a parse that differs from the template's shape (`problem`). */
32
+ export function repairError(template, parser, problem) {
33
+ return new TemplateError(7, `${parser} built a different DOM for this template ${problem}. It repaired the markup ` +
34
+ `(for example <tr> directly in <table>, a block element inside <p>, or <a> inside ` +
35
+ `<a>), so part paths would point at the wrong nodes. Write the valid structure ` +
36
+ `(<tbody>, closing </p> first, …).\n template: ${template.html.slice(0, 120)}`, template.loc);
37
+ }
38
+ //# sourceMappingURL=shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.js","sourceRoot":"","sources":["../../../src/view/normalize/shape.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,6FAA6F;AAC7F,uFAAuF;AACvF,8FAA8F;AAC9F,4FAA4F;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,QAAQ,GAAG,CAAC,IAA2B,EAAU,EAAE,CACvD,IAAI,KAAK,SAAS;IAChB,CAAC,CAAC,SAAS;IACX,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ;QACxB,CAAC,CAAC,IAAI,KAAK,OAAO;YAChB,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,WAAW;QACf,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAEvB,MAAM,IAAI,GAAG,CAAC,IAAe,EAAE,GAAc,EAAW,EAAE,CACxD,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AAE1F,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAC3B,IAAW,EACX,GAAU,EACV,OAA0B,EAAE;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACtD,OAAO,YAAY,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,CAAC,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACtD,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,WAAW,CAAC,QAAwB,EAAE,MAAc,EAAE,OAAe;IACnF,OAAO,IAAI,aAAa,CACtB,CAAC,EACD,GAAG,MAAM,4CAA4C,OAAO,2BAA2B;QACrF,mFAAmF;QACnF,gFAAgF;QAChF,kDAAkD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EACjF,QAAQ,CAAC,GAAG,CACb,CAAC;AACJ,CAAC","sourcesContent":["// Rule 7 by comparison (view/09-template-rules.md \"How rule 7 is checked\"): the DOM an HTML\n// parser built from a template's HTML, as a Shape, against the shape the normalizer computed\n// the part paths for. Any difference means the parser repaired the markup. The runtime\n// preparer feeds it the browser's own parse (prepare.ts); the Vite template compiler feeds it\n// parse5's (src/compiler/parse5-check.ts). No DOM here: it runs in Node and in the browser.\nimport { TemplateError } from './errors.js';\nimport type { Shape, ShapeNode, TemplateObject } from './types.js';\n\nconst describe = (node: ShapeNode | undefined): string =>\n node === undefined\n ? 'nothing'\n : typeof node === 'string'\n ? node === '#text'\n ? 'text'\n : 'a comment'\n : `<${node[0]}>`;\n\nconst same = (want: ShapeNode, got: ShapeNode): boolean =>\n typeof want === 'string' ? want === got : typeof got !== 'string' && want[0] === got[0];\n\n/** The first place where `got` differs from `want`, as a message; undefined if none. */\nexport function shapeMismatch(\n want: Shape,\n got: Shape,\n path: readonly number[] = [],\n): string | undefined {\n for (let k = 0; k < Math.max(want.length, got.length); k++) {\n const w = want[k];\n const g = got[k];\n if (w === undefined || g === undefined || !same(w, g)) {\n return `at path [${[...path, k].join(', ')}]: expected ${describe(w)}, found ${describe(g)}`;\n }\n if (typeof w !== 'string' && typeof g !== 'string') {\n const inner = shapeMismatch(w[1], g[1], [...path, k]);\n if (inner !== undefined) return inner;\n }\n }\n return undefined;\n}\n\n/** Rule 7's error for a parse that differs from the template's shape (`problem`). */\nexport function repairError(template: TemplateObject, parser: string, problem: string): Error {\n return new TemplateError(\n 7,\n `${parser} built a different DOM for this template ${problem}. It repaired the markup ` +\n `(for example <tr> directly in <table>, a block element inside <p>, or <a> inside ` +\n `<a>), so part paths would point at the wrong nodes. Write the valid structure ` +\n `(<tbody>, closing </p> first, …).\\n template: ${template.html.slice(0, 120)}`,\n template.loc,\n );\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export declare class Source {
2
+ readonly strings: readonly string[];
3
+ readonly loc: string | undefined;
4
+ /** Index of the string being read, and the offset in it. */
5
+ i: number;
6
+ pos: number;
7
+ constructor(strings: readonly string[], loc: string | undefined);
8
+ get last(): boolean;
9
+ /** The markup around the current position, with holes shown as `${…}`. */
10
+ near(): string;
11
+ /** Throws rule `rule`'s error, quoting the markup at the current position. */
12
+ fail(rule: number, message: string): never;
13
+ }
@@ -0,0 +1,34 @@
1
+ // The strings being normalized and the tokenizer's position in them, so every rule violation
2
+ // (view/09-template-rules.md) can quote the markup it is about.
3
+ import { TemplateError } from './errors.js';
4
+ const HOLE = '${…}';
5
+ export class Source {
6
+ constructor(strings, loc) {
7
+ this.strings = strings;
8
+ this.loc = loc;
9
+ /** Index of the string being read, and the offset in it. */
10
+ this.i = 0;
11
+ this.pos = 0;
12
+ }
13
+ get last() {
14
+ return this.i === this.strings.length - 1;
15
+ }
16
+ /** The markup around the current position, with holes shown as `${…}`. */
17
+ near() {
18
+ const s = this.strings[this.i] ?? '';
19
+ let before = s.slice(Math.max(0, this.pos - 40), this.pos);
20
+ if (this.pos < 40 && this.i > 0) {
21
+ before = (this.strings[this.i - 1] ?? '').slice(this.pos - 40) + HOLE + before;
22
+ }
23
+ let after = s.slice(this.pos, this.pos + 20);
24
+ if (this.pos + 20 > s.length && !this.last) {
25
+ after += HOLE + (this.strings[this.i + 1] ?? '').slice(0, 20 - after.length);
26
+ }
27
+ return `${before}${after}`.replace(/\s+/g, ' ').trim();
28
+ }
29
+ /** Throws rule `rule`'s error, quoting the markup at the current position. */
30
+ fail(rule, message) {
31
+ throw new TemplateError(rule, message, this.loc, this.near());
32
+ }
33
+ }
34
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/view/normalize/source.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,gEAAgE;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,IAAI,GAAG,MAAM,CAAC;AAEpB,MAAM,OAAO,MAAM;IAKjB,YACW,OAA0B,EAC1B,GAAuB;QADvB,YAAO,GAAP,OAAO,CAAmB;QAC1B,QAAG,GAAH,GAAG,CAAoB;QANlC,4DAA4D;QAC5D,MAAC,GAAG,CAAC,CAAC;QACN,QAAG,GAAG,CAAC,CAAC;IAKL,CAAC;IAEJ,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,0EAA0E;IAC1E,IAAI;QACF,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;QACjF,CAAC;QACD,IAAI,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3C,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,CAAC;IAED,8EAA8E;IAC9E,IAAI,CAAC,IAAY,EAAE,OAAe;QAChC,MAAM,IAAI,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;CACF","sourcesContent":["// The strings being normalized and the tokenizer's position in them, so every rule violation\n// (view/09-template-rules.md) can quote the markup it is about.\nimport { TemplateError } from './errors.js';\n\nconst HOLE = '${…}';\n\nexport class Source {\n /** Index of the string being read, and the offset in it. */\n i = 0;\n pos = 0;\n\n constructor(\n readonly strings: readonly string[],\n readonly loc: string | undefined,\n ) {}\n\n get last(): boolean {\n return this.i === this.strings.length - 1;\n }\n\n /** The markup around the current position, with holes shown as `${…}`. */\n near(): string {\n const s = this.strings[this.i] ?? '';\n let before = s.slice(Math.max(0, this.pos - 40), this.pos);\n if (this.pos < 40 && this.i > 0) {\n before = (this.strings[this.i - 1] ?? '').slice(this.pos - 40) + HOLE + before;\n }\n let after = s.slice(this.pos, this.pos + 20);\n if (this.pos + 20 > s.length && !this.last) {\n after += HOLE + (this.strings[this.i + 1] ?? '').slice(0, 20 - after.length);\n }\n return `${before}${after}`.replace(/\\s+/g, ' ').trim();\n }\n\n /** Throws rule `rule`'s error, quoting the markup at the current position. */\n fail(rule: number, message: string): never {\n throw new TemplateError(rule, message, this.loc, this.near());\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { Source } from './source.js';
2
+ import { type Sink, type StartTag, type State } from './tokens.js';
3
+ export declare abstract class TagStates {
4
+ protected readonly src: Source;
5
+ protected readonly sink: Sink;
6
+ protected state: State;
7
+ protected buf: string;
8
+ protected rawEnd: string;
9
+ protected tag: StartTag;
10
+ private attrName;
11
+ private pieces;
12
+ constructor(src: Source, sink: Sink);
13
+ protected tagChar(c: string): void;
14
+ private startName;
15
+ private endValueless;
16
+ private pushStatic;
17
+ private endQuoted;
18
+ /** A bound attribute named `attrName`; `strings` for a multi-attribute. */
19
+ private pushBound;
20
+ private emitTag;
21
+ /** A hole in a start tag (after string `src.i`). */
22
+ protected holeInTag(): void;
23
+ }
@@ -0,0 +1,192 @@
1
+ // The start-tag states of the template tokenizer (WHATWG HTML: before/after attribute name,
2
+ // attribute name, before attribute value, attribute value in double/single/no quotes, after
3
+ // attribute value, self-closing start tag), and what a hole means in each: an attribute,
4
+ // multi-attribute, boolean, property or hook (view/02-bindings.md), or rule 1, 2 or 5
5
+ // (view/09-template-rules.md). tokenizer.ts adds the data, comment and raw text states.
6
+ import { msg } from './rules.js';
7
+ import { isWs, S } from './tokens.js';
8
+ export class TagStates {
9
+ constructor(src, sink) {
10
+ this.src = src;
11
+ this.sink = sink;
12
+ this.state = S.Data;
13
+ this.buf = '';
14
+ this.rawEnd = '';
15
+ this.tag = { name: '', raw: '', attrs: [], selfClosing: false };
16
+ this.attrName = '';
17
+ this.pieces = [];
18
+ }
19
+ tagChar(c) {
20
+ this.src.pos += 1;
21
+ switch (this.state) {
22
+ case S.BeforeName:
23
+ if (isWs(c))
24
+ return;
25
+ if (c === '/')
26
+ this.state = S.SelfClosing;
27
+ else if (c === '>')
28
+ this.emitTag();
29
+ else
30
+ this.startName(c);
31
+ return;
32
+ case S.Name:
33
+ if (isWs(c))
34
+ this.state = S.AfterName;
35
+ else if (c === '=')
36
+ this.state = S.BeforeValue;
37
+ else if (c === '/' || c === '>')
38
+ this.endValueless(c);
39
+ else
40
+ this.attrName += c;
41
+ return;
42
+ case S.AfterName:
43
+ if (isWs(c))
44
+ return;
45
+ if (c === '=')
46
+ this.state = S.BeforeValue;
47
+ else if (c === '/' || c === '>')
48
+ this.endValueless(c);
49
+ else {
50
+ this.pushStatic(null);
51
+ this.startName(c);
52
+ }
53
+ return;
54
+ case S.BeforeValue:
55
+ if (isWs(c))
56
+ return;
57
+ this.buf = '';
58
+ this.pieces = [];
59
+ if (c === '"')
60
+ this.state = S.ValueDq;
61
+ else if (c === "'")
62
+ this.state = S.ValueSq;
63
+ else if (c === '>') {
64
+ this.pushStatic('""');
65
+ this.emitTag();
66
+ }
67
+ else {
68
+ this.buf = c;
69
+ this.state = S.ValueUnq;
70
+ }
71
+ return;
72
+ case S.ValueDq:
73
+ case S.ValueSq:
74
+ if (c === (this.state === S.ValueDq ? '"' : "'"))
75
+ this.endQuoted(c);
76
+ else
77
+ this.buf += c;
78
+ return;
79
+ case S.ValueUnq:
80
+ if (isWs(c) || c === '>') {
81
+ this.pushStatic(this.buf);
82
+ this.state = S.BeforeName;
83
+ if (c === '>')
84
+ this.emitTag();
85
+ }
86
+ else
87
+ this.buf += c;
88
+ return;
89
+ default:
90
+ // AfterValueQ and SelfClosing: `>` ends the tag, anything else starts a new attribute.
91
+ if (c === '>') {
92
+ this.tag.selfClosing = this.state === S.SelfClosing;
93
+ this.emitTag();
94
+ }
95
+ else if (c === '/')
96
+ this.state = S.SelfClosing;
97
+ else if (!isWs(c))
98
+ this.startName(c);
99
+ else
100
+ this.state = S.BeforeName;
101
+ }
102
+ }
103
+ startName(c) {
104
+ this.attrName = c;
105
+ this.state = S.Name;
106
+ }
107
+ endValueless(c) {
108
+ this.pushStatic(null);
109
+ if (c === '>')
110
+ this.emitTag();
111
+ else
112
+ this.state = S.SelfClosing;
113
+ }
114
+ pushStatic(value) {
115
+ this.tag.attrs.push({ kind: 'static', name: this.attrName, value });
116
+ }
117
+ endQuoted(quote) {
118
+ this.state = S.AfterValueQ;
119
+ if (this.pieces.length === 0) {
120
+ this.pushStatic(quote + this.buf + quote);
121
+ return;
122
+ }
123
+ this.pieces.push(this.buf);
124
+ const single = this.pieces.length === 2 && this.pieces[0] === '' && this.pieces[1] === '';
125
+ this.pushBound(single ? undefined : this.pieces);
126
+ }
127
+ /** A bound attribute named `attrName`; `strings` for a multi-attribute. */
128
+ pushBound(strings) {
129
+ const name = this.attrName;
130
+ const prefix = name.charAt(0);
131
+ if (prefix === '@')
132
+ this.src.fail(1, msg.eventBinding(name));
133
+ if (prefix === '?' || prefix === '.') {
134
+ if (strings !== undefined)
135
+ this.src.fail(5, msg.notSingle(name));
136
+ const kind = prefix === '?' ? 'bool' : 'prop';
137
+ this.tag.attrs.push({ kind, name: name.slice(1) });
138
+ return;
139
+ }
140
+ this.tag.attrs.push(strings === undefined ? { kind: 'attr', name } : { kind: 'attr', name, strings });
141
+ }
142
+ emitTag() {
143
+ const mode = this.sink.start(this.tag);
144
+ this.rawEnd = this.tag.name;
145
+ this.state = mode === 'data' ? S.Data : mode === 'rawtext' ? S.RawText : S.RcData;
146
+ }
147
+ /** A hole in a start tag (after string `src.i`). */
148
+ holeInTag() {
149
+ const { src } = this;
150
+ const next = src.strings[src.i + 1] ?? '';
151
+ const c = next.charAt(0);
152
+ const event = this.attrName.startsWith('@');
153
+ switch (this.state) {
154
+ case S.Name:
155
+ if (event)
156
+ src.fail(1, msg.eventBinding(this.attrName));
157
+ src.fail(2, msg.dynamicName());
158
+ break;
159
+ case S.BeforeValue: {
160
+ // The template ending here is rule 7 (unterminated tag), reported by the tokenizer.
161
+ const atEnd = c === '' && src.i + 1 === src.strings.length - 1;
162
+ const ends = isWs(c) || c === '>' || next.startsWith('/>') || atEnd;
163
+ if (!event && !ends)
164
+ src.fail(5, msg.unquoted(this.attrName));
165
+ this.pushBound(undefined);
166
+ this.state = S.BeforeName;
167
+ break;
168
+ }
169
+ case S.ValueUnq:
170
+ if (event)
171
+ src.fail(1, msg.eventBinding(this.attrName));
172
+ src.fail(5, msg.unquoted(this.attrName));
173
+ break;
174
+ case S.ValueDq:
175
+ case S.ValueSq:
176
+ if (event)
177
+ src.fail(1, msg.eventBinding(this.attrName));
178
+ this.pieces.push(this.buf);
179
+ this.buf = '';
180
+ break;
181
+ default:
182
+ // Before an attribute name: an element hook.
183
+ if (this.state === S.AfterName)
184
+ this.pushStatic(null);
185
+ if (c !== '' && !isWs(c) && c !== '>' && c !== '/')
186
+ src.fail(2, msg.dynamicName());
187
+ this.tag.attrs.push({ kind: 'hook', name: '' });
188
+ this.state = S.BeforeName;
189
+ }
190
+ }
191
+ }
192
+ //# sourceMappingURL=tag-states.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-states.js","sourceRoot":"","sources":["../../../src/view/normalize/tag-states.ts"],"names":[],"mappings":"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","sourcesContent":["// The start-tag states of the template tokenizer (WHATWG HTML: before/after attribute name,\n// attribute name, before attribute value, attribute value in double/single/no quotes, after\n// attribute value, self-closing start tag), and what a hole means in each: an attribute,\n// multi-attribute, boolean, property or hook (view/02-bindings.md), or rule 1, 2 or 5\n// (view/09-template-rules.md). tokenizer.ts adds the data, comment and raw text states.\nimport { msg } from './rules.js';\nimport type { Source } from './source.js';\nimport { isWs, S, type Sink, type StartTag, type State } from './tokens.js';\n\nexport abstract class TagStates {\n protected state: State = S.Data;\n protected buf = '';\n protected rawEnd = '';\n protected tag: StartTag = { name: '', raw: '', attrs: [], selfClosing: false };\n private attrName = '';\n private pieces: string[] = [];\n\n constructor(\n protected readonly src: Source,\n protected readonly sink: Sink,\n ) {}\n\n protected tagChar(c: string): void {\n this.src.pos += 1;\n switch (this.state) {\n case S.BeforeName:\n if (isWs(c)) return;\n if (c === '/') this.state = S.SelfClosing;\n else if (c === '>') this.emitTag();\n else this.startName(c);\n return;\n case S.Name:\n if (isWs(c)) this.state = S.AfterName;\n else if (c === '=') this.state = S.BeforeValue;\n else if (c === '/' || c === '>') this.endValueless(c);\n else this.attrName += c;\n return;\n case S.AfterName:\n if (isWs(c)) return;\n if (c === '=') this.state = S.BeforeValue;\n else if (c === '/' || c === '>') this.endValueless(c);\n else {\n this.pushStatic(null);\n this.startName(c);\n }\n return;\n case S.BeforeValue:\n if (isWs(c)) return;\n this.buf = '';\n this.pieces = [];\n if (c === '\"') this.state = S.ValueDq;\n else if (c === \"'\") this.state = S.ValueSq;\n else if (c === '>') {\n this.pushStatic('\"\"');\n this.emitTag();\n } else {\n this.buf = c;\n this.state = S.ValueUnq;\n }\n return;\n case S.ValueDq:\n case S.ValueSq:\n if (c === (this.state === S.ValueDq ? '\"' : \"'\")) this.endQuoted(c);\n else this.buf += c;\n return;\n case S.ValueUnq:\n if (isWs(c) || c === '>') {\n this.pushStatic(this.buf);\n this.state = S.BeforeName;\n if (c === '>') this.emitTag();\n } else this.buf += c;\n return;\n default:\n // AfterValueQ and SelfClosing: `>` ends the tag, anything else starts a new attribute.\n if (c === '>') {\n this.tag.selfClosing = this.state === S.SelfClosing;\n this.emitTag();\n } else if (c === '/') this.state = S.SelfClosing;\n else if (!isWs(c)) this.startName(c);\n else this.state = S.BeforeName;\n }\n }\n\n private startName(c: string): void {\n this.attrName = c;\n this.state = S.Name;\n }\n\n private endValueless(c: string): void {\n this.pushStatic(null);\n if (c === '>') this.emitTag();\n else this.state = S.SelfClosing;\n }\n\n private pushStatic(value: string | null): void {\n this.tag.attrs.push({ kind: 'static', name: this.attrName, value });\n }\n\n private endQuoted(quote: string): void {\n this.state = S.AfterValueQ;\n if (this.pieces.length === 0) {\n this.pushStatic(quote + this.buf + quote);\n return;\n }\n this.pieces.push(this.buf);\n const single = this.pieces.length === 2 && this.pieces[0] === '' && this.pieces[1] === '';\n this.pushBound(single ? undefined : this.pieces);\n }\n\n /** A bound attribute named `attrName`; `strings` for a multi-attribute. */\n private pushBound(strings: readonly string[] | undefined): void {\n const name = this.attrName;\n const prefix = name.charAt(0);\n if (prefix === '@') this.src.fail(1, msg.eventBinding(name));\n if (prefix === '?' || prefix === '.') {\n if (strings !== undefined) this.src.fail(5, msg.notSingle(name));\n const kind = prefix === '?' ? 'bool' : 'prop';\n this.tag.attrs.push({ kind, name: name.slice(1) });\n return;\n }\n this.tag.attrs.push(\n strings === undefined ? { kind: 'attr', name } : { kind: 'attr', name, strings },\n );\n }\n\n private emitTag(): void {\n const mode = this.sink.start(this.tag);\n this.rawEnd = this.tag.name;\n this.state = mode === 'data' ? S.Data : mode === 'rawtext' ? S.RawText : S.RcData;\n }\n\n /** A hole in a start tag (after string `src.i`). */\n protected holeInTag(): void {\n const { src } = this;\n const next = src.strings[src.i + 1] ?? '';\n const c = next.charAt(0);\n const event = this.attrName.startsWith('@');\n switch (this.state) {\n case S.Name:\n if (event) src.fail(1, msg.eventBinding(this.attrName));\n src.fail(2, msg.dynamicName());\n break;\n case S.BeforeValue: {\n // The template ending here is rule 7 (unterminated tag), reported by the tokenizer.\n const atEnd = c === '' && src.i + 1 === src.strings.length - 1;\n const ends = isWs(c) || c === '>' || next.startsWith('/>') || atEnd;\n if (!event && !ends) src.fail(5, msg.unquoted(this.attrName));\n this.pushBound(undefined);\n this.state = S.BeforeName;\n break;\n }\n case S.ValueUnq:\n if (event) src.fail(1, msg.eventBinding(this.attrName));\n src.fail(5, msg.unquoted(this.attrName));\n break;\n case S.ValueDq:\n case S.ValueSq:\n if (event) src.fail(1, msg.eventBinding(this.attrName));\n this.pieces.push(this.buf);\n this.buf = '';\n break;\n default:\n // Before an attribute name: an element hook.\n if (this.state === S.AfterName) this.pushStatic(null);\n if (c !== '' && !isWs(c) && c !== '>' && c !== '/') src.fail(2, msg.dynamicName());\n this.tag.attrs.push({ kind: 'hook', name: '' });\n this.state = S.BeforeName;\n }\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import type { Source } from './source.js';
2
+ import { type Sink } from './tokens.js';
3
+ export type { AttrToken, ContentMode, Sink, StartTag } from './tokens.js';
4
+ /** Tokenizes `src.strings`, sending tokens and holes to `sink`. */
5
+ export declare function tokenize(src: Source, sink: Sink): void;