@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,42 @@
1
+ // Rendering one Gyral component in place (view/06-server.md "Components"): the end of its start
2
+ // tag (light mark, seed, island attributes), then its view, inside a declarative shadow root
3
+ // with the component's CSS (08 "Server") or as light-DOM children (ADR 0014). The parent's
4
+ // children of a shadow component follow in the parent's walk, after the `<template>`.
5
+ import { ISLAND_ATTRIBUTE, LIGHT_ATTRIBUTE, SEED_ATTRIBUTE } from '../attributes.js';
6
+ import { escapeSeed, styleSafe } from './escape.js';
7
+ import { ROOT, Writer } from './writer.js';
8
+ const styleTexts = new WeakMap();
9
+ /**
10
+ * The text of a shadow component's `<style>` (its CSS texts joined by newlines, `</style`
11
+ * escaped), exactly as written, so `styleHashes()` hashes what the browser sees. `''`: none.
12
+ */
13
+ export function styleText(component) {
14
+ let text = styleTexts.get(component);
15
+ if (text === undefined) {
16
+ text = styleSafe(component.styles.join('\n'));
17
+ styleTexts.set(component, text);
18
+ }
19
+ return text;
20
+ }
21
+ /** Writes a deferred component; nested components are deferred again. */
22
+ export function expand({ component, input }, dev) {
23
+ const { view, seed } = component.render(input);
24
+ const w = new Writer(dev, input.scope);
25
+ let tail = component.light ? ` ${LIGHT_ATTRIBUTE}` : '';
26
+ // Single-quoted, so the JSON's double quotes stay raw (ADR 0012).
27
+ tail += ` ${SEED_ATTRIBUTE}='${escapeSeed(JSON.stringify(seed))}'`;
28
+ if (component.hydrate !== 'load') {
29
+ tail += ` defer-hydration ${ISLAND_ATTRIBUTE}="${component.hydrate}"`;
30
+ }
31
+ w.write(`${tail}>`);
32
+ if (component.light) {
33
+ w.child(view, undefined, ROOT);
34
+ return w.done();
35
+ }
36
+ const css = styleText(component);
37
+ w.write(`<template shadowrootmode="open">${css === '' ? '' : `<style>${css}</style>`}`);
38
+ w.child(view, undefined, ROOT);
39
+ w.write('</template>');
40
+ return w.done();
41
+ }
42
+ //# sourceMappingURL=component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/view/server/component.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,6FAA6F;AAC7F,2FAA2F;AAC3F,sFAAsF;AACtF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAErF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,EAA4B,MAAM,aAAa,CAAC;AAErE,MAAM,UAAU,GAAG,IAAI,OAAO,EAA2B,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,SAA0B;IAClD,IAAI,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9C,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,EAAY,EAAE,GAAY;IACjE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,kEAAkE;IAClE,IAAI,IAAI,IAAI,cAAc,KAAK,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;IACnE,IAAI,SAAS,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;QACjC,IAAI,IAAI,oBAAoB,gBAAgB,KAAK,SAAS,CAAC,OAAO,GAAG,CAAC;IACxE,CAAC;IACD,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;IACpB,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,KAAK,CAAC,mCAAmC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC,CAAC;IACxF,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAClB,CAAC","sourcesContent":["// Rendering one Gyral component in place (view/06-server.md \"Components\"): the end of its start\n// tag (light mark, seed, island attributes), then its view, inside a declarative shadow root\n// with the component's CSS (08 \"Server\") or as light-DOM children (ADR 0014). The parent's\n// children of a shadow component follow in the parent's walk, after the `<template>`.\nimport { ISLAND_ATTRIBUTE, LIGHT_ATTRIBUTE, SEED_ATTRIBUTE } from '../attributes.js';\nimport type { ServerComponent } from '../registry.js';\nimport { escapeSeed, styleSafe } from './escape.js';\nimport { ROOT, Writer, type Deferred, type Item } from './writer.js';\n\nconst styleTexts = new WeakMap<ServerComponent, string>();\n\n/**\n * The text of a shadow component's `<style>` (its CSS texts joined by newlines, `</style`\n * escaped), exactly as written, so `styleHashes()` hashes what the browser sees. `''`: none.\n */\nexport function styleText(component: ServerComponent): string {\n let text = styleTexts.get(component);\n if (text === undefined) {\n text = styleSafe(component.styles.join('\\n'));\n styleTexts.set(component, text);\n }\n return text;\n}\n\n/** Writes a deferred component; nested components are deferred again. */\nexport function expand({ component, input }: Deferred, dev: boolean): Item[] {\n const { view, seed } = component.render(input);\n const w = new Writer(dev, input.scope);\n let tail = component.light ? ` ${LIGHT_ATTRIBUTE}` : '';\n // Single-quoted, so the JSON's double quotes stay raw (ADR 0012).\n tail += ` ${SEED_ATTRIBUTE}='${escapeSeed(JSON.stringify(seed))}'`;\n if (component.hydrate !== 'load') {\n tail += ` defer-hydration ${ISLAND_ATTRIBUTE}=\"${component.hydrate}\"`;\n }\n w.write(`${tail}>`);\n if (component.light) {\n w.child(view, undefined, ROOT);\n return w.done();\n }\n const css = styleText(component);\n w.write(`<template shadowrootmode=\"open\">${css === '' ? '' : `<style>${css}</style>`}`);\n w.child(view, undefined, ROOT);\n w.write('</template>');\n return w.done();\n}\n"]}
@@ -0,0 +1,10 @@
1
+ /** Text content (child holes, `<textarea>`/`<title>` content). */
2
+ export declare function escapeText(text: string): string;
3
+ /** A double-quoted attribute value. */
4
+ export declare function escapeAttr(value: string): string;
5
+ /** A single-quoted attribute value: the `data-gyral-seed` JSON. */
6
+ export declare const escapeSeed: (json: string) => string;
7
+ /** CSS for a `<style>` element: `</style` (any case) would end it; `<\/style` is the same CSS. */
8
+ export declare const styleSafe: (css: string) => string;
9
+ /** HTML whitespace (WHATWG "ASCII whitespace"): text made only of it stays in table structure. */
10
+ export declare const onlyWhitespace: (text: string) => boolean;
@@ -0,0 +1,34 @@
1
+ // Escaping for the server renderer (view/06-server.md "Escaping"). Text escapes `&`, `<` and
2
+ // `>`; double-quoted attribute values escape `&`, `"`, `<` and `>`; the single-quoted seed
3
+ // attribute escapes `&`, `'`, `<` and `>` (so its JSON's double quotes stay raw). Only `&` and
4
+ // the quote can end a quoted value; `<` and `>` are escaped too (as newer revisions of WHATWG
5
+ // HTML's "Serializing HTML fragments" do), so no markup appears raw in an attribute, whatever
6
+ // later reads the page (raw-text contexts, naive tooling, filters).
7
+ const TEXT = /[&<>]/g;
8
+ const ATTR = /[&"<>]/g;
9
+ const SEED = /[&'<>]/g;
10
+ const ENTITY = {
11
+ '&': '&amp;',
12
+ '<': '&lt;',
13
+ '>': '&gt;',
14
+ '"': '&quot;',
15
+ "'": '&#39;',
16
+ };
17
+ const entity = (c) => ENTITY[c] ?? c;
18
+ /** Text content (child holes, `<textarea>`/`<title>` content). */
19
+ export function escapeText(text) {
20
+ TEXT.lastIndex = 0;
21
+ return TEXT.test(text) ? text.replace(TEXT, entity) : text;
22
+ }
23
+ /** A double-quoted attribute value. */
24
+ export function escapeAttr(value) {
25
+ ATTR.lastIndex = 0;
26
+ return ATTR.test(value) ? value.replace(ATTR, entity) : value;
27
+ }
28
+ /** A single-quoted attribute value: the `data-gyral-seed` JSON. */
29
+ export const escapeSeed = (json) => json.replace(SEED, entity);
30
+ /** CSS for a `<style>` element: `</style` (any case) would end it; `<\/style` is the same CSS. */
31
+ export const styleSafe = (css) => css.replace(/<\/(style)/gi, '<\\/$1');
32
+ /** HTML whitespace (WHATWG "ASCII whitespace"): text made only of it stays in table structure. */
33
+ export const onlyWhitespace = (text) => !/[^\t\n\f\r ]/.test(text);
34
+ //# sourceMappingURL=escape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape.js","sourceRoot":"","sources":["../../../src/view/server/escape.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,+FAA+F;AAC/F,8FAA8F;AAC9F,8FAA8F;AAC9F,oEAAoE;AAEpE,MAAM,IAAI,GAAG,QAAQ,CAAC;AACtB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,IAAI,GAAG,SAAS,CAAC;AAEvB,MAAM,MAAM,GAAqC;IAC/C,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;CACb,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAErD,kEAAkE;AAClE,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAChE,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAE/E,kGAAkG;AAClG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;AAExF,kGAAkG;AAClG,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["// Escaping for the server renderer (view/06-server.md \"Escaping\"). Text escapes `&`, `<` and\n// `>`; double-quoted attribute values escape `&`, `\"`, `<` and `>`; the single-quoted seed\n// attribute escapes `&`, `'`, `<` and `>` (so its JSON's double quotes stay raw). Only `&` and\n// the quote can end a quoted value; `<` and `>` are escaped too (as newer revisions of WHATWG\n// HTML's \"Serializing HTML fragments\" do), so no markup appears raw in an attribute, whatever\n// later reads the page (raw-text contexts, naive tooling, filters).\n\nconst TEXT = /[&<>]/g;\nconst ATTR = /[&\"<>]/g;\nconst SEED = /[&'<>]/g;\n\nconst ENTITY: Readonly<Record<string, string>> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n};\n\nconst entity = (c: string): string => ENTITY[c] ?? c;\n\n/** Text content (child holes, `<textarea>`/`<title>` content). */\nexport function escapeText(text: string): string {\n TEXT.lastIndex = 0;\n return TEXT.test(text) ? text.replace(TEXT, entity) : text;\n}\n\n/** A double-quoted attribute value. */\nexport function escapeAttr(value: string): string {\n ATTR.lastIndex = 0;\n return ATTR.test(value) ? value.replace(ATTR, entity) : value;\n}\n\n/** A single-quoted attribute value: the `data-gyral-seed` JSON. */\nexport const escapeSeed = (json: string): string => json.replace(SEED, entity);\n\n/** CSS for a `<style>` element: `</style` (any case) would end it; `<\\/style` is the same CSS. */\nexport const styleSafe = (css: string): string => css.replace(/<\\/(style)/gi, '<\\\\/$1');\n\n/** HTML whitespace (WHATWG \"ASCII whitespace\"): text made only of it stays in table structure. */\nexport const onlyWhitespace = (text: string): boolean => !/[^\\t\\n\\f\\r ]/.test(text);\n"]}
@@ -0,0 +1,28 @@
1
+ import type { ChildValue } from '../render/values.js';
2
+ export interface ServerRenderOptions {
3
+ /**
4
+ * Development markers (`<!--gyral:ID-->` before each template instance, for hydration's
5
+ * checks, 07) and development checks. Default: on in development builds (the `development`
6
+ * export condition, as for the client), off otherwise.
7
+ */
8
+ readonly dev?: boolean;
9
+ }
10
+ /**
11
+ * Renders `value` to HTML chunks, lazily: each step writes up to the next component boundary.
12
+ * Every component's `init` and view run in the step that writes it, so a caller can wrap each
13
+ * step in a per-request scope (ADR 0013).
14
+ */
15
+ export declare function render(value: ChildValue, options?: ServerRenderOptions): Iterable<string>;
16
+ /** Renders `value` to one string. */
17
+ export declare function renderToString(value: ChildValue, options?: ServerRenderOptions): string;
18
+ /**
19
+ * `'sha256-…'` of a `<style>` element's text, for a CSP `style-src` (cached per text).
20
+ * Synchronous (sha256.ts), so a page can build its policy while it renders.
21
+ */
22
+ export declare function styleHashSync(text: string): string;
23
+ /** `styleHashSync`, as a promise (the API before it existed). */
24
+ export declare const styleHash: (text: string) => Promise<string>;
25
+ /** Tag → `<style>` text of every registered shadow component with CSS (08 "Server"). */
26
+ export declare function componentStyles(): ReadonlyMap<string, string>;
27
+ /** The hashes of every registered shadow component's `<style>` (08 "Server"), deduplicated. */
28
+ export declare function styleHashes(): Promise<readonly string[]>;
@@ -0,0 +1,72 @@
1
+ // The server renderer (view/06-server.md "API"): synchronous, chunked, runtime-agnostic (no
2
+ // DOM, no Node-only APIs: a JavaScript SHA-256 for the style hashes). `@gyral/core/server` wraps these,
3
+ // registering recorded specs first; code outside view/ may import only this module of view/server/.
4
+ import { DEV } from '../flags.js';
5
+ import { serverComponents } from '../registry.js';
6
+ import { expand, styleText } from './component.js';
7
+ import { sha256 } from './sha256.js';
8
+ import { ROOT, Writer } from './writer.js';
9
+ function push(stack, items) {
10
+ for (let i = items.length - 1; i >= 0; i--)
11
+ stack.push(items[i]);
12
+ }
13
+ /**
14
+ * Renders `value` to HTML chunks, lazily: each step writes up to the next component boundary.
15
+ * Every component's `init` and view run in the step that writes it, so a caller can wrap each
16
+ * step in a per-request scope (ADR 0013).
17
+ */
18
+ export function* render(value, options = {}) {
19
+ const dev = options.dev ?? DEV;
20
+ const root = new Writer(dev, undefined);
21
+ root.child(value, undefined, ROOT);
22
+ const stack = [];
23
+ push(stack, root.done());
24
+ for (let item = stack.pop(); item !== undefined; item = stack.pop()) {
25
+ if (typeof item === 'string')
26
+ yield item;
27
+ else
28
+ push(stack, expand(item, dev));
29
+ }
30
+ }
31
+ /** Renders `value` to one string. */
32
+ export function renderToString(value, options) {
33
+ let html = '';
34
+ for (const chunk of render(value, options))
35
+ html += chunk;
36
+ return html;
37
+ }
38
+ const hashes = new Map();
39
+ /**
40
+ * `'sha256-…'` of a `<style>` element's text, for a CSP `style-src` (cached per text).
41
+ * Synchronous (sha256.ts), so a page can build its policy while it renders.
42
+ */
43
+ export function styleHashSync(text) {
44
+ let hash = hashes.get(text);
45
+ if (hash === undefined) {
46
+ // The parser turns CR and CRLF into LF before the browser hashes the element's text.
47
+ const digest = sha256(new TextEncoder().encode(text.replace(/\r\n?/g, '\n')));
48
+ let binary = '';
49
+ for (const byte of digest)
50
+ binary += String.fromCharCode(byte);
51
+ hash = `'sha256-${btoa(binary)}'`;
52
+ hashes.set(text, hash);
53
+ }
54
+ return hash;
55
+ }
56
+ /** `styleHashSync`, as a promise (the API before it existed). */
57
+ export const styleHash = (text) => Promise.resolve(styleHashSync(text));
58
+ /** Tag → `<style>` text of every registered shadow component with CSS (08 "Server"). */
59
+ export function componentStyles() {
60
+ const styles = new Map();
61
+ for (const component of serverComponents()) {
62
+ const text = styleText(component);
63
+ if (text !== '')
64
+ styles.set(component.tag, text);
65
+ }
66
+ return styles;
67
+ }
68
+ /** The hashes of every registered shadow component's `<style>` (08 "Server"), deduplicated. */
69
+ export function styleHashes() {
70
+ return Promise.resolve([...new Set([...componentStyles().values()].map(styleHashSync))]);
71
+ }
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/view/server/index.ts"],"names":[],"mappings":"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","sourcesContent":["// The server renderer (view/06-server.md \"API\"): synchronous, chunked, runtime-agnostic (no\n// DOM, no Node-only APIs: a JavaScript SHA-256 for the style hashes). `@gyral/core/server` wraps these,\n// registering recorded specs first; code outside view/ may import only this module of view/server/.\nimport { DEV } from '../flags.js';\nimport { serverComponents } from '../registry.js';\nimport type { ChildValue } from '../render/values.js';\nimport { expand, styleText } from './component.js';\nimport { sha256 } from './sha256.js';\nimport { ROOT, Writer, type Item } from './writer.js';\n\nexport interface ServerRenderOptions {\n /**\n * Development markers (`<!--gyral:ID-->` before each template instance, for hydration's\n * checks, 07) and development checks. Default: on in development builds (the `development`\n * export condition, as for the client), off otherwise.\n */\n readonly dev?: boolean;\n}\n\nfunction push(stack: Item[], items: readonly Item[]): void {\n for (let i = items.length - 1; i >= 0; i--) stack.push(items[i] as Item);\n}\n\n/**\n * Renders `value` to HTML chunks, lazily: each step writes up to the next component boundary.\n * Every component's `init` and view run in the step that writes it, so a caller can wrap each\n * step in a per-request scope (ADR 0013).\n */\nexport function* render(value: ChildValue, options: ServerRenderOptions = {}): Iterable<string> {\n const dev = options.dev ?? DEV;\n const root = new Writer(dev, undefined);\n root.child(value, undefined, ROOT);\n const stack: Item[] = [];\n push(stack, root.done());\n for (let item = stack.pop(); item !== undefined; item = stack.pop()) {\n if (typeof item === 'string') yield item;\n else push(stack, expand(item, dev));\n }\n}\n\n/** Renders `value` to one string. */\nexport function renderToString(value: ChildValue, options?: ServerRenderOptions): string {\n let html = '';\n for (const chunk of render(value, options)) html += chunk;\n return html;\n}\n\nconst hashes = new Map<string, string>();\n\n/**\n * `'sha256-…'` of a `<style>` element's text, for a CSP `style-src` (cached per text).\n * Synchronous (sha256.ts), so a page can build its policy while it renders.\n */\nexport function styleHashSync(text: string): string {\n let hash = hashes.get(text);\n if (hash === undefined) {\n // The parser turns CR and CRLF into LF before the browser hashes the element's text.\n const digest = sha256(new TextEncoder().encode(text.replace(/\\r\\n?/g, '\\n')));\n let binary = '';\n for (const byte of digest) binary += String.fromCharCode(byte);\n hash = `'sha256-${btoa(binary)}'`;\n hashes.set(text, hash);\n }\n return hash;\n}\n\n/** `styleHashSync`, as a promise (the API before it existed). */\nexport const styleHash = (text: string): Promise<string> => Promise.resolve(styleHashSync(text));\n\n/** Tag → `<style>` text of every registered shadow component with CSS (08 \"Server\"). */\nexport function componentStyles(): ReadonlyMap<string, string> {\n const styles = new Map<string, string>();\n for (const component of serverComponents()) {\n const text = styleText(component);\n if (text !== '') styles.set(component.tag, text);\n }\n return styles;\n}\n\n/** The hashes of every registered shadow component's `<style>` (08 \"Server\"), deduplicated. */\nexport function styleHashes(): Promise<readonly string[]> {\n return Promise.resolve([...new Set([...componentStyles().values()].map(styleHashSync))]);\n}\n"]}
@@ -0,0 +1,2 @@
1
+ /** The SHA-256 digest of `bytes` (32 bytes). */
2
+ export declare function sha256(bytes: Uint8Array): Uint8Array;
@@ -0,0 +1,75 @@
1
+ // SHA-256 (FIPS 180-4) in plain JavaScript, for CSP style hashes (view/06-server.md "CSP").
2
+ // Synchronous, unlike WebCrypto's `digest`, so `@gyral/ssr`'s `renderPage` can build the
3
+ // policy at render time, after the page's components are registered, and still return its
4
+ // Response synchronously. Runtime-agnostic (no `node:crypto`); server-only, never in client
5
+ // bundles. Checked against `node:crypto` (sha256.node.test.ts).
6
+ /** Round constants: the first 32 bits of the fractional parts of the cube roots of the first 64 primes. */
7
+ const K = new Uint32Array([
8
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
9
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
10
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
11
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
12
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
13
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
14
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
15
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
16
+ ]);
17
+ /** Initial hash: the first 32 bits of the fractional parts of the square roots of the first 8 primes. */
18
+ const H0 = [
19
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
20
+ ];
21
+ const rotr = (x, n) => (x >>> n) | (x << (32 - n));
22
+ /** The SHA-256 digest of `bytes` (32 bytes). */
23
+ export function sha256(bytes) {
24
+ // Padding: 0x80, zeros, then the bit length as a 64-bit big-endian number.
25
+ const blocks = (bytes.length + 9 + 63) >> 6;
26
+ const m = new Uint8Array(blocks * 64);
27
+ m.set(bytes);
28
+ m[bytes.length] = 0x80;
29
+ const view = new DataView(m.buffer);
30
+ const bits = bytes.length * 8;
31
+ view.setUint32(m.length - 8, Math.floor(bits / 0x100000000));
32
+ view.setUint32(m.length - 4, bits >>> 0);
33
+ const h = new Uint32Array(H0);
34
+ const w = new Uint32Array(64);
35
+ for (let off = 0; off < m.length; off += 64) {
36
+ for (let t = 0; t < 16; t++)
37
+ w[t] = view.getUint32(off + t * 4);
38
+ for (let t = 16; t < 64; t++) {
39
+ const x = w[t - 15];
40
+ const y = w[t - 2];
41
+ const s0 = rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3);
42
+ const s1 = rotr(y, 17) ^ rotr(y, 19) ^ (y >>> 10);
43
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1;
44
+ }
45
+ let [a, b, c, d, e, f, g, k] = Array.from(h);
46
+ for (let t = 0; t < 64; t++) {
47
+ const s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
48
+ const t1 = (k + s1 + ((e & f) ^ (~e & g)) + K[t] + w[t]) | 0;
49
+ const s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
50
+ const t2 = (s0 + ((a & b) ^ (a & c) ^ (b & c))) | 0;
51
+ k = g;
52
+ g = f;
53
+ f = e;
54
+ e = (d + t1) | 0;
55
+ d = c;
56
+ c = b;
57
+ b = a;
58
+ a = (t1 + t2) | 0;
59
+ }
60
+ h[0] = h[0] + a;
61
+ h[1] = h[1] + b;
62
+ h[2] = h[2] + c;
63
+ h[3] = h[3] + d;
64
+ h[4] = h[4] + e;
65
+ h[5] = h[5] + f;
66
+ h[6] = h[6] + g;
67
+ h[7] = h[7] + k;
68
+ }
69
+ const out = new Uint8Array(32);
70
+ const outView = new DataView(out.buffer);
71
+ for (let i = 0; i < 8; i++)
72
+ outView.setUint32(i * 4, h[i]);
73
+ return out;
74
+ }
75
+ //# sourceMappingURL=sha256.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sha256.js","sourceRoot":"","sources":["../../../src/view/server/sha256.ts"],"names":[],"mappings":"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","sourcesContent":["// SHA-256 (FIPS 180-4) in plain JavaScript, for CSP style hashes (view/06-server.md \"CSP\").\n// Synchronous, unlike WebCrypto's `digest`, so `@gyral/ssr`'s `renderPage` can build the\n// policy at render time, after the page's components are registered, and still return its\n// Response synchronously. Runtime-agnostic (no `node:crypto`); server-only, never in client\n// bundles. Checked against `node:crypto` (sha256.node.test.ts).\n\n/** Round constants: the first 32 bits of the fractional parts of the cube roots of the first 64 primes. */\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\n/** Initial hash: the first 32 bits of the fractional parts of the square roots of the first 8 primes. */\nconst H0 = [\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n];\n\n/** The eight working variables. */\ntype Words = [number, number, number, number, number, number, number, number];\n\nconst rotr = (x: number, n: number): number => (x >>> n) | (x << (32 - n));\n\n/** The SHA-256 digest of `bytes` (32 bytes). */\nexport function sha256(bytes: Uint8Array): Uint8Array {\n // Padding: 0x80, zeros, then the bit length as a 64-bit big-endian number.\n const blocks = (bytes.length + 9 + 63) >> 6;\n const m = new Uint8Array(blocks * 64);\n m.set(bytes);\n m[bytes.length] = 0x80;\n const view = new DataView(m.buffer);\n const bits = bytes.length * 8;\n view.setUint32(m.length - 8, Math.floor(bits / 0x100000000));\n view.setUint32(m.length - 4, bits >>> 0);\n const h = new Uint32Array(H0);\n const w = new Uint32Array(64);\n for (let off = 0; off < m.length; off += 64) {\n for (let t = 0; t < 16; t++) w[t] = view.getUint32(off + t * 4);\n for (let t = 16; t < 64; t++) {\n const x = w[t - 15] as number;\n const y = w[t - 2] as number;\n const s0 = rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3);\n const s1 = rotr(y, 17) ^ rotr(y, 19) ^ (y >>> 10);\n w[t] = (w[t - 16] as number) + s0 + (w[t - 7] as number) + s1;\n }\n let [a, b, c, d, e, f, g, k] = Array.from(h) as Words;\n for (let t = 0; t < 64; t++) {\n const s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);\n const t1 = (k + s1 + ((e & f) ^ (~e & g)) + (K[t] as number) + (w[t] as number)) | 0;\n const s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);\n const t2 = (s0 + ((a & b) ^ (a & c) ^ (b & c))) | 0;\n k = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n h[0] = (h[0] as number) + a;\n h[1] = (h[1] as number) + b;\n h[2] = (h[2] as number) + c;\n h[3] = (h[3] as number) + d;\n h[4] = (h[4] as number) + e;\n h[5] = (h[5] as number) + f;\n h[6] = (h[6] as number) + g;\n h[7] = (h[7] as number) + k;\n }\n const out = new Uint8Array(32);\n const outView = new DataView(out.buffer);\n for (let i = 0; i < 8; i++) outView.setUint32(i * 4, h[i] as number);\n return out;\n}\n"]}
@@ -0,0 +1,57 @@
1
+ import type { Segment } from '../normalize/types.js';
2
+ import { type ServerComponent, type ServerProvider, type ServerRenderInput } from '../registry.js';
3
+ /** A component whose content is written later, in its own render step. */
4
+ export interface Deferred {
5
+ readonly component: ServerComponent;
6
+ readonly input: ServerRenderInput;
7
+ }
8
+ /** What a walk produces: markup, with deferred components in document order. */
9
+ export type Item = string | Deferred;
10
+ /** A custom element's start tag while its attribute holes are written. */
11
+ export interface Opening {
12
+ readonly tag: string;
13
+ readonly component: ServerComponent | undefined;
14
+ readonly provider: ServerProvider | undefined;
15
+ readonly attributes: Record<string, string>;
16
+ readonly properties: Record<string, unknown>;
17
+ }
18
+ /** An open custom element until its end tag: plain, a provider, or a light component. */
19
+ export type Frame = {
20
+ readonly k: 'plain';
21
+ } | {
22
+ readonly k: 'provider';
23
+ readonly outer: unknown;
24
+ } | {
25
+ readonly k: 'light';
26
+ readonly tag: string;
27
+ readonly items: number;
28
+ };
29
+ export declare const PLAIN: Frame;
30
+ export declare class Markup {
31
+ protected readonly dev: boolean;
32
+ protected scope: unknown;
33
+ protected buf: string;
34
+ protected readonly items: Item[];
35
+ /**
36
+ * `dev`: development markers and checks. `scope`: the nearest provider's scope, passed to
37
+ * components (undefined: the request's).
38
+ */
39
+ constructor(dev: boolean, scope: unknown);
40
+ write(markup: string): void;
41
+ /** The markup and deferred components written so far. */
42
+ done(): Item[];
43
+ private flush;
44
+ /** `name=${v}` or `name="a ${v} b"`; returns the index of the next value. */
45
+ protected attr(s: Extract<Segment, {
46
+ k: 'attr';
47
+ }>, values: readonly unknown[], at: number, opening: Opening | undefined): number;
48
+ private valued;
49
+ /** A present boolean attribute (`?name`, or `true` from a hook's server half). */
50
+ protected bare(name: string, opening: Opening | undefined): void;
51
+ /** An element hook: its server half's attributes (02 "Element hooks"). */
52
+ protected hook(v: unknown, opening: Opening | undefined): void;
53
+ /** A custom element's start tag: a Gyral component, a provider, or a plain element. */
54
+ protected open(tag: string, html: string, attrs: readonly (readonly [string, string])[]): Opening | undefined;
55
+ protected openEnd(opening: Opening | undefined): Frame;
56
+ protected close(frame: Frame, tag: string): void;
57
+ }
@@ -0,0 +1,121 @@
1
+ import { serverComponent, serverProvider, } from '../registry.js';
2
+ import { hookSpec } from '../render/hooks.js';
3
+ import { badHook } from '../render/warn.js';
4
+ import { escapeAttr, onlyWhitespace } from './escape.js';
5
+ import { absent, attrText, checkAttrName, lightChildrenError, multiText } from './values.js';
6
+ export const PLAIN = { k: 'plain' };
7
+ export class Markup {
8
+ /**
9
+ * `dev`: development markers and checks. `scope`: the nearest provider's scope, passed to
10
+ * components (undefined: the request's).
11
+ */
12
+ constructor(dev, scope) {
13
+ this.dev = dev;
14
+ this.scope = scope;
15
+ this.buf = '';
16
+ this.items = [];
17
+ }
18
+ write(markup) {
19
+ this.buf += markup;
20
+ }
21
+ /** The markup and deferred components written so far. */
22
+ done() {
23
+ this.flush();
24
+ return this.items;
25
+ }
26
+ flush() {
27
+ if (this.buf !== '')
28
+ this.items.push(this.buf);
29
+ this.buf = '';
30
+ }
31
+ /** `name=${v}` or `name="a ${v} b"`; returns the index of the next value. */
32
+ attr(s, values, at, opening) {
33
+ const { name, strings } = s;
34
+ const value = strings === undefined
35
+ ? attrText(values[at], s, name, this.dev)
36
+ : multiText(values, at, strings, s, name, this.dev);
37
+ if (value !== null)
38
+ this.valued(name, value, opening);
39
+ return at + (strings === undefined ? 1 : strings.length - 1);
40
+ }
41
+ valued(name, value, opening) {
42
+ this.buf += ` ${name}="${escapeAttr(value)}"`;
43
+ if (opening !== undefined)
44
+ opening.attributes[name] = value;
45
+ }
46
+ /** A present boolean attribute (`?name`, or `true` from a hook's server half). */
47
+ bare(name, opening) {
48
+ this.buf += ` ${name}`;
49
+ if (opening !== undefined)
50
+ opening.attributes[name] = '';
51
+ }
52
+ /** An element hook: its server half's attributes (02 "Element hooks"). */
53
+ hook(v, opening) {
54
+ if (absent(v))
55
+ return;
56
+ const spec = hookSpec(v);
57
+ if (spec === undefined) {
58
+ if (this.dev)
59
+ badHook(v);
60
+ return;
61
+ }
62
+ const attributes = spec.server?.(v.args) ?? {};
63
+ for (const [name, value] of Object.entries(attributes)) {
64
+ checkAttrName(name);
65
+ if (value === true)
66
+ this.bare(name, opening);
67
+ else
68
+ this.valued(name, value, opening);
69
+ }
70
+ }
71
+ /** A custom element's start tag: a Gyral component, a provider, or a plain element. */
72
+ open(tag, html, attrs) {
73
+ this.buf += html;
74
+ const component = serverComponent(tag);
75
+ const provider = component === undefined ? serverProvider(tag) : undefined;
76
+ if (component === undefined && provider === undefined)
77
+ return undefined;
78
+ return { tag, component, provider, attributes: Object.fromEntries(attrs), properties: {} };
79
+ }
80
+ openEnd(opening) {
81
+ if (opening === undefined) {
82
+ this.buf += '>';
83
+ return PLAIN;
84
+ }
85
+ const { attributes, properties } = opening;
86
+ const messages = properties['initialMessages'];
87
+ const input = {
88
+ attributes,
89
+ properties,
90
+ initialMessages: Array.isArray(messages) ? messages : undefined,
91
+ scope: this.scope,
92
+ };
93
+ if (opening.provider !== undefined) {
94
+ const provided = opening.provider.open(input);
95
+ for (const [name, value] of Object.entries(provided.attributes)) {
96
+ this.buf += ` ${name}="${escapeAttr(value)}"`;
97
+ }
98
+ this.buf += '>';
99
+ const frame = { k: 'provider', outer: this.scope };
100
+ this.scope = provided.scope;
101
+ return frame;
102
+ }
103
+ const component = opening.component; // Sound: open() set one of the two.
104
+ this.flush();
105
+ this.items.push({ component, input });
106
+ return component.light ? { k: 'light', tag: opening.tag, items: this.items.length } : PLAIN;
107
+ }
108
+ close(frame, tag) {
109
+ if (frame.k === 'provider')
110
+ this.scope = frame.outer;
111
+ else if (frame.k === 'light') {
112
+ // Whitespace-only children are dropped; anything else is an error (ADR 0014).
113
+ if (this.items.length !== frame.items || !onlyWhitespace(this.buf)) {
114
+ lightChildrenError(frame.tag);
115
+ }
116
+ this.buf = '';
117
+ }
118
+ this.buf += `</${tag}>`;
119
+ }
120
+ }
121
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../../src/view/server/tags.ts"],"names":[],"mappings":"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","sourcesContent":["// Start tags and custom elements for the server renderer (view/06-server.md \"Writing a template\n// result\", \"Components\"): attribute, boolean and hook holes, and what a custom element's\n// `open`/`openEnd`/`close` segments do. A Gyral component's start tag is written here, but\n// its content (seed, shadow root, view) is deferred: the walk returns strings with the\n// deferred components between them, and `render` (index.ts) expands each one in its own step,\n// so every component boundary is a chunk boundary. A provider (`<gyral-stores>`) is a plain\n// element that gives its subtree a scope until its end tag.\nimport type { Segment } from '../normalize/types.js';\nimport {\n serverComponent,\n serverProvider,\n type ServerComponent,\n type ServerProvider,\n type ServerRenderInput,\n} from '../registry.js';\nimport { hookSpec, type HookResult } from '../render/hooks.js';\nimport { badHook } from '../render/warn.js';\nimport { escapeAttr, onlyWhitespace } from './escape.js';\nimport { absent, attrText, checkAttrName, lightChildrenError, multiText } from './values.js';\n\n/** A component whose content is written later, in its own render step. */\nexport interface Deferred {\n readonly component: ServerComponent;\n readonly input: ServerRenderInput;\n}\n\n/** What a walk produces: markup, with deferred components in document order. */\nexport type Item = string | Deferred;\n\n/** A custom element's start tag while its attribute holes are written. */\nexport interface Opening {\n readonly tag: string;\n readonly component: ServerComponent | undefined;\n readonly provider: ServerProvider | undefined;\n readonly attributes: Record<string, string>;\n readonly properties: Record<string, unknown>;\n}\n\n/** An open custom element until its end tag: plain, a provider, or a light component. */\nexport type Frame =\n | { readonly k: 'plain' }\n | { readonly k: 'provider'; readonly outer: unknown }\n | { readonly k: 'light'; readonly tag: string; readonly items: number };\n\nexport const PLAIN: Frame = { k: 'plain' };\n\nexport class Markup {\n protected buf = '';\n protected readonly items: Item[] = [];\n\n /**\n * `dev`: development markers and checks. `scope`: the nearest provider's scope, passed to\n * components (undefined: the request's).\n */\n constructor(\n protected readonly dev: boolean,\n protected scope: unknown,\n ) {}\n\n write(markup: string): void {\n this.buf += markup;\n }\n\n /** The markup and deferred components written so far. */\n done(): Item[] {\n this.flush();\n return this.items;\n }\n\n private flush(): void {\n if (this.buf !== '') this.items.push(this.buf);\n this.buf = '';\n }\n\n /** `name=${v}` or `name=\"a ${v} b\"`; returns the index of the next value. */\n protected attr(\n s: Extract<Segment, { k: 'attr' }>,\n values: readonly unknown[],\n at: number,\n opening: Opening | undefined,\n ): number {\n const { name, strings } = s;\n const value =\n strings === undefined\n ? attrText(values[at], s, name, this.dev)\n : multiText(values, at, strings, s, name, this.dev);\n if (value !== null) this.valued(name, value, opening);\n return at + (strings === undefined ? 1 : strings.length - 1);\n }\n\n private valued(name: string, value: string, opening: Opening | undefined): void {\n this.buf += ` ${name}=\"${escapeAttr(value)}\"`;\n if (opening !== undefined) opening.attributes[name] = value;\n }\n\n /** A present boolean attribute (`?name`, or `true` from a hook's server half). */\n protected bare(name: string, opening: Opening | undefined): void {\n this.buf += ` ${name}`;\n if (opening !== undefined) opening.attributes[name] = '';\n }\n\n /** An element hook: its server half's attributes (02 \"Element hooks\"). */\n protected hook(v: unknown, opening: Opening | undefined): void {\n if (absent(v)) return;\n const spec = hookSpec(v);\n if (spec === undefined) {\n if (this.dev) badHook(v);\n return;\n }\n const attributes = spec.server?.((v as HookResult).args) ?? {};\n for (const [name, value] of Object.entries(attributes)) {\n checkAttrName(name);\n if (value === true) this.bare(name, opening);\n else this.valued(name, value, opening);\n }\n }\n\n /** A custom element's start tag: a Gyral component, a provider, or a plain element. */\n protected open(\n tag: string,\n html: string,\n attrs: readonly (readonly [string, string])[],\n ): Opening | undefined {\n this.buf += html;\n const component = serverComponent(tag);\n const provider = component === undefined ? serverProvider(tag) : undefined;\n if (component === undefined && provider === undefined) return undefined;\n return { tag, component, provider, attributes: Object.fromEntries(attrs), properties: {} };\n }\n\n protected openEnd(opening: Opening | undefined): Frame {\n if (opening === undefined) {\n this.buf += '>';\n return PLAIN;\n }\n const { attributes, properties } = opening;\n const messages = properties['initialMessages'];\n const input: ServerRenderInput = {\n attributes,\n properties,\n initialMessages: Array.isArray(messages) ? (messages as readonly unknown[]) : undefined,\n scope: this.scope,\n };\n if (opening.provider !== undefined) {\n const provided = opening.provider.open(input);\n for (const [name, value] of Object.entries(provided.attributes)) {\n this.buf += ` ${name}=\"${escapeAttr(value)}\"`;\n }\n this.buf += '>';\n const frame: Frame = { k: 'provider', outer: this.scope };\n this.scope = provided.scope;\n return frame;\n }\n const component = opening.component as ServerComponent; // Sound: open() set one of the two.\n this.flush();\n this.items.push({ component, input });\n return component.light ? { k: 'light', tag: opening.tag, items: this.items.length } : PLAIN;\n }\n\n protected close(frame: Frame, tag: string): void {\n if (frame.k === 'provider') this.scope = frame.outer;\n else if (frame.k === 'light') {\n // Whitespace-only children are dropped; anything else is an error (ADR 0014).\n if (this.items.length !== frame.items || !onlyWhitespace(this.buf)) {\n lightChildrenError(frame.tag);\n }\n this.buf = '';\n }\n this.buf += `</${tag}>`;\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export declare const absent: (v: unknown) => boolean;
2
+ export declare const truthy: (v: unknown) => boolean;
3
+ /** A Promise in any hole: server renders are synchronous (06 "API"). Always an error. */
4
+ export declare function checkPromise(v: object, where: string): void;
5
+ /** `name=${v}`: the value to write, or null to leave the attribute out. */
6
+ export declare function attrText(v: unknown, at: object, name: string, dev: boolean): string | null;
7
+ /** `name="a ${x} b"`: pieces joined; `nothing` in any piece leaves the attribute out. */
8
+ export declare function multiText(values: readonly unknown[], from: number, strings: readonly string[], at: object, name: string, dev: boolean): string | null;
9
+ /** `<textarea>`/`<title>` content: child-hole rules flattened to a string, as on the client. */
10
+ export declare function textContent(v: unknown, at: object, dev: boolean): string;
11
+ /** Text written directly in table structure would be foster-parented (rule 7). */
12
+ export declare function fosterError(text: string, parent: string): never;
13
+ /** A light-DOM component owns its children (ADR 0014). */
14
+ export declare function lightChildrenError(tag: string): never;
15
+ /** An attribute name from a hook's server half must not break the start tag. */
16
+ export declare function checkAttrName(name: string): void;
@@ -0,0 +1,86 @@
1
+ // Value rules for attribute and text-content holes on the server (view/02-bindings.md
2
+ // "Attribute values", "Live form state"; view/06-server.md "Writing a template result"),
3
+ // identical to the client's (render/attr-parts.ts) so both sides write the same attributes.
4
+ // And the server-only errors: a Promise anywhere (renders are synchronous), text the parser
5
+ // would move out of table structure, children given to a light-DOM component.
6
+ import { nothing } from '../render/values.js';
7
+ import { warnTrue, warnValue } from '../render/warn.js';
8
+ const SPEC = 'docs/design-docs/view';
9
+ export const absent = (v) => v === null || v === undefined || v === nothing;
10
+ export const truthy = (v) => v !== nothing && !!v;
11
+ const isObject = (v) => (typeof v === 'object' && v !== null) || typeof v === 'function';
12
+ /** `String(v)`: objects and functions as the client writes them (render/attr-parts.ts). */
13
+ const text = String;
14
+ const isThenable = (v) => typeof v.then === 'function';
15
+ /** A Promise in any hole: server renders are synchronous (06 "API"). Always an error. */
16
+ export function checkPromise(v, where) {
17
+ if (!isThenable(v))
18
+ return;
19
+ throw new TypeError(`gyral: ${where} got a Promise. Server renders are synchronous: state is known before ` +
20
+ 'rendering, so load the data first (in the route handler or a form action) and pass ' +
21
+ `it as props (${SPEC}/06-server.md "API").`);
22
+ }
23
+ /** `String(v)` for an attribute value, with the development warning for objects. */
24
+ function written(v, at, name, dev) {
25
+ if (typeof v === 'string')
26
+ return v;
27
+ if (isObject(v)) {
28
+ checkPromise(v, `the attribute ${name}`);
29
+ if (dev)
30
+ warnValue(at, v, `the attribute ${name}`);
31
+ }
32
+ return text(v);
33
+ }
34
+ /** `name=${v}`: the value to write, or null to leave the attribute out. */
35
+ export function attrText(v, at, name, dev) {
36
+ return absent(v) ? null : written(v, at, name, dev);
37
+ }
38
+ /** `name="a ${x} b"`: pieces joined; `nothing` in any piece leaves the attribute out. */
39
+ export function multiText(values, from, strings, at, name, dev) {
40
+ let joined = strings[0] ?? '';
41
+ for (let i = 1; i < strings.length; i++) {
42
+ const v = values[from + i - 1];
43
+ if (v === nothing)
44
+ return null;
45
+ joined +=
46
+ (v === null || v === undefined ? '' : written(v, at, name, dev)) + strings[i];
47
+ }
48
+ return joined;
49
+ }
50
+ /** `<textarea>`/`<title>` content: child-hole rules flattened to a string, as on the client. */
51
+ export function textContent(v, at, dev) {
52
+ if (typeof v === 'string')
53
+ return v;
54
+ if (typeof v === 'number')
55
+ return String(v);
56
+ if (isObject(v)) {
57
+ checkPromise(v, 'the text content');
58
+ if (dev)
59
+ warnValue(at, v, 'the text content');
60
+ return text(v);
61
+ }
62
+ if (dev && v === true)
63
+ warnTrue(at);
64
+ return '';
65
+ }
66
+ /** Text written directly in table structure would be foster-parented (rule 7). */
67
+ export function fosterError(text, parent) {
68
+ throw new Error(`gyral: the text ${JSON.stringify(text.slice(0, 40))} is written directly inside ` +
69
+ `<${parent}>. The HTML parser moves text out of table structure (foster parenting), so ` +
70
+ 'the page would differ from what the client renders. Put text inside a <td>, <th> or ' +
71
+ `<caption> (${SPEC}/09-template-rules.md, rule 7).`);
72
+ }
73
+ /** A light-DOM component owns its children (ADR 0014). */
74
+ export function lightChildrenError(tag) {
75
+ throw new Error(`gyral: <${tag}> renders in light DOM (shadow: false), so it owns its children, but its ` +
76
+ 'parent wrote children inside it. Pass the data as props instead, or make it a shadow ' +
77
+ `component and use <slot> (${SPEC}/06-server.md "Components", ADR 0014).`);
78
+ }
79
+ /** An attribute name from a hook's server half must not break the start tag. */
80
+ export function checkAttrName(name) {
81
+ if (/^[^\s"'>/=\0]+$/.test(name))
82
+ return;
83
+ throw new TypeError(`gyral: an element hook's server half returned the attribute name ${JSON.stringify(name)}, ` +
84
+ `which isn't a valid attribute name (${SPEC}/02-bindings.md "Element hooks").`);
85
+ }
86
+ //# sourceMappingURL=values.js.map