@madojs/mado 0.5.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 (162) hide show
  1. package/AGENTS.md +291 -0
  2. package/CHANGELOG.md +23 -0
  3. package/LICENSE +21 -0
  4. package/README.md +371 -0
  5. package/ROADMAP.md +52 -0
  6. package/dist/src/component.d.ts +48 -0
  7. package/dist/src/component.js +140 -0
  8. package/dist/src/component.js.map +1 -0
  9. package/dist/src/context.d.ts +40 -0
  10. package/dist/src/context.js +67 -0
  11. package/dist/src/context.js.map +1 -0
  12. package/dist/src/css.d.ts +54 -0
  13. package/dist/src/css.js +137 -0
  14. package/dist/src/css.js.map +1 -0
  15. package/dist/src/devtools.d.ts +22 -0
  16. package/dist/src/devtools.js +63 -0
  17. package/dist/src/devtools.js.map +1 -0
  18. package/dist/src/diagnostics.d.ts +11 -0
  19. package/dist/src/diagnostics.js +28 -0
  20. package/dist/src/diagnostics.js.map +1 -0
  21. package/dist/src/each.d.ts +39 -0
  22. package/dist/src/each.js +35 -0
  23. package/dist/src/each.js.map +1 -0
  24. package/dist/src/forms.d.ts +71 -0
  25. package/dist/src/forms.js +161 -0
  26. package/dist/src/forms.js.map +1 -0
  27. package/dist/src/head.d.ts +19 -0
  28. package/dist/src/head.js +97 -0
  29. package/dist/src/head.js.map +1 -0
  30. package/dist/src/html/bindings.d.ts +78 -0
  31. package/dist/src/html/bindings.js +304 -0
  32. package/dist/src/html/bindings.js.map +1 -0
  33. package/dist/src/html/parser.d.ts +64 -0
  34. package/dist/src/html/parser.js +521 -0
  35. package/dist/src/html/parser.js.map +1 -0
  36. package/dist/src/html/template-types.d.ts +27 -0
  37. package/dist/src/html/template-types.js +8 -0
  38. package/dist/src/html/template-types.js.map +1 -0
  39. package/dist/src/html/template.d.ts +45 -0
  40. package/dist/src/html/template.js +119 -0
  41. package/dist/src/html/template.js.map +1 -0
  42. package/dist/src/html.d.ts +16 -0
  43. package/dist/src/html.js +16 -0
  44. package/dist/src/html.js.map +1 -0
  45. package/dist/src/index.d.ts +35 -0
  46. package/dist/src/index.js +39 -0
  47. package/dist/src/index.js.map +1 -0
  48. package/dist/src/lazy.d.ts +38 -0
  49. package/dist/src/lazy.js +73 -0
  50. package/dist/src/lazy.js.map +1 -0
  51. package/dist/src/lifecycle.d.ts +45 -0
  52. package/dist/src/lifecycle.js +66 -0
  53. package/dist/src/lifecycle.js.map +1 -0
  54. package/dist/src/page.d.ts +161 -0
  55. package/dist/src/page.js +38 -0
  56. package/dist/src/page.js.map +1 -0
  57. package/dist/src/persisted.d.ts +47 -0
  58. package/dist/src/persisted.js +119 -0
  59. package/dist/src/persisted.js.map +1 -0
  60. package/dist/src/resource.d.ts +120 -0
  61. package/dist/src/resource.js +275 -0
  62. package/dist/src/resource.js.map +1 -0
  63. package/dist/src/router/manifest.d.ts +56 -0
  64. package/dist/src/router/manifest.js +302 -0
  65. package/dist/src/router/manifest.js.map +1 -0
  66. package/dist/src/router/match.d.ts +62 -0
  67. package/dist/src/router/match.js +117 -0
  68. package/dist/src/router/match.js.map +1 -0
  69. package/dist/src/router/navigation.d.ts +89 -0
  70. package/dist/src/router/navigation.js +263 -0
  71. package/dist/src/router/navigation.js.map +1 -0
  72. package/dist/src/router.d.ts +13 -0
  73. package/dist/src/router.js +13 -0
  74. package/dist/src/router.js.map +1 -0
  75. package/dist/src/signal.d.ts +67 -0
  76. package/dist/src/signal.js +238 -0
  77. package/dist/src/signal.js.map +1 -0
  78. package/docs/README.md +12 -0
  79. package/docs/en/00-the-mado-way.md +106 -0
  80. package/docs/en/01-routing.md +204 -0
  81. package/docs/en/02-project-layout.md +58 -0
  82. package/docs/en/03-static-bake.md +251 -0
  83. package/docs/en/04-ide-setup.md +162 -0
  84. package/docs/en/05-why-mado.md +193 -0
  85. package/docs/en/06-for-backenders.md +422 -0
  86. package/docs/en/07-llm-pitfalls.md +486 -0
  87. package/docs/en/08-llm-zero-history-test.md +56 -0
  88. package/docs/en/09-shadow-vs-light-dom.md +122 -0
  89. package/docs/en/README.md +16 -0
  90. package/docs/fr/00-the-mado-way.md +108 -0
  91. package/docs/fr/01-routing.md +202 -0
  92. package/docs/fr/02-project-layout.md +58 -0
  93. package/docs/fr/03-static-bake.md +290 -0
  94. package/docs/fr/04-ide-setup.md +162 -0
  95. package/docs/fr/05-why-mado.md +193 -0
  96. package/docs/fr/06-for-backenders.md +432 -0
  97. package/docs/fr/07-llm-pitfalls.md +487 -0
  98. package/docs/fr/08-llm-zero-history-test.md +60 -0
  99. package/docs/fr/09-shadow-vs-light-dom.md +121 -0
  100. package/docs/fr/README.md +16 -0
  101. package/docs/ru/00-the-mado-way.md +93 -0
  102. package/docs/ru/01-routing.md +194 -0
  103. package/docs/ru/02-project-layout.md +57 -0
  104. package/docs/ru/03-static-bake.md +251 -0
  105. package/docs/ru/04-ide-setup.md +144 -0
  106. package/docs/ru/05-why-mado.md +193 -0
  107. package/docs/ru/06-for-backenders.md +422 -0
  108. package/docs/ru/07-llm-pitfalls.md +485 -0
  109. package/docs/ru/08-llm-zero-history-test.md +56 -0
  110. package/docs/ru/09-shadow-vs-light-dom.md +122 -0
  111. package/docs/ru/README.md +14 -0
  112. package/docs/uk/00-the-mado-way.md +54 -0
  113. package/docs/uk/01-routing.md +82 -0
  114. package/docs/uk/02-project-layout.md +46 -0
  115. package/docs/uk/03-static-bake.md +49 -0
  116. package/docs/uk/04-ide-setup.md +26 -0
  117. package/docs/uk/05-why-mado.md +34 -0
  118. package/docs/uk/06-for-backenders.md +50 -0
  119. package/docs/uk/07-llm-pitfalls.md +82 -0
  120. package/docs/uk/08-llm-zero-history-test.md +31 -0
  121. package/docs/uk/09-shadow-vs-light-dom.md +40 -0
  122. package/docs/uk/README.md +16 -0
  123. package/llms.txt +155 -0
  124. package/package.json +81 -0
  125. package/scripts/bake.mjs +406 -0
  126. package/scripts/bundle.mjs +146 -0
  127. package/scripts/cli.mjs +382 -0
  128. package/scripts/new.mjs +80 -0
  129. package/scripts/preview.mjs +176 -0
  130. package/scripts/release-notes.mjs +66 -0
  131. package/scripts/showcase-regression.mjs +392 -0
  132. package/server/serve.mjs +292 -0
  133. package/starters/crud/README.md +21 -0
  134. package/starters/crud/index.html +20 -0
  135. package/starters/crud/package.json +17 -0
  136. package/starters/crud/src/components/app-shell.ts +51 -0
  137. package/starters/crud/src/components/ticket-detail.ts +33 -0
  138. package/starters/crud/src/components/ticket-form.ts +69 -0
  139. package/starters/crud/src/components/ticket-list.ts +66 -0
  140. package/starters/crud/src/lib/api.ts +76 -0
  141. package/starters/crud/src/main.ts +12 -0
  142. package/starters/crud/src/pages/home.ts +18 -0
  143. package/starters/crud/src/pages/not-found.ts +12 -0
  144. package/starters/crud/src/pages/ticket-detail.ts +6 -0
  145. package/starters/crud/src/pages/ticket-new.ts +6 -0
  146. package/starters/crud/src/pages/tickets.ts +6 -0
  147. package/starters/crud/src/routes.ts +9 -0
  148. package/starters/crud/src/styles/global.ts +155 -0
  149. package/starters/crud/tsconfig.json +15 -0
  150. package/starters/minimal/README.md +19 -0
  151. package/starters/minimal/index.html +20 -0
  152. package/starters/minimal/package.json +17 -0
  153. package/starters/minimal/src/components/app-counter.ts +31 -0
  154. package/starters/minimal/src/main.ts +9 -0
  155. package/starters/minimal/src/pages/home.ts +18 -0
  156. package/starters/minimal/src/pages/not-found.ts +14 -0
  157. package/starters/minimal/src/routes.ts +6 -0
  158. package/starters/minimal/src/styles/global.ts +60 -0
  159. package/starters/minimal/tsconfig.json +15 -0
  160. package/templates/page-detail.ts +63 -0
  161. package/templates/page-form.ts +94 -0
  162. package/templates/page-list.ts +79 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Bindings: how values end up in DOM nodes after template cloning.
