@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,122 @@
1
+ // Development checks for lists (view/03-lists.md "Keys", "Rows must be pure"). Keys must be
2
+ // unique strings or numbers. Skipped rows are re-evaluated and compared with what is committed
3
+ // (template, by id or identity, and values, recursively); a difference warns once per row
4
+ // function. At most 200 rows are checked per flush (per render call outside one), rotating
5
+ // through each list. Only reached under `if (DEV)`.
6
+ import { DEV } from '#view-dev';
7
+ import { isTemplateResult, templateOf } from '../template.js';
8
+ import { BOOL, CHECKED, HOOK, MULTI, OPEN, STATE, TEXTAREA, textOf, TITLE, truthy, } from './attr-parts.js';
9
+ import { ChildPart, EMPTY, INSTANCE, ITEMS, LIST, RAW, TEXT } from './child-part.js';
10
+ import { hookSpec, sameArgs } from './hooks.js';
11
+ import { samePick } from './rows.js';
12
+ import { isList, rawHtml } from './values.js';
13
+ import { badKey, warnImpureRow } from './warn.js';
14
+ /** Rows re-evaluated per flush (render.ts `renderBatch`), or per render call outside one. */
15
+ export const ROW_CHECKS = 200;
16
+ let budget = ROW_CHECKS;
17
+ const warned = new WeakSet();
18
+ /** Called at the start of each flush, or of a `render` call outside one. */
19
+ export function resetRowChecks() {
20
+ budget = ROW_CHECKS;
21
+ }
22
+ /** Keys are unique strings or numbers. Guarded here too: the lazy hydration chunk calls it. */
23
+ export function checkKeys(items, key) {
24
+ if (!DEV)
25
+ return;
26
+ const seen = new Set();
27
+ for (let i = 0; i < items.length; i++) {
28
+ const k = key(items[i]);
29
+ if (typeof k !== 'string' && typeof k !== 'number')
30
+ badKey(k, i, false);
31
+ if (seen.has(k))
32
+ badKey(k, i, true);
33
+ seen.add(k);
34
+ }
35
+ }
36
+ export function recheckRows(list, l) {
37
+ const rows = list.rows;
38
+ const n = rows.length;
39
+ if (n === 0 || budget <= 0 || warned.has(l.row))
40
+ return;
41
+ const count = Math.min(budget, n);
42
+ budget -= count;
43
+ let at = list.cursor % n;
44
+ for (let k = 0; k < count; k++) {
45
+ const row = rows[at];
46
+ if (!sameChild(row, l.row(row.item, row.picked))) {
47
+ warned.add(l.row);
48
+ warnImpureRow(l.row);
49
+ break;
50
+ }
51
+ at = (at + 1) % n;
52
+ }
53
+ list.cursor = at;
54
+ }
55
+ /** Whether rendering `value` into `part` would change nothing. */
56
+ export function sameChild(part, value) {
57
+ if (typeof value === 'string' || typeof value === 'number') {
58
+ return part.kind === TEXT && Object.is(part.value, value);
59
+ }
60
+ if (typeof value === 'object' && value !== null) {
61
+ if (isTemplateResult(value)) {
62
+ if (part.kind !== INSTANCE)
63
+ return false;
64
+ const committed = part.content;
65
+ const template = templateOf(value);
66
+ return ((committed.template === template ||
67
+ (template.id !== undefined && template.id === committed.template.id)) &&
68
+ committed.parts.every((p) => samePart(p, value.values)));
69
+ }
70
+ if (isList(value))
71
+ return part.kind === LIST && sameList(part.content, value);
72
+ if (Array.isArray(value)) {
73
+ if (part.kind !== ITEMS)
74
+ return false;
75
+ const rows = part.content.rows;
76
+ return rows.length === value.length && rows.every((r, i) => sameChild(r, value[i]));
77
+ }
78
+ const html = rawHtml(value);
79
+ if (html !== undefined)
80
+ return part.kind === RAW && part.content.html === html;
81
+ }
82
+ return part.kind === EMPTY;
83
+ }
84
+ function samePart(p, values) {
85
+ if (p instanceof ChildPart)
86
+ return sameChild(p, values[p.at]);
87
+ const part = p;
88
+ const v = values[part.at];
89
+ switch (part.kind) {
90
+ case MULTI:
91
+ return (part.pieces ?? []).every((piece, i) => Object.is(piece, values[part.at + i]));
92
+ case BOOL:
93
+ case CHECKED:
94
+ case STATE:
95
+ case OPEN:
96
+ return part.value === truthy(v);
97
+ case TITLE:
98
+ case TEXTAREA:
99
+ return part.value === textOf(part, v);
100
+ case HOOK: {
101
+ const spec = hookSpec(v);
102
+ if (spec === undefined)
103
+ return part.spec === null;
104
+ return spec === part.spec && sameArgs(v.args, part.args);
105
+ }
106
+ default:
107
+ // ATTR, PROP and VALUE keep the raw committed value.
108
+ return Object.is(part.value, v);
109
+ }
110
+ }
111
+ function sameList(list, l) {
112
+ const rows = list.rows;
113
+ if (rows.length !== l.items.length)
114
+ return false;
115
+ return rows.every((row, i) => {
116
+ const item = l.items[i];
117
+ return (row.item === item &&
118
+ Object.is(row.key, l.key(item)) &&
119
+ samePick(row.picked, l.pick === undefined ? undefined : l.pick(item)));
120
+ });
121
+ }
122
+ //# sourceMappingURL=dev-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-check.js","sourceRoot":"","sources":["../../../src/view/render/dev-check.ts"],"names":[],"mappings":"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","sourcesContent":["// Development checks for lists (view/03-lists.md \"Keys\", \"Rows must be pure\"). Keys must be\n// unique strings or numbers. Skipped rows are re-evaluated and compared with what is committed\n// (template, by id or identity, and values, recursively); a difference warns once per row\n// function. At most 200 rows are checked per flush (per render call outside one), rotating\n// through each list. Only reached under `if (DEV)`.\nimport { DEV } from '#view-dev';\nimport { isTemplateResult, templateOf } from '../template.js';\nimport {\n BOOL,\n CHECKED,\n HOOK,\n MULTI,\n OPEN,\n STATE,\n TEXTAREA,\n textOf,\n TITLE,\n truthy,\n type AttrPart,\n type Part,\n} from './attr-parts.js';\nimport { ChildPart, EMPTY, INSTANCE, ITEMS, LIST, RAW, TEXT } from './child-part.js';\nimport type { RawRange } from './raw.js';\nimport { hookSpec, sameArgs, type HookResult } from './hooks.js';\nimport type { Instance } from './instance.js';\nimport { samePick, type List } from './rows.js';\nimport { isList, rawHtml, type ListResult } from './values.js';\nimport { badKey, warnImpureRow } from './warn.js';\n\n/** Rows re-evaluated per flush (render.ts `renderBatch`), or per render call outside one. */\nexport const ROW_CHECKS = 200;\nlet budget = ROW_CHECKS;\nconst warned = new WeakSet<object>();\n\n/** Called at the start of each flush, or of a `render` call outside one. */\nexport function resetRowChecks(): void {\n budget = ROW_CHECKS;\n}\n\n/** Keys are unique strings or numbers. Guarded here too: the lazy hydration chunk calls it. */\nexport function checkKeys(items: readonly unknown[], key: (item: unknown) => unknown): void {\n if (!DEV) return;\n const seen = new Set<unknown>();\n for (let i = 0; i < items.length; i++) {\n const k = key(items[i]);\n if (typeof k !== 'string' && typeof k !== 'number') badKey(k, i, false);\n if (seen.has(k)) badKey(k, i, true);\n seen.add(k);\n }\n}\n\nexport function recheckRows(list: List, l: ListResult): void {\n const rows = list.rows;\n const n = rows.length;\n if (n === 0 || budget <= 0 || warned.has(l.row)) return;\n const count = Math.min(budget, n);\n budget -= count;\n let at = list.cursor % n;\n for (let k = 0; k < count; k++) {\n const row = rows[at] as ChildPart;\n if (!sameChild(row, l.row(row.item, row.picked))) {\n warned.add(l.row);\n warnImpureRow(l.row);\n break;\n }\n at = (at + 1) % n;\n }\n list.cursor = at;\n}\n\n/** Whether rendering `value` into `part` would change nothing. */\nexport function sameChild(part: ChildPart, value: unknown): boolean {\n if (typeof value === 'string' || typeof value === 'number') {\n return part.kind === TEXT && Object.is(part.value, value);\n }\n if (typeof value === 'object' && value !== null) {\n if (isTemplateResult(value)) {\n if (part.kind !== INSTANCE) return false;\n const committed = part.content as Instance;\n const template = templateOf(value);\n return (\n (committed.template === template ||\n (template.id !== undefined && template.id === committed.template.id)) &&\n committed.parts.every((p) => samePart(p, value.values))\n );\n }\n if (isList(value)) return part.kind === LIST && sameList(part.content as List, value);\n if (Array.isArray(value)) {\n if (part.kind !== ITEMS) return false;\n const rows = (part.content as List).rows;\n return rows.length === value.length && rows.every((r, i) => sameChild(r, value[i]));\n }\n const html = rawHtml(value);\n if (html !== undefined) return part.kind === RAW && (part.content as RawRange).html === html;\n }\n return part.kind === EMPTY;\n}\n\nfunction samePart(p: Part, values: readonly unknown[]): boolean {\n if (p instanceof ChildPart) return sameChild(p, values[p.at]);\n const part = p as AttrPart;\n const v = values[part.at];\n switch (part.kind) {\n case MULTI:\n return (part.pieces ?? []).every((piece, i) => Object.is(piece, values[part.at + i]));\n case BOOL:\n case CHECKED:\n case STATE:\n case OPEN:\n return part.value === truthy(v);\n case TITLE:\n case TEXTAREA:\n return part.value === textOf(part, v);\n case HOOK: {\n const spec = hookSpec(v);\n if (spec === undefined) return part.spec === null;\n return spec === part.spec && sameArgs((v as HookResult).args, part.args);\n }\n default:\n // ATTR, PROP and VALUE keep the raw committed value.\n return Object.is(part.value, v);\n }\n}\n\nfunction sameList(list: List, l: ListResult): boolean {\n const rows = list.rows;\n if (rows.length !== l.items.length) return false;\n return rows.every((row, i) => {\n const item = l.items[i];\n return (\n row.item === item &&\n Object.is(row.key, l.key(item)) &&\n samePick(row.picked, l.pick === undefined ? undefined : l.pick(item))\n );\n });\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { type HookResult, type HookSpec } from './hooks.js';
2
+ /** Defines an element hook: a small behaviour attached to the element it sits on. */
3
+ export declare function defineHook<A extends readonly unknown[]>(spec: HookSpec<A>): (...args: A) => HookResult<A>;
@@ -0,0 +1,20 @@
1
+ // `defineHook` (view/02-bindings.md "Element hooks"): its results carry `commitHook`, so the
2
+ // code that compares arguments and queues client calls is bundled only by apps with hooks.
3
+ import { hookResult, hookSpec, queueHook, sameArgs, } from './hooks.js';
4
+ /** Queues the client call when the hook or its arguments changed. */
5
+ function commitHook(part, result) {
6
+ const spec = hookSpec(result);
7
+ const args = result.args;
8
+ const same = spec === part.spec;
9
+ if (same && sameArgs(args, part.args))
10
+ return;
11
+ part.prev = same ? part.args : undefined;
12
+ part.spec = spec;
13
+ part.args = args;
14
+ queueHook(part);
15
+ }
16
+ /** Defines an element hook: a small behaviour attached to the element it sits on. */
17
+ export function defineHook(spec) {
18
+ return (...args) => hookResult(spec, args, commitHook);
19
+ }
20
+ //# sourceMappingURL=hook-part.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-part.js","sourceRoot":"","sources":["../../../src/view/render/hook-part.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,GAIT,MAAM,YAAY,CAAC;AAEpB,qEAAqE;AACrE,SAAS,UAAU,CAAC,IAAc,EAAE,MAAkB;IACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAiC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC;IAChC,IAAI,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,SAAS,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,UAAU,CACxB,IAAiB;IAEjB,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC","sourcesContent":["// `defineHook` (view/02-bindings.md \"Element hooks\"): its results carry `commitHook`, so the\n// code that compares arguments and queues client calls is bundled only by apps with hooks.\nimport {\n hookResult,\n hookSpec,\n queueHook,\n sameArgs,\n type HookPart,\n type HookResult,\n type HookSpec,\n} from './hooks.js';\n\n/** Queues the client call when the hook or its arguments changed. */\nfunction commitHook(part: HookPart, result: HookResult): void {\n const spec = hookSpec(result) as HookSpec<readonly unknown[]>;\n const args = result.args;\n const same = spec === part.spec;\n if (same && sameArgs(args, part.args)) return;\n part.prev = same ? part.args : undefined;\n part.spec = spec;\n part.args = args;\n queueHook(part);\n}\n\n/** Defines an element hook: a small behaviour attached to the element it sits on. */\nexport function defineHook<A extends readonly unknown[]>(\n spec: HookSpec<A>,\n): (...args: A) => HookResult<A> {\n return (...args) => hookResult(spec, args, commitHook);\n}\n"]}
@@ -0,0 +1,40 @@
1
+ declare const HOOK: unique symbol;
2
+ /** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */
3
+ export declare const COMMIT_HOOK: unique symbol;
4
+ /** Attributes a hook's server half adds to the start tag (`true`: present, no value). */
5
+ export type HookAttributes = Readonly<Record<string, string | true>>;
6
+ export interface HookSpec<A extends readonly unknown[]> {
7
+ /** Attributes for the server-rendered start tag (view/06-server.md). */
8
+ server?(args: A): HookAttributes;
9
+ /** Runs after the commit when `args` changed; `prev` is undefined the first time. */
10
+ client(el: Element, args: A, prev: A | undefined): void;
11
+ }
12
+ /** What a hook returns in a template: `<input ${invalid(errors)}>`. */
13
+ export interface HookResult<A extends readonly unknown[] = readonly unknown[]> {
14
+ readonly [HOOK]: HookSpec<A>;
15
+ readonly [COMMIT_HOOK]: (part: HookPart, result: HookResult) => void;
16
+ readonly args: A;
17
+ }
18
+ /** A hook position as committing sees it (an element part of kind HOOK). */
19
+ export interface HookPart {
20
+ readonly el: Element;
21
+ spec: HookSpec<readonly unknown[]> | null;
22
+ args: readonly unknown[] | undefined;
23
+ prev: readonly unknown[] | undefined;
24
+ }
25
+ export declare const isHook: (value: unknown) => value is HookResult;
26
+ /** The spec of a hook result, or undefined for anything else. */
27
+ export declare const hookSpec: (value: unknown) => HookSpec<readonly unknown[]> | undefined;
28
+ /** Internal (hook-part.ts): a hook result. */
29
+ export declare const hookResult: <A extends readonly unknown[]>(spec: HookSpec<A>, args: A, commit: HookResult[typeof COMMIT_HOOK]) => HookResult<A>;
30
+ /** Shallow comparison of two argument lists, `Object.is` per argument. */
31
+ export declare function sameArgs(a: readonly unknown[], b: readonly unknown[] | undefined): boolean;
32
+ /** Queues `part`'s client call for the end of the render (document order). */
33
+ export declare function queueHook(part: HookPart): void;
34
+ /** The queue position before a render, for `runHooks`/`dropHooks`. */
35
+ export declare const hookMark: () => number;
36
+ /** Runs the `client` calls queued since `mark`, in document order. */
37
+ export declare function runHooks(mark: number): void;
38
+ /** Forgets the calls queued since `mark` (the render threw). */
39
+ export declare function dropHooks(mark: number): void;
40
+ export {};
@@ -0,0 +1,46 @@
1
+ // Element hooks (view/02-bindings.md "Element hooks", "Commit order"): their types and the
2
+ // queue of client calls. A hook position (attr-parts.ts, kind HOOK) queues itself when its
3
+ // arguments change (shallow `Object.is` per argument, hook-part.ts, which also holds
4
+ // `defineHook`); `render` runs the queued `client` calls after the commit, in document order.
5
+ // There is no cleanup: listeners a hook adds to its element are collected with it.
6
+ const HOOK = Symbol('gyral.hook');
7
+ /** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */
8
+ export const COMMIT_HOOK = Symbol('gyral.hook.commit');
9
+ export const isHook = (value) => typeof value === 'object' && value !== null && HOOK in value;
10
+ /** The spec of a hook result, or undefined for anything else. */
11
+ export const hookSpec = (value) => isHook(value) ? value[HOOK] : undefined;
12
+ /** Internal (hook-part.ts): a hook result. */
13
+ export const hookResult = (spec, args, commit) => ({ [HOOK]: spec, [COMMIT_HOOK]: commit, args });
14
+ /** Shallow comparison of two argument lists, `Object.is` per argument. */
15
+ export function sameArgs(a, b) {
16
+ if (b === undefined || a.length !== b.length)
17
+ return false;
18
+ for (let i = 0; i < a.length; i++)
19
+ if (!Object.is(a[i], b[i]))
20
+ return false;
21
+ return true;
22
+ }
23
+ const queue = [];
24
+ /** Queues `part`'s client call for the end of the render (document order). */
25
+ export function queueHook(part) {
26
+ queue.push(part);
27
+ }
28
+ /** The queue position before a render, for `runHooks`/`dropHooks`. */
29
+ export const hookMark = () => queue.length;
30
+ /** Runs the `client` calls queued since `mark`, in document order. */
31
+ export function runHooks(mark) {
32
+ try {
33
+ for (let i = mark; i < queue.length; i++) {
34
+ const part = queue[i];
35
+ part.spec.client(part.el, part.args, part.prev);
36
+ }
37
+ }
38
+ finally {
39
+ queue.length = mark;
40
+ }
41
+ }
42
+ /** Forgets the calls queued since `mark` (the render threw). */
43
+ export function dropHooks(mark) {
44
+ queue.length = mark;
45
+ }
46
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/view/render/hooks.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,2FAA2F;AAC3F,qFAAqF;AACrF,8FAA8F;AAC9F,mFAAmF;AAEnF,MAAM,IAAI,GAAkB,MAAM,CAAC,YAAY,CAAC,CAAC;AACjD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAkB,MAAM,CAAC,mBAAmB,CAAC,CAAC;AA2BtE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAuB,EAAE,CAC5D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC;AAE/D,iEAAiE;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA4C,EAAE,CACnF,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAE1C,8CAA8C;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAiB,EACjB,IAAO,EACP,MAAsC,EACvB,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAEpE,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,CAAqB,EAAE,CAAiC;IAC/E,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,KAAK,GAAe,EAAE,CAAC;AAE7B,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAEnD,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAa,CAAC;YACjC,IAAI,CAAC,IAAqC,CAAC,MAAM,CAChD,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,IAA0B,EAC/B,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;IACH,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACtB,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;AACtB,CAAC","sourcesContent":["// Element hooks (view/02-bindings.md \"Element hooks\", \"Commit order\"): their types and the\n// queue of client calls. A hook position (attr-parts.ts, kind HOOK) queues itself when its\n// arguments change (shallow `Object.is` per argument, hook-part.ts, which also holds\n// `defineHook`); `render` runs the queued `client` calls after the commit, in document order.\n// There is no cleanup: listeners a hook adds to its element are collected with it.\n\nconst HOOK: unique symbol = Symbol('gyral.hook');\n/** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */\nexport const COMMIT_HOOK: unique symbol = Symbol('gyral.hook.commit');\n\n/** Attributes a hook's server half adds to the start tag (`true`: present, no value). */\nexport type HookAttributes = Readonly<Record<string, string | true>>;\n\nexport interface HookSpec<A extends readonly unknown[]> {\n /** Attributes for the server-rendered start tag (view/06-server.md). */\n server?(args: A): HookAttributes;\n /** Runs after the commit when `args` changed; `prev` is undefined the first time. */\n client(el: Element, args: A, prev: A | undefined): void;\n}\n\n/** What a hook returns in a template: `<input ${invalid(errors)}>`. */\nexport interface HookResult<A extends readonly unknown[] = readonly unknown[]> {\n readonly [HOOK]: HookSpec<A>;\n readonly [COMMIT_HOOK]: (part: HookPart, result: HookResult) => void;\n readonly args: A;\n}\n\n/** A hook position as committing sees it (an element part of kind HOOK). */\nexport interface HookPart {\n readonly el: Element;\n spec: HookSpec<readonly unknown[]> | null;\n args: readonly unknown[] | undefined;\n prev: readonly unknown[] | undefined;\n}\n\nexport const isHook = (value: unknown): value is HookResult =>\n typeof value === 'object' && value !== null && HOOK in value;\n\n/** The spec of a hook result, or undefined for anything else. */\nexport const hookSpec = (value: unknown): HookSpec<readonly unknown[]> | undefined =>\n isHook(value) ? value[HOOK] : undefined;\n\n/** Internal (hook-part.ts): a hook result. */\nexport const hookResult = <A extends readonly unknown[]>(\n spec: HookSpec<A>,\n args: A,\n commit: HookResult[typeof COMMIT_HOOK],\n): HookResult<A> => ({ [HOOK]: spec, [COMMIT_HOOK]: commit, args });\n\n/** Shallow comparison of two argument lists, `Object.is` per argument. */\nexport function sameArgs(a: readonly unknown[], b: readonly unknown[] | undefined): boolean {\n if (b === undefined || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;\n return true;\n}\n\nconst queue: HookPart[] = [];\n\n/** Queues `part`'s client call for the end of the render (document order). */\nexport function queueHook(part: HookPart): void {\n queue.push(part);\n}\n\n/** The queue position before a render, for `runHooks`/`dropHooks`. */\nexport const hookMark = (): number => queue.length;\n\n/** Runs the `client` calls queued since `mark`, in document order. */\nexport function runHooks(mark: number): void {\n try {\n for (let i = mark; i < queue.length; i++) {\n const part = queue[i] as HookPart;\n (part.spec as HookSpec<readonly unknown[]>).client(\n part.el,\n part.args as readonly unknown[],\n part.prev,\n );\n }\n } finally {\n queue.length = mark;\n }\n}\n\n/** Forgets the calls queued since `mark` (the render threw). */\nexport function dropHooks(mark: number): void {\n queue.length = mark;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { type SeenMarkup } from './seen.js';
2
+ import type { ChildValue } from './values.js';
3
+ /**
4
+ * Hydrates the server-rendered DOM in `root` with `value`, the first client render
5
+ * (view/07-hydration.md): builds the parts over the existing nodes, runs element hooks' client
6
+ * halves once, and leaves later `render` calls to update in place. Throws `HydrationMismatch`
7
+ * when the DOM doesn't match; `host` names the component in its message; `seen` is as for
8
+ * `render`.
9
+ */
10
+ export declare function hydrate(value: ChildValue, root: Element | ShadowRoot, host?: string, seen?: SeenMarkup): void;
@@ -0,0 +1,33 @@
1
+ // `hydrate(value, root)` (view/07-hydration.md): the first client render of server-rendered DOM.
2
+ // Kept apart from render.ts so the walk (adopt.ts) is bundled only where hydration is used: core
3
+ // loads it lazily, with the first server-rendered host (07 "Loading").
4
+ import { adopt } from './adopt.js';
5
+ import { ChildPart } from './child-part.js';
6
+ import { dropHooks, hookMark, runHooks } from './hooks.js';
7
+ import { setRootPart } from './render.js';
8
+ import { listenFor } from './seen.js';
9
+ /**
10
+ * Hydrates the server-rendered DOM in `root` with `value`, the first client render
11
+ * (view/07-hydration.md): builds the parts over the existing nodes, runs element hooks' client
12
+ * halves once, and leaves later `render` calls to update in place. Throws `HydrationMismatch`
13
+ * when the DOM doesn't match; `host` names the component in its message; `seen` is as for
14
+ * `render`.
15
+ */
16
+ export function hydrate(value, root, host = 'the root', seen) {
17
+ const part = new ChildPart(root, null, null, 0, false, 0);
18
+ const mark = hookMark();
19
+ const outer = listenFor(seen);
20
+ try {
21
+ adopt(part, value, root, host);
22
+ }
23
+ catch (error) {
24
+ dropHooks(mark);
25
+ throw error;
26
+ }
27
+ finally {
28
+ listenFor(outer);
29
+ }
30
+ setRootPart(root, part);
31
+ runHooks(mark);
32
+ }
33
+ //# sourceMappingURL=hydrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../../../src/view/render/hydrate.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,iGAAiG;AACjG,uEAAuE;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAGvD;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CACrB,KAAiB,EACjB,IAA0B,EAC1B,IAAI,GAAG,UAAU,EACjB,IAAiB;IAEjB,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC","sourcesContent":["// `hydrate(value, root)` (view/07-hydration.md): the first client render of server-rendered DOM.\n// Kept apart from render.ts so the walk (adopt.ts) is bundled only where hydration is used: core\n// loads it lazily, with the first server-rendered host (07 \"Loading\").\nimport { adopt } from './adopt.js';\nimport { ChildPart } from './child-part.js';\nimport { dropHooks, hookMark, runHooks } from './hooks.js';\nimport { setRootPart } from './render.js';\nimport { listenFor, type SeenMarkup } from './seen.js';\nimport type { ChildValue } from './values.js';\n\n/**\n * Hydrates the server-rendered DOM in `root` with `value`, the first client render\n * (view/07-hydration.md): builds the parts over the existing nodes, runs element hooks' client\n * halves once, and leaves later `render` calls to update in place. Throws `HydrationMismatch`\n * when the DOM doesn't match; `host` names the component in its message; `seen` is as for\n * `render`.\n */\nexport function hydrate(\n value: ChildValue,\n root: Element | ShadowRoot,\n host = 'the root',\n seen?: SeenMarkup,\n): void {\n const part = new ChildPart(root, null, null, 0, false, 0);\n const mark = hookMark();\n const outer = listenFor(seen);\n try {\n adopt(part, value, root, host);\n } catch (error) {\n dropHooks(mark);\n throw error;\n } finally {\n listenFor(outer);\n }\n setRootPart(root, part);\n runHooks(mark);\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { TemplateObject } from '../normalize/types.js';
2
+ import { type Part } from './attr-parts.js';
3
+ import { ChildPart, type Owner } from './child-part.js';
4
+ /** The DOM cloned from one template, plus its parts. */
5
+ export declare class Instance implements Owner {
6
+ readonly template: TemplateObject;
7
+ /** The result source last rendered (strings array or compiled object), for a fast compare. */
8
+ source: unknown;
9
+ /** The child part whose content this instance is. */
10
+ readonly holder: ChildPart;
11
+ readonly parts: Part[];
12
+ /** First and last static root nodes; null when the template is a single hole. */
13
+ start: Node | null;
14
+ end: Node | null;
15
+ /** Root-level child parts before the first / after the last static root node. */
16
+ head: ChildPart | null;
17
+ tail: ChildPart | null;
18
+ /** The clone, until it is inserted. */
19
+ frag: DocumentFragment | null;
20
+ /** `adopt`: hydration (adopt.ts) fills the parts and root nodes from server DOM instead. */
21
+ constructor(template: TemplateObject, source: unknown, holder: ChildPart, adopt?: boolean);
22
+ private build;
23
+ /** Commits this render's values, part by part in document order. */
24
+ update(values: readonly unknown[]): void;
25
+ /** Inserts the (committed) clone; afterwards root-level parts resolve through the holder. */
26
+ insert(parent: Node, before: Node | null): void;
27
+ first(): Node | null;
28
+ last(): Node | null;
29
+ remove(): void;
30
+ /** Owner of root-level open parts: the clone while building, then the holder's parent. */
31
+ parentFor(): Node;
32
+ endFor(): Node | null;
33
+ }
@@ -0,0 +1,107 @@
1
+ import { attrPart } from './attr-parts.js';
2
+ import { ChildPart } from './child-part.js';
3
+ import { removeRange } from './nodes.js';
4
+ import { report } from './seen.js';
5
+ import { CHILD, nodes, planOf, ROOT, stack, walk } from './plan.js';
6
+ /** The DOM cloned from one template, plus its parts. */
7
+ export class Instance {
8
+ /** `adopt`: hydration (adopt.ts) fills the parts and root nodes from server DOM instead. */
9
+ constructor(template, source, holder, adopt) {
10
+ this.template = template;
11
+ this.source = source;
12
+ this.holder = holder;
13
+ this.parts = [];
14
+ this.head = null;
15
+ this.tail = null;
16
+ this.frag = this.start = this.end = null;
17
+ report(template);
18
+ if (adopt === true)
19
+ return;
20
+ const plan = planOf(template);
21
+ if (plan.single) {
22
+ const root = document.importNode(plan.content.firstChild, true);
23
+ stack[1] = root;
24
+ this.start = this.end = root;
25
+ }
26
+ else {
27
+ const frag = document.importNode(plan.content, true);
28
+ stack[0] = frag;
29
+ this.frag = frag;
30
+ this.start = frag.firstChild;
31
+ this.end = frag.lastChild;
32
+ }
33
+ walk(plan);
34
+ this.build(plan);
35
+ }
36
+ build(plan) {
37
+ const { a, b, at, kinds } = plan;
38
+ const specs = this.template.parts;
39
+ for (let i = 0; i < kinds.length; i++) {
40
+ const kind = kinds[i];
41
+ const node = nodes[a[i]];
42
+ if (kind >= 0) {
43
+ this.parts.push(attrPart(node, kind, specs[i], at[i]));
44
+ continue;
45
+ }
46
+ const r = b[i];
47
+ const ref = r >= 0 ? nodes[r] : null;
48
+ if (kind !== ROOT) {
49
+ this.parts.push(new ChildPart(node, ref, null, 0, kind !== CHILD, at[i]));
50
+ continue;
51
+ }
52
+ const part = new ChildPart(null, ref, ref === null ? this : null, 0, false, at[i]);
53
+ if (ref === null)
54
+ this.tail = part;
55
+ else if (ref === this.start)
56
+ this.head = part;
57
+ this.parts.push(part);
58
+ }
59
+ }
60
+ /** Commits this render's values, part by part in document order. */
61
+ update(values) {
62
+ const parts = this.parts;
63
+ for (let i = 0; i < parts.length; i++)
64
+ parts[i].set(values);
65
+ }
66
+ /** Inserts the (committed) clone; afterwards root-level parts resolve through the holder. */
67
+ insert(parent, before) {
68
+ parent.insertBefore(this.frag ?? this.start, before);
69
+ this.frag = null;
70
+ }
71
+ first() {
72
+ const head = this.head !== null ? this.head.first() : null;
73
+ if (head !== null)
74
+ return head;
75
+ if (this.start !== null)
76
+ return this.start;
77
+ return this.tail !== null ? this.tail.first() : null;
78
+ }
79
+ last() {
80
+ const tail = this.tail !== null ? this.tail.last() : null;
81
+ if (tail !== null)
82
+ return tail;
83
+ if (this.end !== null)
84
+ return this.end;
85
+ return this.head !== null ? this.head.last() : null;
86
+ }
87
+ remove() {
88
+ const first = this.first();
89
+ if (first === null)
90
+ return;
91
+ const last = this.last();
92
+ if (first === last)
93
+ first.remove();
94
+ else
95
+ removeRange(first, last);
96
+ }
97
+ /** Owner of root-level open parts: the clone while building, then the holder's parent. */
98
+ parentFor() {
99
+ if (this.frag !== null)
100
+ return this.frag;
101
+ return this.start !== null ? this.start.parentNode : this.holder.parent();
102
+ }
103
+ endFor() {
104
+ return this.frag !== null ? null : this.holder.end();
105
+ }
106
+ }
107
+ //# sourceMappingURL=instance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance.js","sourceRoot":"","sources":["../../../src/view/render/instance.ts"],"names":[],"mappings":"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","sourcesContent":["// Template instances (view/01-templates.md \"Instantiation\", view/02-bindings.md \"Commit order\").\n// An instance is cloned with `document.importNode` (nested custom elements upgrade at once),\n// every part's nodes are resolved from the clone first by child-index paths (firstChild/\n// nextSibling, sharing prefixes; no TreeWalker, no marker search), then the values commit while\n// the clone is still detached, and only then is it inserted, so child components connect with\n// their props set. A template with one root node and no root-level holes clones just that node.\n// How to reach the nodes, and what each part is, comes from the template's plan (plan.ts).\n// Hydration (adopt.ts) creates instances with `adopt` set and fills them from server DOM.\nimport type { PartSpec, TemplateObject } from '../normalize/types.js';\nimport { attrPart, type Part } from './attr-parts.js';\nimport { ChildPart, type Owner } from './child-part.js';\nimport { removeRange } from './nodes.js';\nimport { report } from './seen.js';\nimport { CHILD, nodes, planOf, ROOT, stack, walk, type Plan } from './plan.js';\n\n/** The DOM cloned from one template, plus its parts. */\nexport class Instance implements Owner {\n readonly template: TemplateObject;\n /** The result source last rendered (strings array or compiled object), for a fast compare. */\n source: unknown;\n /** The child part whose content this instance is. */\n readonly holder: ChildPart;\n readonly parts: Part[];\n /** First and last static root nodes; null when the template is a single hole. */\n start: Node | null;\n end: Node | null;\n /** Root-level child parts before the first / after the last static root node. */\n head: ChildPart | null;\n tail: ChildPart | null;\n /** The clone, until it is inserted. */\n frag: DocumentFragment | null;\n\n /** `adopt`: hydration (adopt.ts) fills the parts and root nodes from server DOM instead. */\n constructor(template: TemplateObject, source: unknown, holder: ChildPart, adopt?: boolean) {\n this.template = template;\n this.source = source;\n this.holder = holder;\n this.parts = [];\n this.head = null;\n this.tail = null;\n this.frag = this.start = this.end = null;\n report(template);\n if (adopt === true) return;\n const plan = planOf(template);\n if (plan.single) {\n const root = document.importNode(plan.content.firstChild as Node, true);\n stack[1] = root;\n this.start = this.end = root;\n } else {\n const frag = document.importNode(plan.content, true);\n stack[0] = frag;\n this.frag = frag;\n this.start = frag.firstChild;\n this.end = frag.lastChild;\n }\n walk(plan);\n this.build(plan);\n }\n\n private build(plan: Plan): void {\n const { a, b, at, kinds } = plan;\n const specs = this.template.parts;\n for (let i = 0; i < kinds.length; i++) {\n const kind = kinds[i] as number;\n const node = nodes[a[i] as number] as Element;\n if (kind >= 0) {\n this.parts.push(attrPart(node, kind, specs[i] as PartSpec, at[i] as number));\n continue;\n }\n const r = b[i] as number;\n const ref = r >= 0 ? (nodes[r] as Node) : null;\n if (kind !== ROOT) {\n this.parts.push(new ChildPart(node, ref, null, 0, kind !== CHILD, at[i] as number));\n continue;\n }\n const part = new ChildPart(null, ref, ref === null ? this : null, 0, false, at[i] as number);\n if (ref === null) this.tail = part;\n else if (ref === this.start) this.head = part;\n this.parts.push(part);\n }\n }\n\n /** Commits this render's values, part by part in document order. */\n update(values: readonly unknown[]): void {\n const parts = this.parts;\n for (let i = 0; i < parts.length; i++) (parts[i] as Part).set(values);\n }\n\n /** Inserts the (committed) clone; afterwards root-level parts resolve through the holder. */\n insert(parent: Node, before: Node | null): void {\n parent.insertBefore(this.frag ?? (this.start as Node), before);\n this.frag = null;\n }\n\n first(): Node | null {\n const head = this.head !== null ? this.head.first() : null;\n if (head !== null) return head;\n if (this.start !== null) return this.start;\n return this.tail !== null ? this.tail.first() : null;\n }\n\n last(): Node | null {\n const tail = this.tail !== null ? this.tail.last() : null;\n if (tail !== null) return tail;\n if (this.end !== null) return this.end;\n return this.head !== null ? this.head.last() : null;\n }\n\n remove(): void {\n const first = this.first();\n if (first === null) return;\n const last = this.last() as Node;\n if (first === last) (first as ChildNode).remove();\n else removeRange(first, last);\n }\n\n /** Owner of root-level open parts: the clone while building, then the holder's parent. */\n parentFor(): Node {\n if (this.frag !== null) return this.frag;\n return this.start !== null ? (this.start.parentNode as Node) : this.holder.parent();\n }\n\n endFor(): Node | null {\n return this.frag !== null ? null : this.holder.end();\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { ChildPart } from './child-part.js';
2
+ import { List } from './rows.js';
3
+ import { type ChildValue, type ListResult } from './values.js';
4
+ export { List } from './rows.js';
5
+ /** Removes every row; the list's part keeps its (now empty) list. */
6
+ export declare function clearList(part: ChildPart, list: List): void;
7
+ /**
8
+ * Creates rows for `l.items[from…to]` (keys from `keys[i - from]` when given) into one
9
+ * fragment, pushes them onto `rows` and inserts the fragment before `end`.
10
+ */
11
+ export declare function createRows(part: ChildPart, list: List, l: ListResult, rows: ChildPart[], from: number, to: number, end: Node | null, keys?: readonly unknown[]): void;
12
+ /**
13
+ * A keyed list (view/03-lists.md). `key` must give each item a unique string or number; `row`
14
+ * must depend only on its arguments: a row re-renders only when its item object or its `pick`
15
+ * result changes.
16
+ */
17
+ export declare function each<T>(items: readonly T[], key: (item: T) => string | number, row: (item: T) => ChildValue): ListResult;
18
+ export declare function each<T, P>(items: readonly T[], key: (item: T) => string | number, row: (item: T, picked: P) => ChildValue, pick: (item: T) => P): ListResult;
19
+ /** A positional array: items reused by index (view/02-bindings.md "Child values"). */
20
+ export declare function commitItems(part: ChildPart, values: readonly unknown[]): void;