@gyral/core 0.1.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 (340) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +1 -1
  3. package/NOTICE +1 -1
  4. package/README.md +9 -7
  5. package/dist/children.d.ts +5 -2
  6. package/dist/children.js +8 -3
  7. package/dist/children.js.map +1 -1
  8. package/dist/command.js +6 -0
  9. package/dist/command.js.map +1 -1
  10. package/dist/compiler/ast.d.ts +21 -0
  11. package/dist/compiler/ast.js +145 -0
  12. package/dist/compiler/ast.js.map +1 -0
  13. package/dist/compiler/compile.d.ts +38 -0
  14. package/dist/compiler/compile.js +129 -0
  15. package/dist/compiler/compile.js.map +1 -0
  16. package/dist/compiler/hooks.d.ts +18 -0
  17. package/dist/compiler/hooks.js +186 -0
  18. package/dist/compiler/hooks.js.map +1 -0
  19. package/dist/compiler/parse5-check.d.ts +21 -0
  20. package/dist/compiler/parse5-check.js +55 -0
  21. package/dist/compiler/parse5-check.js.map +1 -0
  22. package/dist/compiler/scan.d.ts +31 -0
  23. package/dist/compiler/scan.js +152 -0
  24. package/dist/compiler/scan.js.map +1 -0
  25. package/dist/compiler/source.d.ts +34 -0
  26. package/dist/compiler/source.js +114 -0
  27. package/dist/compiler/source.js.map +1 -0
  28. package/dist/define.d.ts +2 -2
  29. package/dist/define.js +35 -334
  30. package/dist/define.js.map +1 -1
  31. package/dist/devtools-events.d.ts +5 -0
  32. package/dist/devtools-events.js.map +1 -1
  33. package/dist/devtools-off.d.ts +1 -0
  34. package/dist/devtools-off.js +1 -0
  35. package/dist/devtools-off.js.map +1 -1
  36. package/dist/devtools.d.ts +1 -0
  37. package/dist/devtools.js +3 -0
  38. package/dist/devtools.js.map +1 -1
  39. package/dist/drivers-scope.d.ts +1 -1
  40. package/dist/drivers-scope.js +1 -8
  41. package/dist/drivers-scope.js.map +1 -1
  42. package/dist/element-types.d.ts +5 -3
  43. package/dist/element-types.js.map +1 -1
  44. package/dist/element.d.ts +3 -0
  45. package/dist/element.js +269 -0
  46. package/dist/element.js.map +1 -0
  47. package/dist/eslint/imports.d.ts +24 -0
  48. package/dist/eslint/imports.js +78 -0
  49. package/dist/eslint/imports.js.map +1 -0
  50. package/dist/eslint/index.d.ts +15 -0
  51. package/dist/eslint/index.js +15 -0
  52. package/dist/eslint/index.js.map +1 -0
  53. package/dist/eslint/locate.d.ts +33 -0
  54. package/dist/eslint/locate.js +132 -0
  55. package/dist/eslint/locate.js.map +1 -0
  56. package/dist/eslint/row-purity-rule.d.ts +2 -0
  57. package/dist/eslint/row-purity-rule.js +103 -0
  58. package/dist/eslint/row-purity-rule.js.map +1 -0
  59. package/dist/eslint/template-rule.d.ts +5 -0
  60. package/dist/eslint/template-rule.js +66 -0
  61. package/dist/eslint/template-rule.js.map +1 -0
  62. package/dist/features.d.ts +39 -0
  63. package/dist/features.js +2 -0
  64. package/dist/features.js.map +1 -0
  65. package/dist/focus.d.ts +9 -2
  66. package/dist/focus.js +17 -2
  67. package/dist/focus.js.map +1 -1
  68. package/dist/hooks/invalid.d.ts +14 -0
  69. package/dist/hooks/invalid.js +72 -0
  70. package/dist/hooks/invalid.js.map +1 -0
  71. package/dist/hooks/labelled-by.d.ts +13 -0
  72. package/dist/hooks/labelled-by.js +51 -0
  73. package/dist/hooks/labelled-by.js.map +1 -0
  74. package/dist/host-model.d.ts +48 -0
  75. package/dist/host-model.js +155 -0
  76. package/dist/host-model.js.map +1 -0
  77. package/dist/hydration-client.d.ts +9 -0
  78. package/dist/hydration-client.js +35 -0
  79. package/dist/hydration-client.js.map +1 -0
  80. package/dist/hydration.d.ts +13 -19
  81. package/dist/hydration.js +45 -45
  82. package/dist/hydration.js.map +1 -1
  83. package/dist/index.d.ts +9 -16
  84. package/dist/index.js +9 -16
  85. package/dist/index.js.map +1 -1
  86. package/dist/intent.d.ts +31 -8
  87. package/dist/intent.js +82 -27
  88. package/dist/intent.js.map +1 -1
  89. package/dist/internal/interpreter.d.ts +7 -1
  90. package/dist/internal/interpreter.js +118 -73
  91. package/dist/internal/interpreter.js.map +1 -1
  92. package/dist/invokers-shim.d.ts +6 -0
  93. package/dist/invokers-shim.js +32 -0
  94. package/dist/invokers-shim.js.map +1 -0
  95. package/dist/invokers.d.ts +3 -5
  96. package/dist/invokers.js +11 -51
  97. package/dist/invokers.js.map +1 -1
  98. package/dist/islands.d.ts +0 -2
  99. package/dist/islands.js +4 -11
  100. package/dist/islands.js.map +1 -1
  101. package/dist/light-dom.d.ts +3 -52
  102. package/dist/light-dom.js +5 -100
  103. package/dist/light-dom.js.map +1 -1
  104. package/dist/prop.d.ts +66 -0
  105. package/dist/prop.js +22 -0
  106. package/dist/prop.js.map +1 -0
  107. package/dist/props.d.ts +52 -21
  108. package/dist/props.js +150 -34
  109. package/dist/props.js.map +1 -1
  110. package/dist/scheduler.d.ts +39 -0
  111. package/dist/scheduler.js +230 -0
  112. package/dist/scheduler.js.map +1 -0
  113. package/dist/server-component.d.ts +10 -0
  114. package/dist/server-component.js +102 -0
  115. package/dist/server-component.js.map +1 -0
  116. package/dist/server-specs.d.ts +6 -0
  117. package/dist/server-specs.js +13 -0
  118. package/dist/server-specs.js.map +1 -0
  119. package/dist/server.d.ts +28 -0
  120. package/dist/server.js +50 -0
  121. package/dist/server.js.map +1 -0
  122. package/dist/settled.d.ts +10 -0
  123. package/dist/settled.js +40 -0
  124. package/dist/settled.js.map +1 -0
  125. package/dist/states.d.ts +3 -3
  126. package/dist/states.js +4 -7
  127. package/dist/states.js.map +1 -1
  128. package/dist/store-binding.d.ts +6 -3
  129. package/dist/store-binding.js +5 -6
  130. package/dist/store-binding.js.map +1 -1
  131. package/dist/store-scope.d.ts +6 -7
  132. package/dist/store-scope.js +11 -26
  133. package/dist/store-scope.js.map +1 -1
  134. package/dist/store.d.ts +3 -0
  135. package/dist/store.js +9 -2
  136. package/dist/store.js.map +1 -1
  137. package/dist/stores-provider.d.ts +2 -6
  138. package/dist/stores-provider.js +21 -55
  139. package/dist/stores-provider.js.map +1 -1
  140. package/dist/transitions.d.ts +5 -6
  141. package/dist/transitions.js +11 -20
  142. package/dist/transitions.js.map +1 -1
  143. package/dist/types.d.ts +19 -23
  144. package/dist/types.js.map +1 -1
  145. package/dist/view/attributes.d.ts +6 -0
  146. package/dist/view/attributes.js +10 -0
  147. package/dist/view/attributes.js.map +1 -0
  148. package/dist/view/compiled.d.ts +1 -0
  149. package/dist/view/compiled.js +6 -0
  150. package/dist/view/compiled.js.map +1 -0
  151. package/dist/view/dev-off.d.ts +1 -0
  152. package/dist/view/dev-off.js +4 -0
  153. package/dist/view/dev-off.js.map +1 -0
  154. package/dist/view/dev.d.ts +1 -0
  155. package/dist/view/dev.js +5 -0
  156. package/dist/view/dev.js.map +1 -0
  157. package/dist/view/flags.d.ts +1 -0
  158. package/dist/view/flags.js +4 -0
  159. package/dist/view/flags.js.map +1 -0
  160. package/dist/view/index.d.ts +21 -0
  161. package/dist/view/index.js +21 -0
  162. package/dist/view/index.js.map +1 -0
  163. package/dist/view/normalize/check.d.ts +20 -0
  164. package/dist/view/normalize/check.js +78 -0
  165. package/dist/view/normalize/check.js.map +1 -0
  166. package/dist/view/normalize/emit.d.ts +13 -0
  167. package/dist/view/normalize/emit.js +136 -0
  168. package/dist/view/normalize/emit.js.map +1 -0
  169. package/dist/view/normalize/entities.d.ts +4 -0
  170. package/dist/view/normalize/entities.js +38 -0
  171. package/dist/view/normalize/entities.js.map +1 -0
  172. package/dist/view/normalize/errors.d.ts +9 -0
  173. package/dist/view/normalize/errors.js +19 -0
  174. package/dist/view/normalize/errors.js.map +1 -0
  175. package/dist/view/normalize/id.d.ts +7 -0
  176. package/dist/view/normalize/id.js +48 -0
  177. package/dist/view/normalize/id.js.map +1 -0
  178. package/dist/view/normalize/normalize.d.ts +15 -0
  179. package/dist/view/normalize/normalize.js +36 -0
  180. package/dist/view/normalize/normalize.js.map +1 -0
  181. package/dist/view/normalize/repairs.d.ts +24 -0
  182. package/dist/view/normalize/repairs.js +166 -0
  183. package/dist/view/normalize/repairs.js.map +1 -0
  184. package/dist/view/normalize/rules.d.ts +30 -0
  185. package/dist/view/normalize/rules.js +90 -0
  186. package/dist/view/normalize/rules.js.map +1 -0
  187. package/dist/view/normalize/shape.d.ts +5 -0
  188. package/dist/view/normalize/shape.js +38 -0
  189. package/dist/view/normalize/shape.js.map +1 -0
  190. package/dist/view/normalize/source.d.ts +13 -0
  191. package/dist/view/normalize/source.js +34 -0
  192. package/dist/view/normalize/source.js.map +1 -0
  193. package/dist/view/normalize/tag-states.d.ts +23 -0
  194. package/dist/view/normalize/tag-states.js +192 -0
  195. package/dist/view/normalize/tag-states.js.map +1 -0
  196. package/dist/view/normalize/tokenizer.d.ts +5 -0
  197. package/dist/view/normalize/tokenizer.js +233 -0
  198. package/dist/view/normalize/tokenizer.js.map +1 -0
  199. package/dist/view/normalize/tokens.d.ts +51 -0
  200. package/dist/view/normalize/tokens.js +24 -0
  201. package/dist/view/normalize/tokens.js.map +1 -0
  202. package/dist/view/normalize/tree.d.ts +59 -0
  203. package/dist/view/normalize/tree.js +190 -0
  204. package/dist/view/normalize/tree.js.map +1 -0
  205. package/dist/view/normalize/types.d.ts +126 -0
  206. package/dist/view/normalize/types.js +26 -0
  207. package/dist/view/normalize/types.js.map +1 -0
  208. package/dist/view/normalize/whitespace.d.ts +2 -0
  209. package/dist/view/normalize/whitespace.js +182 -0
  210. package/dist/view/normalize/whitespace.js.map +1 -0
  211. package/dist/view/prepare-stub.d.ts +3 -0
  212. package/dist/view/prepare-stub.js +7 -0
  213. package/dist/view/prepare-stub.js.map +1 -0
  214. package/dist/view/prepare.d.ts +8 -0
  215. package/dist/view/prepare.js +57 -0
  216. package/dist/view/prepare.js.map +1 -0
  217. package/dist/view/registry.d.ts +63 -0
  218. package/dist/view/registry.js +19 -0
  219. package/dist/view/registry.js.map +1 -0
  220. package/dist/view/render/adopt-attr.d.ts +14 -0
  221. package/dist/view/render/adopt-attr.js +77 -0
  222. package/dist/view/render/adopt-attr.js.map +1 -0
  223. package/dist/view/render/adopt-plan.d.ts +10 -0
  224. package/dist/view/render/adopt-plan.js +26 -0
  225. package/dist/view/render/adopt-plan.js.map +1 -0
  226. package/dist/view/render/adopt.d.ts +3 -0
  227. package/dist/view/render/adopt.js +269 -0
  228. package/dist/view/render/adopt.js.map +1 -0
  229. package/dist/view/render/attr-parts.d.ts +61 -0
  230. package/dist/view/render/attr-parts.js +229 -0
  231. package/dist/view/render/attr-parts.js.map +1 -0
  232. package/dist/view/render/child-part.d.ts +51 -0
  233. package/dist/view/render/child-part.js +170 -0
  234. package/dist/view/render/child-part.js.map +1 -0
  235. package/dist/view/render/dev-check.d.ts +12 -0
  236. package/dist/view/render/dev-check.js +122 -0
  237. package/dist/view/render/dev-check.js.map +1 -0
  238. package/dist/view/render/hook-part.d.ts +3 -0
  239. package/dist/view/render/hook-part.js +20 -0
  240. package/dist/view/render/hook-part.js.map +1 -0
  241. package/dist/view/render/hooks.d.ts +40 -0
  242. package/dist/view/render/hooks.js +46 -0
  243. package/dist/view/render/hooks.js.map +1 -0
  244. package/dist/view/render/hydrate.d.ts +10 -0
  245. package/dist/view/render/hydrate.js +33 -0
  246. package/dist/view/render/hydrate.js.map +1 -0
  247. package/dist/view/render/instance.d.ts +33 -0
  248. package/dist/view/render/instance.js +107 -0
  249. package/dist/view/render/instance.js.map +1 -0
  250. package/dist/view/render/list.d.ts +20 -0
  251. package/dist/view/render/list.js +156 -0
  252. package/dist/view/render/list.js.map +1 -0
  253. package/dist/view/render/mismatch.d.ts +10 -0
  254. package/dist/view/render/mismatch.js +53 -0
  255. package/dist/view/render/mismatch.js.map +1 -0
  256. package/dist/view/render/nodes.d.ts +10 -0
  257. package/dist/view/render/nodes.js +37 -0
  258. package/dist/view/render/nodes.js.map +1 -0
  259. package/dist/view/render/place.d.ts +18 -0
  260. package/dist/view/render/place.js +69 -0
  261. package/dist/view/render/place.js.map +1 -0
  262. package/dist/view/render/plan.d.ts +26 -0
  263. package/dist/view/render/plan.js +124 -0
  264. package/dist/view/render/plan.js.map +1 -0
  265. package/dist/view/render/raw.d.ts +18 -0
  266. package/dist/view/render/raw.js +68 -0
  267. package/dist/view/render/raw.js.map +1 -0
  268. package/dist/view/render/render.d.ts +12 -0
  269. package/dist/view/render/render.js +60 -0
  270. package/dist/view/render/render.js.map +1 -0
  271. package/dist/view/render/reorder.d.ts +4 -0
  272. package/dist/view/render/reorder.js +101 -0
  273. package/dist/view/render/reorder.js.map +1 -0
  274. package/dist/view/render/rows.d.ts +23 -0
  275. package/dist/view/render/rows.js +95 -0
  276. package/dist/view/render/rows.js.map +1 -0
  277. package/dist/view/render/seen.d.ts +11 -0
  278. package/dist/view/render/seen.js +17 -0
  279. package/dist/view/render/seen.js.map +1 -0
  280. package/dist/view/render/values.d.ts +29 -0
  281. package/dist/view/render/values.js +13 -0
  282. package/dist/view/render/values.js.map +1 -0
  283. package/dist/view/render/warn.d.ts +14 -0
  284. package/dist/view/render/warn.js +69 -0
  285. package/dist/view/render/warn.js.map +1 -0
  286. package/dist/view/server/component.d.ts +9 -0
  287. package/dist/view/server/component.js +42 -0
  288. package/dist/view/server/component.js.map +1 -0
  289. package/dist/view/server/escape.d.ts +10 -0
  290. package/dist/view/server/escape.js +34 -0
  291. package/dist/view/server/escape.js.map +1 -0
  292. package/dist/view/server/index.d.ts +28 -0
  293. package/dist/view/server/index.js +72 -0
  294. package/dist/view/server/index.js.map +1 -0
  295. package/dist/view/server/sha256.d.ts +2 -0
  296. package/dist/view/server/sha256.js +75 -0
  297. package/dist/view/server/sha256.js.map +1 -0
  298. package/dist/view/server/tags.d.ts +57 -0
  299. package/dist/view/server/tags.js +121 -0
  300. package/dist/view/server/tags.js.map +1 -0
  301. package/dist/view/server/values.d.ts +16 -0
  302. package/dist/view/server/values.js +86 -0
  303. package/dist/view/server/values.js.map +1 -0
  304. package/dist/view/server/writer.d.ts +16 -0
  305. package/dist/view/server/writer.js +155 -0
  306. package/dist/view/server/writer.js.map +1 -0
  307. package/dist/view/styles.d.ts +25 -0
  308. package/dist/view/styles.js +58 -0
  309. package/dist/view/styles.js.map +1 -0
  310. package/dist/view/template-element.d.ts +3 -0
  311. package/dist/view/template-element.js +25 -0
  312. package/dist/view/template-element.js.map +1 -0
  313. package/dist/view/template.d.ts +21 -0
  314. package/dist/view/template.js +30 -0
  315. package/dist/view/template.js.map +1 -0
  316. package/dist/vite.d.ts +45 -6
  317. package/dist/vite.js +150 -25
  318. package/dist/vite.js.map +1 -1
  319. package/package.json +41 -7
  320. package/dist/accessible-name.d.ts +0 -19
  321. package/dist/accessible-name.js +0 -56
  322. package/dist/accessible-name.js.map +0 -1
  323. package/dist/element-directive.d.ts +0 -20
  324. package/dist/element-directive.js +0 -31
  325. package/dist/element-directive.js.map +0 -1
  326. package/dist/internal/runtime.d.ts +0 -7
  327. package/dist/internal/runtime.js +0 -8
  328. package/dist/internal/runtime.js.map +0 -1
  329. package/dist/invalid.d.ts +0 -21
  330. package/dist/invalid.js +0 -70
  331. package/dist/invalid.js.map +0 -1
  332. package/dist/live-boolean.d.ts +0 -22
  333. package/dist/live-boolean.js +0 -34
  334. package/dist/live-boolean.js.map +0 -1
  335. package/dist/styles.d.ts +0 -12
  336. package/dist/styles.js +0 -11
  337. package/dist/styles.js.map +0 -1
  338. package/dist/textarea.d.ts +0 -26
  339. package/dist/textarea.js +0 -85
  340. package/dist/textarea.js.map +0 -1