3
+ * All binding types are described in one place so that adding
4
+ * a new one (e.g. `??=` or `style.<prop>`) is intentional and visible.
5
+ *
6
+ * Split into two groups:
7
+ * - bindChild — child binding (text / node / array / TemplateResult / each)
8
+ * - bindAttr — attribute / event / DOM property / boolean
9
+ *
10
+ * Reactivity: if a value is a function (signal/computed), we wrap it
11
+ * in effect(); the returned Disposer goes into the instance's disposers list
12
+ * so that on update()/dispose() everything is properly cleaned up.
13
+ */
14
+ import { effect } from "../signal.js";
15
+ import { isEachResult } from "../each.js";
16
+ import { warnOnce } from "../diagnostics.js";
17
+ import { isTemplateResult, } from "./template-types.js";
18
+ /**
19
+ * Ownership invariant:
20
+ * - ChildState owns everything inserted before its anchor for that binding.
21
+ * - Plain nodes are tracked in current.
22
+ * - Nested TemplateResult instances are tracked in currentInsts and must be
23
+ * dispose()'d before removing current nodes, because they can own deeper
24
+ * anchors/effects/nodes not visible to the parent instance.
25
+ * - each() owns its own InstantiatedTemplate entries through eachEntries.
26
+ */
27
+ export function createChildState(anchor) {
28
+ return {
29
+ anchor,
30
+ current: [],
31
+ currentInsts: [],
32
+ isEach: false,
33
+ eachEntries: new Map(),
34
+ eachOrder: [],
35
+ };
36
+ }
37
+ export function disposeChildState(st) {
38
+ if (st.isEach) {
39
+ for (const entry of st.eachEntries.values())
40
+ entry.inst.dispose();
41
+ st.eachEntries.clear();
42
+ st.eachOrder = [];
43
+ st.isEach = false;
44
+ }
45
+ clearCurrent(st);
46
+ }
47
+ /**
48
+ * Bind a value to a child binding. If value is a function (signal),
49
+ * subscribe via effect(); otherwise render once.
50
+ *
51
+ * instantiateFn is passed as a parameter to avoid circular
52
+ * dependency bindings ↔ template.
53
+ */
54
+ export function bindChild(st, value, disposers, instantiateFn) {
55
+ if (typeof value === "function") {
56
+ const d = effect(() => {
57
+ renderChild(st, value(), instantiateFn);
58
+ });
59
+ disposers.push(d);
60
+ return;
61
+ }
62
+ renderChild(st, value, instantiateFn);
63
+ }
64
+ function renderChild(st, value, instantiateFn) {
65
+ // each result: apply keyed reconciliation
66
+ if (isEachResult(value)) {
67
+ applyEach(st, value, instantiateFn);
68
+ return;
69
+ }
70
+ // switching from each mode to normal: remove each entries
71
+ if (st.isEach) {
72
+ for (const entry of st.eachEntries.values())
73
+ entry.inst.dispose();
74
+ st.eachEntries.clear();
75
+ st.eachOrder = [];
76
+ st.isEach = false;
77
+ }
78
+ // normal branch: clear + recreate
79
+ clearCurrent(st);
80
+ const parent = st.anchor.parentNode;
81
+ if (!parent)
82
+ return;
83
+ const append = (node) => {
84
+ parent.insertBefore(node, st.anchor);
85
+ st.current.push(node);
86
+ };
87
+ const handle = (v) => {
88
+ if (v == null || v === false || v === true)
89
+ return;
90
+ if (v instanceof Node) {
91
+ append(v);
92
+ return;
93
+ }
94
+ if (isTemplateResult(v)) {
95
+ const inst = instantiateFn(v);
96
+ const inserted = [...inst.fragment.childNodes];
97
+ parent.insertBefore(inst.fragment, st.anchor);
98
+ st.currentInsts.push(inst);
99
+ for (const n of inserted)
100
+ st.current.push(n);
101
+ return;
102
+ }
103
+ if (Array.isArray(v)) {
104
+ for (const item of v)
105
+ handle(item);
106
+ return;
107
+ }
108
+ append(document.createTextNode(String(v)));
109
+ };
110
+ handle(value);
111
+ }
112
+ function clearCurrent(st) {
113
+ for (const inst of st.currentInsts.splice(0))
114
+ inst.dispose();
115
+ for (const n of st.current)
116
+ n.parentNode?.removeChild(n);
117
+ st.current = [];
118
+ }
119
+ /**
120
+ * Keyed reconciliation: apply an EachResult to a ChildState.
121
+ *
122
+ * Algorithm (simple and readable, O(n) by keys):
123
+ * 1. If switched from "normal" mode — first clear old content.
124
+ * 2. Build new Map nextEntries: for each item
125
+ * - if key existed — reuse entry, call inst.update(values).
126
+ * - if key is new — instantiate(template).
127
+ * 3. Remove entries for keys no longer in the new list.
128
+ * 4. Place nodes in the correct order via insertBefore(node, refNode).
129
+ * refNode is determined by position: iterate from the end to start,
130
+ * ref = top node of the next entry (or st.anchor for the last).
131
+ */
132
+ function applyEach(st, result, instantiateFn) {
133
+ // Switching from the normal branch to each: clear previous content first.
134
+ if (!st.isEach && (st.current.length > 0 || st.currentInsts.length > 0)) {
135
+ clearCurrent(st);
136
+ }
137
+ st.isEach = true;
138
+ const parent = st.anchor.parentNode;
139
+ if (!parent)
140
+ return;
141
+ const items = result.items;
142
+ const keyOf = result.keyOf;
143
+ const renderFn = result.render;
144
+ // 1) Build new keys and entries.
145
+ const newEntries = new Map();
146
+ const newOrder = [];
147
+ const seen = new Set();
148
+ for (let i = 0; i < items.length; i++) {
149
+ const item = items[i];
150
+ let key = keyOf(item, i);
151
+ if (seen.has(key)) {
152
+ key = `${String(key)}__dup_${i}`;
153
+ }
154
+ seen.add(key);
155
+ const tpl = renderFn(item, i);
156
+ const prev = st.eachEntries.get(key);
157
+ if (prev) {
158
+ // same key → try updating the same instance.
159
+ // If the template changed (different strings) — recreate.
160
+ const sameTemplate = prev.inst._strings === tpl.strings;
161
+ if (sameTemplate) {
162
+ prev.inst.update(tpl.values);
163
+ newEntries.set(key, prev);
164
+ }
165
+ else {
166
+ prev.inst.dispose();
167
+ const inst = instantiateFn(tpl);
168
+ const nodes = [...inst.fragment.childNodes];
169
+ // The fragment is not inserted yet; reorder below will place it.
170
+ newEntries.set(key, { inst, nodes });
171
+ }
172
+ }
173
+ else {
174
+ const inst = instantiateFn(tpl);
175
+ const nodes = [...inst.fragment.childNodes];
176
+ newEntries.set(key, { inst, nodes });
177
+ }
178
+ newOrder.push(key);
179
+ }
180
+ // 2) remove entries for keys no longer present
181
+ for (const [oldKey, oldEntry] of st.eachEntries) {
182
+ if (!newEntries.has(oldKey)) {
183
+ oldEntry.inst.dispose();
184
+ }
185
+ }
186
+ // 3) place nodes in the correct order.
187
+ // Iterate from the end: for each entry insertBefore(node, ref),
188
+ // where ref is the first node of the next entry, or st.anchor for the last.
189
+ let refNode = st.anchor;
190
+ for (let i = newOrder.length - 1; i >= 0; i--) {
191
+ const key = newOrder[i];
192
+ const entry = newEntries.get(key);
193
+ // Insert entry nodes before refNode in the correct order.
194
+ // Go from last to first so every node ends up before refNode in order.
195
+ for (let j = entry.nodes.length - 1; j >= 0; j--) {
196
+ const n = entry.nodes[j];
197
+ // insertBefore moves the node if it is already in the DOM.
198
+ if (n.parentNode !== parent || n.nextSibling !== refNode) {
199
+ parent.insertBefore(n, refNode);
200
+ }
201
+ refNode = n;
202
+ }
203
+ }
204
+ st.eachEntries = newEntries;
205
+ st.eachOrder = newOrder;
206
+ }
207
+ // ---------- Attribute binding ----------
208
+ /**
209
+ * Apply a value to an attr binding. Route by prefix:
210
+ * @event → addEventListener
211
+ * .prop → el[prop] = value
212
+ * ?attr → toggleAttribute by truthy/falsy
213
+ * otherwise → setAttribute / removeAttribute (with multi-part support)
214
+ */
215
+ export function bindAttr(el, spec, values, disposers) {
216
+ const name = spec.name;
217
+ const isMulti = spec.isMulti;
218
+ // event — single only, no interpolation (meaningless)
219
+ if (name.startsWith("@")) {
220
+ if (isMulti) {
221
+ throw new Error(`[mado] event binding ${name} does not support interpolation.`);
222
+ }
223
+ const evt = name.slice(1);
224
+ const handler = values[spec.slots[0]];
225
+ el.addEventListener(evt, handler);
226
+ disposers.push(() => el.removeEventListener(evt, handler));
227
+ return;
228
+ }
229
+ // .prop — DOM property (single only)
230
+ if (name.startsWith(".")) {
231
+ if (isMulti) {
232
+ throw new Error(`[mado] property binding ${name} does not support interpolation.`);
233
+ }
234
+ const prop = name.slice(1);
235
+ const v = values[spec.slots[0]];
236
+ applyReactive(v, disposers, (vv) => {
237
+ el[prop] = vv;
238
+ });
239
+ return;
240
+ }
241
+ // ?attr — boolean attribute (single only)
242
+ if (name.startsWith("?")) {
243
+ if (isMulti) {
244
+ throw new Error(`[mado] boolean binding ${name} does not support interpolation.`);
245
+ }
246
+ const attrName = name.slice(1);
247
+ const v = values[spec.slots[0]];
248
+ applyReactive(v, disposers, (vv) => {
249
+ if (vv)
250
+ el.setAttribute(attrName, "");
251
+ else
252
+ el.removeAttribute(attrName);
253
+ });
254
+ return;
255
+ }
256
+ // ordinary attribute
257
+ if (!isMulti) {
258
+ warnBooleanAttrIfNeeded(name);
259
+ const v = values[spec.slots[0]];
260
+ applyReactive(v, disposers, (vv) => {
261
+ if (vv == null || vv === false)
262
+ el.removeAttribute(name);
263
+ else
264
+ el.setAttribute(name, vv === true ? "" : String(vv));
265
+ });
266
+ return;
267
+ }
268
+ // multi-part: assemble from spec.strings + values[spec.slots[i]].
269
+ // If at least one part is a function (signal), we need an effect.
270
+ const hasReactive = spec.slots.some((s) => typeof values[s] === "function");
271
+ const compute = () => {
272
+ let out = spec.strings[0] ?? "";
273
+ for (let i = 0; i < spec.slots.length; i++) {
274
+ const v = values[spec.slots[i]];
275
+ const resolved = typeof v === "function" ? v() : v;
276
+ out += resolved == null ? "" : String(resolved);
277
+ out += spec.strings[i + 1] ?? "";
278
+ }
279
+ return out;
280
+ };
281
+ if (hasReactive) {
282
+ const d = effect(() => el.setAttribute(name, compute()));
283
+ disposers.push(d);
284
+ }
285
+ else {
286
+ el.setAttribute(name, compute());
287
+ }
288
+ }
289
+ function warnBooleanAttrIfNeeded(name) {
290
+ if (name !== "disabled" && name !== "checked")
291
+ return;
292
+ warnOnce(`boolean-attr-${name}`, `Use ?${name}= for a boolean attribute. ${name}=\${...} sets a string attribute and often behaves incorrectly.`);
293
+ }
294
+ /** Universal wrapper: if a function — subscribe, otherwise apply once. */
295
+ function applyReactive(value, disposers, apply) {
296
+ if (typeof value === "function") {
297
+ const d = effect(() => apply(value()));
298
+ disposers.push(d);
299
+ }
300
+ else {
301
+ apply(value);
302
+ }
303
+ }
304
+ //# sourceMappingURL=bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bindings.js","sourceRoot":"","sources":["../../../src/html/bindings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Tagged-template parser: a state machine that turns strings[] into
3
+ * { template: HTMLTemplateElement, bindings: BindingSpec[] }
4
+ *
5
+ * It does not depend on the reactive runtime (signal/each/effect), only on DOM
6
+ * APIs (document.createElement and walking Node trees). That makes it possible
7
+ * to test the parser in isolation and reuse it for bake / SSR through linkedom.
8
+ *
9
+ * Algorithm:
10
+ * 1. Walk strings[] char-by-char through an explicit finite state machine.
11
+ * For every `${}` slot we know the current context: text, attribute,
12
+ * attribute value, comment, or raw text.
13
+ * 2. Build the final HTML string with markers:
14
+ * - `<!--mado$N-->` for child slots
15
+ * - `data-mado-bind-N="…"` for attributes
16
+ * and keep a parallel BindingSpec list that describes each slot.
17
+ * 3. Parse HTML through `<template>.innerHTML`, then walk() finds markers in
18
+ * the DOM and fills BindingSpec.path and childIndex. Marker attributes are
19
+ * removed from elements; marker comments remain as child binding anchors.
20
+ * 4. Cache by strings identity. TemplateStringsArray is stable for the same
21
+ * tagged literal between calls.
22
+ */
23
+ export declare const CHILD_MARKER_PREFIX = "mado$";
24
+ export declare const ATTR_MARKER_PREFIX = "data-mado-bind-";
25
+ export interface ChildBindingSpec {
26
+ type: "child";
27
+ id: number;
28
+ path: number[];
29
+ childIndex: number;
30
+ slot: number;
31
+ }
32
+ /** Attribute / event / property / boolean — can be multi-part. */
33
+ export interface AttrBindingSpec {
34
+ type: "attr";
35
+ id: number;
36
+ path: number[];
37
+ /** Attribute name: 'class', '@click', '.value', '?disabled'. */
38
+ name: string;
39
+ /**
40
+ * If the attribute is single-part (the entire value = one ${}), then
41
+ * slots = [N], strings = ['', ''], isMulti = false.
42
+ * If multi-part, strings and slots alternate:
43
+ * strings[0] + values[slots[0]] + strings[1] + ... + strings[k]
44
+ */
45
+ strings: string[];
46
+ slots: number[];
47
+ /** True if the value is assembled from multiple parts (static + slots). */
48
+ isMulti: boolean;
49
+ }
50
+ export type BindingSpec = ChildBindingSpec | AttrBindingSpec;
51
+ export interface ParsedTemplate {
52
+ template: HTMLTemplateElement;
53
+ bindings: BindingSpec[];
54
+ }
55
+ /**
56
+ * Main export: parse a tagged-template literal into a ready-to-instantiate
57
+ * ParsedTemplate. Idempotent (cached by strings).
58
+ */
59
+ export declare function parseTemplate(strings: TemplateStringsArray): ParsedTemplate;
60
+ /**
61
+ * Retrieve a node by path from root. Used when instantiating
62
+ * a template to resolve BindingSpec.path → concrete Node in the clone.
63
+ */
64
+ export declare function resolvePath(root: Node, path: number[]): Node;