@@ -0,0 +1,78 @@
1
+ // The template rules (view/09-template-rules.md) as a check that reports where it stopped, for
2
+ // tools that point at the markup (the ESLint plugin, @gyral/core/eslint). It runs the same
3
+ // steps as `analyze` (normalize.ts) up to the last one that can fail: minify whitespace, then
4
+ // tokenize and build the tree (emit and the id never throw). Like the compiler and the runtime,
5
+ // it stops at a template's first error: the tokenizer can't recover from one.
6
+ import { TemplateError } from './errors.js';
7
+ import { Source } from './source.js';
8
+ import { tokenize } from './tokenizer.js';
9
+ import { TreeBuilder } from './tree.js';
10
+ import { minifyStrings } from './whitespace.js';
11
+ /** Forwards tokens to the tree builder, remembering where the current token started. */
12
+ class Tracker {
13
+ constructor(src, tree) {
14
+ this.src = src;
15
+ this.tree = tree;
16
+ this.mark = [0, 0];
17
+ }
18
+ /** A token starts at `mark`; an error before `after` is about it (a child hole: the hole). */
19
+ before(about = true) {
20
+ this.from = about ? this.mark : undefined;
21
+ }
22
+ after() {
23
+ this.from = undefined;
24
+ this.mark = [this.src.i, this.src.pos];
25
+ }
26
+ text(raw) {
27
+ this.before();
28
+ this.tree.text(raw);
29
+ this.after();
30
+ }
31
+ comment(raw) {
32
+ this.before();
33
+ this.tree.comment(raw);
34
+ this.after();
35
+ }
36
+ doctype(raw) {
37
+ this.before();
38
+ this.tree.doctype(raw);
39
+ this.after();
40
+ }
41
+ start(tag) {
42
+ this.before();
43
+ const mode = this.tree.start(tag);
44
+ this.after();
45
+ return mode;
46
+ }
47
+ end(name) {
48
+ this.before();
49
+ this.tree.end(name);
50
+ this.after();
51
+ }
52
+ hole(kind) {
53
+ this.before(false);
54
+ this.tree.hole(kind);
55
+ this.after();
56
+ }
57
+ finish() {
58
+ this.before();
59
+ this.tree.finish();
60
+ this.after();
61
+ }
62
+ }
63
+ /** The template's first rule violation, or undefined when `normalize` would accept it. */
64
+ export function checkTemplate(strings) {
65
+ const normalized = minifyStrings(strings);
66
+ const src = new Source(normalized, undefined);
67
+ const tracker = new Tracker(src, new TreeBuilder(src));
68
+ try {
69
+ tokenize(src, tracker);
70
+ }
71
+ catch (error) {
72
+ if (!(error instanceof TemplateError))
73
+ throw error;
74
+ return { error, strings: normalized, at: [src.i, src.pos], from: tracker.from };
75
+ }
76
+ return undefined;
77
+ }
78
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/view/normalize/check.ts"],"names":[],"mappings":"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","sourcesContent":["// The template rules (view/09-template-rules.md) as a check that reports where it stopped, for\n// tools that point at the markup (the ESLint plugin, @gyral/core/eslint). It runs the same\n// steps as `analyze` (normalize.ts) up to the last one that can fail: minify whitespace, then\n// tokenize and build the tree (emit and the id never throw). Like the compiler and the runtime,\n// it stops at a template's first error: the tokenizer can't recover from one.\nimport { TemplateError } from './errors.js';\nimport { Source } from './source.js';\nimport { tokenize, type ContentMode, type Sink, type StartTag } from './tokenizer.js';\nimport { TreeBuilder } from './tree.js';\nimport { minifyStrings } from './whitespace.js';\n\n/** A position in the minified strings: string index, offset in that string. */\nexport type At = readonly [index: number, offset: number];\n\n/** A template's first rule violation, and where the normalizer was when it found it. */\nexport interface TemplateIssue {\n /** The same error `normalize(strings)` throws. */\n readonly error: TemplateError;\n /** The whitespace-minified strings the rules read (as many as the input). */\n readonly strings: readonly string[];\n /** Where reading stopped. */\n readonly at: At;\n /**\n * Where the token the error is about starts, when the tree builder found it in a tag, an end\n * tag or a run of text (the token ends at `at`). Undefined when the tokenizer found it at\n * `at` itself, or at a child hole (then `at` is the end of the string before the hole).\n */\n readonly from: At | undefined;\n}\n\n/** Forwards tokens to the tree builder, remembering where the current token started. */\nclass Tracker implements Sink {\n mark: At = [0, 0];\n from: At | undefined;\n\n constructor(\n private readonly src: Source,\n private readonly tree: TreeBuilder,\n ) {}\n\n /** A token starts at `mark`; an error before `after` is about it (a child hole: the hole). */\n private before(about = true): void {\n this.from = about ? this.mark : undefined;\n }\n\n private after(): void {\n this.from = undefined;\n this.mark = [this.src.i, this.src.pos];\n }\n\n text(raw: string): void {\n this.before();\n this.tree.text(raw);\n this.after();\n }\n comment(raw: string): void {\n this.before();\n this.tree.comment(raw);\n this.after();\n }\n doctype(raw: string): void {\n this.before();\n this.tree.doctype(raw);\n this.after();\n }\n start(tag: StartTag): ContentMode {\n this.before();\n const mode = this.tree.start(tag);\n this.after();\n return mode;\n }\n end(name: string): void {\n this.before();\n this.tree.end(name);\n this.after();\n }\n hole(kind: 'child' | 'text'): void {\n this.before(false);\n this.tree.hole(kind);\n this.after();\n }\n finish(): void {\n this.before();\n this.tree.finish();\n this.after();\n }\n}\n\n/** The template's first rule violation, or undefined when `normalize` would accept it. */\nexport function checkTemplate(strings: readonly string[]): TemplateIssue | undefined {\n const normalized = minifyStrings(strings);\n const src = new Source(normalized, undefined);\n const tracker = new Tracker(src, new TreeBuilder(src));\n try {\n tokenize(src, tracker);\n } catch (error) {\n if (!(error instanceof TemplateError)) throw error;\n return { error, strings: normalized, at: [src.i, src.pos], from: tracker.from };\n }\n return undefined;\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import type { TreeNode } from './tree.js';
2
+ import { type PartSpec, type Segment, type Shape } from './types.js';
3
+ export interface Emitted {
4
+ readonly html: string;
5
+ readonly parts: PartSpec[];
6
+ readonly segments: Segment[];
7
+ readonly shape: Shape;
8
+ }
9
+ /**
10
+ * Emits the HTML, part table, segments and shape for a template's tree. A `server` template
11
+ * (a page shell) gets no anchors: hydration never walks it, and the browser never renders it.
12
+ */
13
+ export declare function emit(root: readonly TreeNode[], server: boolean): Emitted;
@@ -0,0 +1,136 @@
1
+ import { ATTR_PART, BOOL_PART, CHILD_BEFORE, CHILD_END, CHILD_SOLE, HOOK_PART, MULTI_PART, PROP_PART, TEXT_PART, } from './types.js';
2
+ const ANCHOR = '<!---->';
3
+ class Emitter {
4
+ /** A page shell (`server`): never hydrated, so it needs no anchors (06). */
5
+ constructor(server) {
6
+ this.server = server;
7
+ this.html = '';
8
+ this.parts = [];
9
+ this.segments = [];
10
+ }
11
+ /** Static markup: appended to the HTML and to the last string segment. */
12
+ out(text) {
13
+ if (text === '')
14
+ return;
15
+ this.html += text;
16
+ const last = this.segments.length - 1;
17
+ const prev = this.segments[last];
18
+ if (typeof prev === 'string')
19
+ this.segments[last] = prev + text;
20
+ else
21
+ this.segments.push(text);
22
+ }
23
+ op(segment) {
24
+ this.segments.push(segment);
25
+ }
26
+ /** `parent`: the parent element's name; undefined at the template root. */
27
+ children(nodes, path, parent) {
28
+ const shape = [];
29
+ nodes.forEach((node, k) => {
30
+ switch (node.type) {
31
+ case 'text':
32
+ this.out(node.raw);
33
+ shape.push('#text');
34
+ return;
35
+ case 'comment':
36
+ this.out(node.raw);
37
+ shape.push('#comment');
38
+ return;
39
+ case 'doctype':
40
+ // Server templates only; the browser drops a doctype inside a fragment.
41
+ this.out(node.raw);
42
+ return;
43
+ case 'el':
44
+ shape.push(this.element(node, [...path, shape.length]));
45
+ return;
46
+ case 'hole':
47
+ if (node.kind === 'text') {
48
+ this.parts.push([TEXT_PART, path]);
49
+ this.op({ k: 'text' });
50
+ return;
51
+ }
52
+ this.child(nodes, k, path, shape, parent);
53
+ }
54
+ });
55
+ return shape;
56
+ }
57
+ /** A child hole: inserts before the next static element or comment, the end, or an anchor. */
58
+ child(nodes, k, path, shape, parent) {
59
+ const next = nodes[k + 1];
60
+ this.op(parent === undefined ? { k: 'child' } : { k: 'child', in: parent });
61
+ if (next === undefined) {
62
+ this.parts.push([nodes.length === 1 ? CHILD_SOLE : CHILD_END, path]);
63
+ return;
64
+ }
65
+ this.parts.push([CHILD_BEFORE, path, shape.length]);
66
+ if (next.type === 'el' || next.type === 'comment' || this.server)
67
+ return;
68
+ this.out(ANCHOR);
69
+ shape.push('#comment');
70
+ }
71
+ element(el, path) {
72
+ let open = `<${el.raw}`;
73
+ for (const a of el.attrs) {
74
+ if (a.kind === 'static')
75
+ open += a.value === null ? ` ${a.name}` : ` ${a.name}=${a.value}`;
76
+ }
77
+ if (el.props !== undefined) {
78
+ this.html += open;
79
+ this.op({ k: 'open', tag: el.name, html: open, attrs: el.props });
80
+ }
81
+ else
82
+ this.out(open);
83
+ for (const a of el.attrs) {
84
+ if (a.kind === 'static')
85
+ continue;
86
+ if (a.kind === 'hook') {
87
+ this.parts.push([HOOK_PART, path]);
88
+ this.op({ k: 'hook' });
89
+ }
90
+ else if (a.kind === 'attr' && a.strings !== undefined) {
91
+ this.parts.push([MULTI_PART, path, a.name, a.strings]);
92
+ this.op({ k: 'attr', name: a.name, strings: a.strings });
93
+ }
94
+ else {
95
+ const kind = a.kind === 'attr' ? ATTR_PART : a.kind === 'bool' ? BOOL_PART : PROP_PART;
96
+ this.parts.push([kind, path, a.name]);
97
+ this.op({ k: a.kind, name: a.name });
98
+ }
99
+ }
100
+ const end = el.empty && el.ns !== 'html' ? '/>' : '>';
101
+ if (el.props !== undefined) {
102
+ this.html += end;
103
+ this.op({ k: 'openEnd' });
104
+ }
105
+ else
106
+ this.out(end);
107
+ if (el.empty)
108
+ return [el.name, []];
109
+ // The parser drops a newline right after <pre>, <listing> and <textarea>: give it one to
110
+ // drop, so a hole or text starting with a newline keeps its own.
111
+ const first = el.children[0];
112
+ const newline = el.ns === 'html' && /^(pre|listing|textarea)$/.test(el.name);
113
+ if (newline &&
114
+ (first?.type === 'hole' || (first?.type === 'text' && first.raw.startsWith('\n')))) {
115
+ this.out('\n');
116
+ }
117
+ const shape = this.children(el.children, path, el.name);
118
+ if (el.props !== undefined) {
119
+ this.html += `</${el.raw}>`;
120
+ this.op({ k: 'close', tag: el.name });
121
+ }
122
+ else
123
+ this.out(`</${el.raw}>`);
124
+ return [el.name, shape];
125
+ }
126
+ }
127
+ /**
128
+ * Emits the HTML, part table, segments and shape for a template's tree. A `server` template
129
+ * (a page shell) gets no anchors: hydration never walks it, and the browser never renders it.
130
+ */
131
+ export function emit(root, server) {
132
+ const e = new Emitter(server);
133
+ const shape = e.children(root, []);
134
+ return { html: e.html, parts: e.parts, segments: e.segments, shape };
135
+ }
136
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/view/normalize/emit.ts"],"names":[],"mappings":"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","sourcesContent":["// Emits the template object's markup from the normalizer's tree (view/01-templates.md steps 3\n// and 4): the client HTML (bound attributes removed, anchors added by view/02-bindings.md's\n// anchor rule), the server segments (types.ts), the part table with child-index paths, and the\n// shape of the DOM the browser must build (checked by prepare.ts).\nimport type { ElementNode, TreeNode } from './tree.js';\nimport {\n ATTR_PART,\n BOOL_PART,\n CHILD_BEFORE,\n CHILD_END,\n CHILD_SOLE,\n HOOK_PART,\n MULTI_PART,\n PROP_PART,\n TEXT_PART,\n type PartSpec,\n type Path,\n type Segment,\n type Shape,\n type ShapeNode,\n} from './types.js';\n\nconst ANCHOR = '<!---->';\n\nexport interface Emitted {\n readonly html: string;\n readonly parts: PartSpec[];\n readonly segments: Segment[];\n readonly shape: Shape;\n}\n\nclass Emitter {\n /** A page shell (`server`): never hydrated, so it needs no anchors (06). */\n constructor(private readonly server: boolean) {}\n\n html = '';\n readonly parts: PartSpec[] = [];\n readonly segments: Segment[] = [];\n\n /** Static markup: appended to the HTML and to the last string segment. */\n out(text: string): void {\n if (text === '') return;\n this.html += text;\n const last = this.segments.length - 1;\n const prev = this.segments[last];\n if (typeof prev === 'string') this.segments[last] = prev + text;\n else this.segments.push(text);\n }\n\n op(segment: Segment): void {\n this.segments.push(segment);\n }\n\n /** `parent`: the parent element's name; undefined at the template root. */\n children(nodes: readonly TreeNode[], path: Path, parent?: string): Shape {\n const shape: ShapeNode[] = [];\n nodes.forEach((node, k) => {\n switch (node.type) {\n case 'text':\n this.out(node.raw);\n shape.push('#text');\n return;\n case 'comment':\n this.out(node.raw);\n shape.push('#comment');\n return;\n case 'doctype':\n // Server templates only; the browser drops a doctype inside a fragment.\n this.out(node.raw);\n return;\n case 'el':\n shape.push(this.element(node, [...path, shape.length]));\n return;\n case 'hole':\n if (node.kind === 'text') {\n this.parts.push([TEXT_PART, path]);\n this.op({ k: 'text' });\n return;\n }\n this.child(nodes, k, path, shape, parent);\n }\n });\n return shape;\n }\n\n /** A child hole: inserts before the next static element or comment, the end, or an anchor. */\n private child(\n nodes: readonly TreeNode[],\n k: number,\n path: Path,\n shape: ShapeNode[],\n parent: string | undefined,\n ): void {\n const next = nodes[k + 1];\n this.op(parent === undefined ? { k: 'child' } : { k: 'child', in: parent });\n if (next === undefined) {\n this.parts.push([nodes.length === 1 ? CHILD_SOLE : CHILD_END, path]);\n return;\n }\n this.parts.push([CHILD_BEFORE, path, shape.length]);\n if (next.type === 'el' || next.type === 'comment' || this.server) return;\n this.out(ANCHOR);\n shape.push('#comment');\n }\n\n private element(el: ElementNode, path: Path): ShapeNode {\n let open = `<${el.raw}`;\n for (const a of el.attrs) {\n if (a.kind === 'static') open += a.value === null ? ` ${a.name}` : ` ${a.name}=${a.value}`;\n }\n if (el.props !== undefined) {\n this.html += open;\n this.op({ k: 'open', tag: el.name, html: open, attrs: el.props });\n } else this.out(open);\n for (const a of el.attrs) {\n if (a.kind === 'static') continue;\n if (a.kind === 'hook') {\n this.parts.push([HOOK_PART, path]);\n this.op({ k: 'hook' });\n } else if (a.kind === 'attr' && a.strings !== undefined) {\n this.parts.push([MULTI_PART, path, a.name, a.strings]);\n this.op({ k: 'attr', name: a.name, strings: a.strings });\n } else {\n const kind = a.kind === 'attr' ? ATTR_PART : a.kind === 'bool' ? BOOL_PART : PROP_PART;\n this.parts.push([kind, path, a.name]);\n this.op({ k: a.kind, name: a.name });\n }\n }\n const end = el.empty && el.ns !== 'html' ? '/>' : '>';\n if (el.props !== undefined) {\n this.html += end;\n this.op({ k: 'openEnd' });\n } else this.out(end);\n if (el.empty) return [el.name, []];\n // The parser drops a newline right after <pre>, <listing> and <textarea>: give it one to\n // drop, so a hole or text starting with a newline keeps its own.\n const first = el.children[0];\n const newline = el.ns === 'html' && /^(pre|listing|textarea)$/.test(el.name);\n if (\n newline &&\n (first?.type === 'hole' || (first?.type === 'text' && first.raw.startsWith('\\n')))\n ) {\n this.out('\\n');\n }\n const shape = this.children(el.children, path, el.name);\n if (el.props !== undefined) {\n this.html += `</${el.raw}>`;\n this.op({ k: 'close', tag: el.name });\n } else this.out(`</${el.raw}>`);\n return [el.name, shape];\n }\n}\n\n/**\n * Emits the HTML, part table, segments and shape for a template's tree. A `server` template\n * (a page shell) gets no anchors: hydration never walks it, and the browser never renders it.\n */\nexport function emit(root: readonly TreeNode[], server: boolean): Emitted {\n const e = new Emitter(server);\n const shape = e.children(root, []);\n return { html: e.html, parts: e.parts, segments: e.segments, shape };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ /** Decodes `raw`; `unknown(name)` is called (and must throw) for an unsupported name. */
2
+ export declare function decodeRefs(raw: string, unknown: (name: string) => never): string;
3
+ /** The value of a static attribute as written (`"a"`, `'a'`, `a`), without its quotes. */
4
+ export declare function unquote(value: string): string;
@@ -0,0 +1,38 @@
1
+ // Character references in attribute text the client sets itself: the static pieces of a
2
+ // multi-attribute and a custom element's static attributes (its props on the server). The
3
+ // WHATWG named-reference table has over 2,000 entries, so only numeric references and the
4
+ // common names are decoded; any other `&name;` is rule 13 (proposed). Text and plain static
5
+ // attributes are never decoded here: they stay in the template HTML for the browser to parse.
6
+ const NAMED = {
7
+ amp: '&',
8
+ lt: '<',
9
+ gt: '>',
10
+ quot: '"',
11
+ apos: "'",
12
+ nbsp: ' ',
13
+ };
14
+ const REF = /&(#[0-9]+|#[xX][0-9a-fA-F]+|[A-Za-z][A-Za-z0-9]*);/g;
15
+ function codePoint(n) {
16
+ const invalid = n === 0 || n > 0x10ffff || (n >= 0xd800 && n <= 0xdfff);
17
+ return String.fromCodePoint(invalid ? 0xfffd : n);
18
+ }
19
+ /** Decodes `raw`; `unknown(name)` is called (and must throw) for an unsupported name. */
20
+ export function decodeRefs(raw, unknown) {
21
+ if (!raw.includes('&'))
22
+ return raw;
23
+ return raw.replace(REF, (_, ref) => {
24
+ if (ref.startsWith('#x') || ref.startsWith('#X'))
25
+ return codePoint(parseInt(ref.slice(2), 16));
26
+ if (ref.startsWith('#'))
27
+ return codePoint(parseInt(ref.slice(1), 10));
28
+ return NAMED[ref] ?? unknown(ref);
29
+ });
30
+ }
31
+ /** The value of a static attribute as written (`"a"`, `'a'`, `a`), without its quotes. */
32
+ export function unquote(value) {
33
+ const q = value.charAt(0);
34
+ return (q === '"' || q === "'") && value.endsWith(q) && value.length >= 2
35
+ ? value.slice(1, -1)
36
+ : value;
37
+ }
38
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../../../src/view/normalize/entities.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,0FAA0F;AAC1F,0FAA0F;AAC1F,4FAA4F;AAC5F,8FAA8F;AAE9F,MAAM,KAAK,GAAuC;IAChD,GAAG,EAAE,GAAG;IACR,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,GAAG,GAAG,qDAAqD,CAAC;AAElE,SAAS,SAAS,CAAC,CAAS;IAC1B,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;IACxE,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,OAAgC;IACtE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACnC,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE;QACzC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/F,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACtE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QACvE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC;AACZ,CAAC","sourcesContent":["// Character references in attribute text the client sets itself: the static pieces of a\n// multi-attribute and a custom element's static attributes (its props on the server). The\n// WHATWG named-reference table has over 2,000 entries, so only numeric references and the\n// common names are decoded; any other `&name;` is rule 13 (proposed). Text and plain static\n// attributes are never decoded here: they stay in the template HTML for the browser to parse.\n\nconst NAMED: Record<string, string | undefined> = {\n amp: '&',\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n nbsp: ' ',\n};\n\nconst REF = /&(#[0-9]+|#[xX][0-9a-fA-F]+|[A-Za-z][A-Za-z0-9]*);/g;\n\nfunction codePoint(n: number): string {\n const invalid = n === 0 || n > 0x10ffff || (n >= 0xd800 && n <= 0xdfff);\n return String.fromCodePoint(invalid ? 0xfffd : n);\n}\n\n/** Decodes `raw`; `unknown(name)` is called (and must throw) for an unsupported name. */\nexport function decodeRefs(raw: string, unknown: (name: string) => never): string {\n if (!raw.includes('&')) return raw;\n return raw.replace(REF, (_, ref: string) => {\n if (ref.startsWith('#x') || ref.startsWith('#X')) return codePoint(parseInt(ref.slice(2), 16));\n if (ref.startsWith('#')) return codePoint(parseInt(ref.slice(1), 10));\n return NAMED[ref] ?? unknown(ref);\n });\n}\n\n/** The value of a static attribute as written (`\"a\"`, `'a'`, `a`), without its quotes. */\nexport function unquote(value: string): string {\n const q = value.charAt(0);\n return (q === '\"' || q === \"'\") && value.endsWith(q) && value.length >= 2\n ? value.slice(1, -1)\n : value;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ export declare const RULES_DOC = "docs/design-docs/view/09-template-rules.md";
2
+ /** Rule 11's message, here so the client's template cache needn't load the rule messages. */
3
+ export declare const SERVER_ONLY: string;
4
+ /** A template breaks rule `rule` of view/09-template-rules.md. */
5
+ export declare class TemplateError extends Error {
6
+ readonly rule: number;
7
+ readonly loc: string | undefined;
8
+ constructor(rule: number, message: string, loc?: string, near?: string);
9
+ }
@@ -0,0 +1,19 @@
1
+ // TemplateError: what the template rules (view/09-template-rules.md) throw. Kept apart from the
2
+ // rule checks so code that only needs the class (template-element.ts) stays small.
3
+ export const RULES_DOC = 'docs/design-docs/view/09-template-rules.md';
4
+ /** Rule 11's message, here so the client's template cache needn't load the rule messages. */
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 ' +
7
+ 'components (not the page) in the browser.';
8
+ /** A template breaks rule `rule` of view/09-template-rules.md. */
9
+ export class TemplateError extends Error {
10
+ constructor(rule, message, loc, near) {
11
+ const doc = ` (${RULES_DOC}, rule ${String(rule)})`;
12
+ const context = (near === undefined ? '' : `\n near: ${near}`) + (loc === undefined ? '' : `\n at ${loc}`);
13
+ super(`[gyral template rule ${String(rule)}] ${message}${doc}${context}`);
14
+ this.name = 'TemplateError';
15
+ this.rule = rule;
16
+ this.loc = loc;
17
+ }
18
+ }
19
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,7 @@
1
+ /** The id of a template's normalized strings. */
2
+ export declare function templateId(strings: readonly string[]): string;
3
+ /**
4
+ * Development: records `id` → strings and warns once when two different normalized templates
5
+ * share an id (the compiler fails the build instead).
6
+ */
7
+ export declare function recordTemplateId(id: string, strings: readonly string[]): void;
@@ -0,0 +1,48 @@
1
+ // Template ids (view/01-templates.md "Template ids"): a deterministic 53-bit hash of the
2
+ // normalized strings, printed in base 36. Two independent 32-bit multiply-xorshift lanes over
3
+ // the UTF-16 code units, with each string's length mixed in first so ["a", "b"] and ["ab"]
4
+ // differ; a final avalanche, then 21 bits of one lane and 32 of the other. Only Math.imul and
5
+ // integer ops: the same result in Node, browsers and the compiler.
6
+ function mix(h, k, m) {
7
+ return Math.imul(h ^ k, m);
8
+ }
9
+ function avalanche(h, a, b) {
10
+ let x = Math.imul(h ^ (h >>> 16), a);
11
+ x = Math.imul(x ^ (x >>> 13), b);
12
+ return x ^ (x >>> 16);
13
+ }
14
+ /** The id of a template's normalized strings. */
15
+ export function templateId(strings) {
16
+ let h1 = 0x9e3779b9 ^ strings.length;
17
+ let h2 = 0x85ebca6b ^ strings.length;
18
+ for (const s of strings) {
19
+ h1 = mix(h1, s.length, 0x2d51);
20
+ h2 = mix(h2, s.length, 0x1b873593);
21
+ for (let k = 0; k < s.length; k++) {
22
+ const c = s.charCodeAt(k);
23
+ h1 = mix(h1, c, 0x9e3779b1);
24
+ h2 = mix(h2, c, 0x5bd1e995);
25
+ }
26
+ }
27
+ const lo = avalanche(h1 ^ Math.imul(h2, 0x27d4eb2f), 0x85ebca6b, 0xc2b2ae35) >>> 0;
28
+ const hi = avalanche(h2 ^ lo, 0x2c1b3c6d, 0x297a2d39) & 0x1fffff;
29
+ return (hi * 0x100000000 + lo).toString(36);
30
+ }
31
+ const seen = new Map();
32
+ /**
33
+ * Development: records `id` → strings and warns once when two different normalized templates
34
+ * share an id (the compiler fails the build instead).
35
+ */
36
+ export function recordTemplateId(id, strings) {
37
+ const key = JSON.stringify(strings);
38
+ const known = seen.get(id);
39
+ if (known === undefined)
40
+ seen.set(id, key);
41
+ else if (known !== key) {
42
+ console.warn(`gyral: two different templates share the id ${id}; server output and hydration may ` +
43
+ `confuse them. Change one template slightly (e.g. add a class) and report this ` +
44
+ `collision.\n ${known}\n ${key}`);
45
+ seen.set(id, key);
46
+ }
47
+ }
48
+ //# sourceMappingURL=id.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,15 @@
1
+ import type { NormalizedTemplate, Shape } from './types.js';
2
+ export interface Analysis {
3
+ readonly template: NormalizedTemplate;
4
+ /** The whitespace-normalized strings the id was computed from. */
5
+ readonly strings: readonly string[];
6
+ /** The DOM the browser must build from `template.html` (checked by the runtime preparer). */
7
+ readonly shape: Shape;
8
+ }
9
+ /** The template object plus what the runtime preparer checks it against. */
10
+ export declare function analyze(strings: readonly string[], loc?: string): Analysis;
11
+ /**
12
+ * Normalizes a template's static strings into its template object (JSON data). Throws a
13
+ * TemplateError for markup that breaks a template rule.
14
+ */
15
+ export declare function normalize(strings: readonly string[], loc?: string): NormalizedTemplate;
@@ -0,0 +1,36 @@
1
+ // The normalizer (view/01-templates.md "Normalization"): one pure function from a call site's
2
+ // static strings to its template object, shared by the Vite compiler, the browser's runtime
3
+ // preparer and the server renderer. Steps: minify whitespace (holes never move), tokenize and
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.
6
+ import { emit } from './emit.js';
7
+ import { templateId } from './id.js';
8
+ import { Source } from './source.js';
9
+ import { tokenize } from './tokenizer.js';
10
+ import { TreeBuilder } from './tree.js';
11
+ import { minifyStrings } from './whitespace.js';
12
+ /** The template object plus what the runtime preparer checks it against. */
13
+ export function analyze(strings, loc) {
14
+ const normalized = minifyStrings(strings);
15
+ const src = new Source(normalized, loc);
16
+ const tree = new TreeBuilder(src);
17
+ tokenize(src, tree);
18
+ const { html, parts, segments, shape } = emit(tree.root, tree.server);
19
+ const template = {
20
+ id: templateId(normalized),
21
+ html,
22
+ parts,
23
+ ...(tree.server ? { server: true } : {}),
24
+ segments,
25
+ ...(loc === undefined ? {} : { loc }),
26
+ };
27
+ return { template, strings: normalized, shape };
28
+ }
29
+ /**
30
+ * Normalizes a template's static strings into its template object (JSON data). Throws a
31
+ * TemplateError for markup that breaks a template rule.
32
+ */
33
+ export function normalize(strings, loc) {
34
+ return analyze(strings, loc).template;
35
+ }
36
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,24 @@
1
+ export type Ns = 'html' | 'svg' | 'math';
2
+ export interface OpenElement {
3
+ readonly name: string;
4
+ readonly ns: Ns;
5
+ }
6
+ /** How the tree builder treats content of a container (its insertion mode, roughly). */
7
+ export type Context = 'body' | 'table' | 'tbody' | 'tr' | 'colgroup';
8
+ /** The context an element's children are parsed in. */
9
+ export declare function contextOf(name: string): Context;
10
+ /**
11
+ * The context of a template root or <template> content: decided by its first start tag
12
+ * (the "in template" insertion mode).
13
+ */
14
+ export declare function rootContext(firstTag: string): Context;
15
+ /**
16
+ * Rule 7 for a start tag in the HTML namespace. `atRoot`: the container is the template root
17
+ * or a <template>'s content, where content the parser would foster-parent stays in place.
18
+ * Returns the error message, or undefined when the parser keeps the tag where it is written.
19
+ */
20
+ export declare function startRepair(name: string, ctx: Context, atRoot: boolean, stack: readonly OpenElement[], hiddenInput: boolean): string | undefined;
21
+ /** Rule 7 for static text: non-whitespace text in table structure is moved out of it. */
22
+ export declare function textRepair(raw: string, ctx: Context, atRoot: boolean): string | undefined;
23
+ /** Rule 7 in SVG/MathML: HTML tags that end the foreign element. */
24
+ export declare function breaksOutOfForeign(name: string, hasFontAttr: boolean): boolean;