@fluixi/devtools 0.2.0-alpha.2 → 0.2.0-alpha.4

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 (158) hide show
  1. package/README.md +80 -2
  2. package/dist/callsite.cjs +72 -0
  3. package/dist/callsite.d.ts +22 -0
  4. package/dist/callsite.d.ts.map +1 -0
  5. package/dist/callsite.js +82 -0
  6. package/dist/callsite.mjs +51 -0
  7. package/dist/change-view.cjs +134 -0
  8. package/dist/change-view.d.ts +10 -0
  9. package/dist/change-view.d.ts.map +1 -0
  10. package/dist/change-view.js +102 -0
  11. package/dist/change-view.mjs +111 -0
  12. package/dist/copy.cjs +63 -0
  13. package/dist/copy.d.ts +9 -0
  14. package/dist/copy.d.ts.map +1 -0
  15. package/dist/copy.js +52 -0
  16. package/dist/copy.mjs +42 -0
  17. package/dist/describe.cjs +55 -0
  18. package/dist/describe.d.ts +3 -0
  19. package/dist/describe.d.ts.map +1 -0
  20. package/dist/describe.js +47 -0
  21. package/dist/describe.mjs +34 -0
  22. package/dist/detail-panel.cjs +307 -0
  23. package/dist/detail-panel.d.ts +17 -0
  24. package/dist/detail-panel.d.ts.map +1 -0
  25. package/dist/detail-panel.js +217 -0
  26. package/dist/detail-panel.mjs +284 -0
  27. package/dist/diff.cjs +225 -0
  28. package/dist/diff.d.ts +31 -0
  29. package/dist/diff.d.ts.map +1 -0
  30. package/dist/diff.js +132 -0
  31. package/dist/diff.mjs +202 -0
  32. package/dist/dom.cjs +204 -0
  33. package/dist/dom.d.ts +81 -0
  34. package/dist/dom.d.ts.map +1 -0
  35. package/dist/dom.js +269 -0
  36. package/dist/dom.mjs +183 -0
  37. package/dist/export.cjs +221 -0
  38. package/dist/export.d.ts +55 -0
  39. package/dist/export.d.ts.map +1 -0
  40. package/dist/export.js +90 -0
  41. package/dist/export.mjs +209 -0
  42. package/dist/float.cjs +232 -0
  43. package/dist/float.d.ts +54 -0
  44. package/dist/float.d.ts.map +1 -0
  45. package/dist/float.js +256 -0
  46. package/dist/float.mjs +211 -0
  47. package/dist/format.cjs +175 -0
  48. package/dist/format.d.ts +16 -0
  49. package/dist/format.d.ts.map +1 -0
  50. package/dist/format.js +188 -0
  51. package/dist/format.mjs +154 -0
  52. package/dist/graph-view.cjs +893 -0
  53. package/dist/graph-view.d.ts +79 -2
  54. package/dist/graph-view.d.ts.map +1 -1
  55. package/dist/graph-view.js +866 -50
  56. package/dist/graph-view.mjs +870 -0
  57. package/dist/highlight.cjs +140 -0
  58. package/dist/highlight.d.ts +56 -0
  59. package/dist/highlight.d.ts.map +1 -0
  60. package/dist/highlight.js +154 -0
  61. package/dist/highlight.mjs +119 -0
  62. package/dist/history.cjs +95 -0
  63. package/dist/history.d.ts +59 -0
  64. package/dist/history.d.ts.map +1 -0
  65. package/dist/history.js +85 -0
  66. package/dist/history.mjs +74 -0
  67. package/dist/hook.cjs +1562 -0
  68. package/dist/hook.d.ts +60 -0
  69. package/dist/hook.d.ts.map +1 -0
  70. package/dist/hook.js +142 -0
  71. package/dist/hook.mjs +1553 -0
  72. package/dist/index.cjs +4552 -0
  73. package/dist/index.d.ts +44 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +25 -1
  76. package/dist/index.mjs +4544 -0
  77. package/dist/inspector.cjs +688 -0
  78. package/dist/inspector.d.ts +60 -0
  79. package/dist/inspector.d.ts.map +1 -0
  80. package/dist/inspector.js +415 -0
  81. package/dist/inspector.mjs +676 -0
  82. package/dist/instrument.cjs +497 -0
  83. package/dist/instrument.d.ts +147 -5
  84. package/dist/instrument.d.ts.map +1 -1
  85. package/dist/instrument.js +164 -44
  86. package/dist/instrument.mjs +487 -0
  87. package/dist/kind-filter.cjs +172 -0
  88. package/dist/kind-filter.d.ts +39 -0
  89. package/dist/kind-filter.d.ts.map +1 -0
  90. package/dist/kind-filter.js +151 -0
  91. package/dist/kind-filter.mjs +151 -0
  92. package/dist/menu.cjs +141 -0
  93. package/dist/menu.d.ts +37 -0
  94. package/dist/menu.d.ts.map +1 -0
  95. package/dist/menu.js +125 -0
  96. package/dist/menu.mjs +120 -0
  97. package/dist/observe.cjs +1352 -0
  98. package/dist/observe.d.ts +80 -0
  99. package/dist/observe.d.ts.map +1 -0
  100. package/dist/observe.js +893 -0
  101. package/dist/observe.mjs +1345 -0
  102. package/dist/palette.cjs +52 -0
  103. package/dist/palette.d.ts +11 -0
  104. package/dist/palette.d.ts.map +1 -0
  105. package/dist/palette.js +27 -0
  106. package/dist/palette.mjs +31 -0
  107. package/dist/path.cjs +45 -0
  108. package/dist/path.d.ts +19 -0
  109. package/dist/path.d.ts.map +1 -0
  110. package/dist/path.js +49 -0
  111. package/dist/path.mjs +24 -0
  112. package/dist/plugin.cjs +87 -0
  113. package/dist/plugin.d.ts +121 -0
  114. package/dist/plugin.d.ts.map +1 -0
  115. package/dist/plugin.js +74 -0
  116. package/dist/plugin.mjs +66 -0
  117. package/dist/plugins/context.cjs +98 -0
  118. package/dist/plugins/context.d.ts +10 -0
  119. package/dist/plugins/context.d.ts.map +1 -0
  120. package/dist/plugins/context.js +80 -0
  121. package/dist/plugins/context.mjs +75 -0
  122. package/dist/plugins/directives.cjs +98 -0
  123. package/dist/plugins/directives.d.ts +25 -0
  124. package/dist/plugins/directives.d.ts.map +1 -0
  125. package/dist/plugins/directives.js +78 -0
  126. package/dist/plugins/directives.mjs +75 -0
  127. package/dist/plugins/index.cjs +162 -0
  128. package/dist/plugins/index.d.ts +7 -0
  129. package/dist/plugins/index.d.ts.map +1 -0
  130. package/dist/plugins/index.js +9 -0
  131. package/dist/plugins/index.mjs +140 -0
  132. package/dist/source.cjs +111 -0
  133. package/dist/source.d.ts +72 -0
  134. package/dist/source.d.ts.map +1 -0
  135. package/dist/source.js +153 -0
  136. package/dist/source.mjs +90 -0
  137. package/dist/timeline.cjs +350 -0
  138. package/dist/timeline.d.ts +30 -0
  139. package/dist/timeline.d.ts.map +1 -0
  140. package/dist/timeline.js +271 -0
  141. package/dist/timeline.mjs +327 -0
  142. package/dist/tree.cjs +574 -0
  143. package/dist/tree.d.ts +128 -0
  144. package/dist/tree.d.ts.map +1 -0
  145. package/dist/tree.js +645 -0
  146. package/dist/tree.mjs +551 -0
  147. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  148. package/dist/value-pane.cjs +223 -0
  149. package/dist/value-pane.d.ts +10 -0
  150. package/dist/value-pane.d.ts.map +1 -0
  151. package/dist/value-pane.js +61 -0
  152. package/dist/value-pane.mjs +200 -0
  153. package/dist/wire.cjs +109 -0
  154. package/dist/wire.d.ts +100 -0
  155. package/dist/wire.d.ts.map +1 -0
  156. package/dist/wire.js +93 -0
  157. package/dist/wire.mjs +89 -0
  158. package/package.json +17 -5
package/dist/dom.js ADDED
@@ -0,0 +1,269 @@
1
+ /** Kept in step with LOC_TAG in @fluixi/dom's runtime.ts. */
2
+ const LOC_TAG = '__fx_loc';
3
+ /** The position the runtime stamped on an element, when there is one. */
4
+ function locationOf(element) {
5
+ return element[LOC_TAG];
6
+ }
7
+ /** Elements described per tag. Caps how large a snapshot can get. */
8
+ export const DOM_BUDGET = 200;
9
+ /**
10
+ * Static attributes only: a class computed at runtime is not in the source.
11
+ *
12
+ * Written out rather than spread-and-join. This runs once per element of the page on every
13
+ * sample, and building three throwaway arrays to read at most two class names cost more
14
+ * than everything else the walk does.
15
+ */
16
+ export function describeElement(element) {
17
+ let out = element.tagName.toLowerCase();
18
+ if (element.id)
19
+ out += `#${element.id}`;
20
+ const classes = element.classList;
21
+ if (classes.length > 0) {
22
+ out += `.${classes[0]}`;
23
+ if (classes.length > 1)
24
+ out += `.${classes[1]}`;
25
+ }
26
+ return out;
27
+ }
28
+ /**
29
+ * Describe what every tag rendered, in one pass.
30
+ *
31
+ * Per-tag would rebuild the element maps each time, which is enough work to stall a render
32
+ * loop on a page of any size.
33
+ */
34
+ export function describeAll(graph,
35
+ /** What a tag returned. Must not fall back to anything, or two tags claim one element. */
36
+ roots,
37
+ /** Where a value writes. */
38
+ writtenBy, kinds,
39
+ /** What plugins attached to an element, when any did. */
40
+ extraFor) {
41
+ const owners = new Map();
42
+ const writers = new Map();
43
+ const rendered = new Map();
44
+ for (const node of graph.values()) {
45
+ if (kinds.has(node.kind)) {
46
+ const found = roots(node.id);
47
+ rendered.set(node.id, found);
48
+ for (const element of found)
49
+ if (!owners.has(element))
50
+ owners.set(element, node.id);
51
+ continue;
52
+ }
53
+ for (const element of writtenBy(node.id)) {
54
+ const held = writers.get(element);
55
+ if (held)
56
+ held.push(node.id);
57
+ else
58
+ writers.set(element, [node.id]);
59
+ }
60
+ }
61
+ const { claimed, containers } = claimOrphans(graph, rendered, writtenBy, kinds, owners);
62
+ const claims = new Map();
63
+ for (const [element, id] of claimed) {
64
+ const held = claims.get(id);
65
+ if (held)
66
+ held.push(element);
67
+ else
68
+ claims.set(id, [element]);
69
+ }
70
+ const landing = landings(graph, rendered, writtenBy, kinds, claimed, containers);
71
+ const out = new Map();
72
+ for (const node of graph.values()) {
73
+ if (!kinds.has(node.kind))
74
+ continue;
75
+ const budget = { left: DOM_BUDGET };
76
+ const walk = (element) => {
77
+ const owner = owners.get(element) ?? claimed.get(element);
78
+ // Another tag starts here, so stop. Its DOM goes under its own row.
79
+ const where = locationOf(element);
80
+ if (owner !== undefined && owner !== node.id) {
81
+ return { label: describeElement(element), children: [], owner, element, ...(where ? { at: where } : {}) };
82
+ }
83
+ // The element the application was mounted into. It goes above the tag rather than
84
+ // inside it, and what it holds is reached through the tags themselves, so the walk
85
+ // stops rather than describing the whole application a second time.
86
+ if (containers.has(element)) {
87
+ return { label: describeElement(element), children: [], container: true, element, ...(where ? { at: where } : {}) };
88
+ }
89
+ const children = [];
90
+ // Read once: `children` is live, so indexing it in the condition re-resolves the
91
+ // collection on every step and a parent with a thousand of them goes quadratic.
92
+ const kids = element.children;
93
+ for (let i = 0, n = kids.length; i < n && budget.left > 0; i++) {
94
+ budget.left -= 1;
95
+ children.push(walk(kids[i]));
96
+ }
97
+ const writes = writers.get(element);
98
+ const extra = extraFor?.(element);
99
+ // Only tags nested inside this one. A tag further out writes through this element on
100
+ // its way down, and putting it here would nest it under its own child.
101
+ const inside = landing.get(element)?.filter((id) => within(graph, id, node.id));
102
+ return {
103
+ label: describeElement(element),
104
+ children,
105
+ element,
106
+ ...(where ? { at: where } : {}),
107
+ ...(writes?.length ? { writes } : {}),
108
+ ...(inside?.length ? { inside } : {}),
109
+ ...(extra ? { extra } : {}),
110
+ };
111
+ };
112
+ out.set(node.id, [...(rendered.get(node.id) ?? []), ...(claims.get(node.id) ?? [])].map(walk));
113
+ }
114
+ return out;
115
+ }
116
+ /** Whether `id` sits under `ancestor` in the component nesting. */
117
+ function within(graph, id, ancestor) {
118
+ const seen = new Set();
119
+ for (let at = graph.get(id)?.createdIn; at !== undefined && !seen.has(at); at = graph.get(at)?.createdIn) {
120
+ if (at === ancestor)
121
+ return true;
122
+ seen.add(at);
123
+ }
124
+ return false;
125
+ }
126
+ /**
127
+ * Where a tag that rendered nothing of its own goes: the shallowest element it writes into.
128
+ * A tag writes to its own insertion point and, through whatever it renders, to everything
129
+ * below that, so the shallowest is the one it is responsible for.
130
+ *
131
+ * Where several land on the same element only the outermost is kept, because the rest come
132
+ * with it as its children.
133
+ */
134
+ function landings(graph, rendered, writtenBy, kinds, claimed, containers) {
135
+ const claimers = new Set(claimed.values());
136
+ const landing = new Map();
137
+ for (const node of graph.values()) {
138
+ if (!kinds.has(node.kind) || (rendered.get(node.id) ?? []).length)
139
+ continue;
140
+ if (claimers.has(node.id))
141
+ continue;
142
+ let shallowest;
143
+ let best = Infinity;
144
+ for (const element of writtenBy(node.id)) {
145
+ // The mount container holds the whole application; landing a tag in it would put that
146
+ // tag beside the root instead of under it.
147
+ if (containers.has(element))
148
+ continue;
149
+ const depth = depthInDocument(element);
150
+ if (depth < best) {
151
+ best = depth;
152
+ shallowest = element;
153
+ }
154
+ }
155
+ if (!shallowest)
156
+ continue;
157
+ const held = landing.get(shallowest);
158
+ if (held)
159
+ held.push(node.id);
160
+ else
161
+ landing.set(shallowest, [node.id]);
162
+ }
163
+ for (const [element, ids] of landing) {
164
+ landing.set(element, ids.filter((id) => !ids.some((other) => other !== id && within(graph, id, other))));
165
+ }
166
+ return landing;
167
+ }
168
+ /** How deep a tag sits in the component nesting, following what created it. */
169
+ export function tagDepths(graph, kinds) {
170
+ const depth = new Map();
171
+ const of = (id, seen) => {
172
+ const held = depth.get(id);
173
+ if (held !== undefined)
174
+ return held;
175
+ if (seen.has(id))
176
+ return 0;
177
+ seen.add(id);
178
+ const parent = graph.get(id)?.createdIn;
179
+ const value = parent === undefined ? 0 : of(parent, seen) + 1;
180
+ depth.set(id, value);
181
+ return value;
182
+ };
183
+ for (const node of graph.values())
184
+ if (kinds.has(node.kind))
185
+ of(node.id, new Set());
186
+ return depth;
187
+ }
188
+ function depthInDocument(element) {
189
+ let steps = 0;
190
+ for (let at = element.parentElement; at; at = at.parentElement)
191
+ steps++;
192
+ return steps;
193
+ }
194
+ /**
195
+ * Where to put a tag that returned no element of its own, one whose body is another
196
+ * component, or a boundary like Suspense. What it writes into is the only evidence of where
197
+ * its content went.
198
+ *
199
+ * Two rules keep this from doing damage. Only elements with no owned ancestor are taken: one
200
+ * below an owned element is already inside that tag's tree, and claiming it there would cut
201
+ * the tree in half at an arbitrary point. And where several tags write to the same place, the
202
+ * innermost wins. Every tag on the path from the root writes through to the leaves, so the
203
+ * outermost is always a match and never the interesting one.
204
+ */
205
+ function claimOrphans(graph, rendered, writtenBy, kinds, owners) {
206
+ const depth = tagDepths(graph, kinds);
207
+ // An element holding something a tag rendered is a wrapper the application was put into,
208
+ // not content a tag produced. The outermost tag writing there is the one it belongs to;
209
+ // for anything else it is the innermost.
210
+ const wraps = (element) => {
211
+ for (const owned of owners.keys())
212
+ if (element !== owned && element.contains(owned))
213
+ return true;
214
+ return false;
215
+ };
216
+ const writing = new Map();
217
+ for (const node of graph.values()) {
218
+ if (!kinds.has(node.kind) || (rendered.get(node.id) ?? []).length)
219
+ continue;
220
+ for (const element of writtenBy(node.id)) {
221
+ if (owners.has(element))
222
+ continue;
223
+ const held = writing.get(element);
224
+ if (held)
225
+ held.push(node.id);
226
+ else
227
+ writing.set(element, [node.id]);
228
+ }
229
+ }
230
+ const claimed = new Map();
231
+ const containers = new Set();
232
+ const covered = (element) => {
233
+ for (let at = element.parentElement; at; at = at.parentElement) {
234
+ if (owners.has(at) || claimed.has(at))
235
+ return true;
236
+ }
237
+ return false;
238
+ };
239
+ // Shallowest first, so each one is only tested against ancestors already decided.
240
+ const order = [...writing.keys()].sort((a, b) => depthInDocument(a) - depthInDocument(b));
241
+ for (const element of order) {
242
+ if (covered(element))
243
+ continue;
244
+ const ids = writing.get(element);
245
+ const container = wraps(element);
246
+ const pick = ids.reduce((best, id) => {
247
+ const a = depth.get(id) ?? 0;
248
+ const b = depth.get(best) ?? 0;
249
+ return container ? (a < b ? id : best) : a > b ? id : best;
250
+ });
251
+ claimed.set(element, pick);
252
+ if (container)
253
+ containers.add(element);
254
+ }
255
+ return { claimed, containers };
256
+ }
257
+ /**
258
+ * Drop the Elements so the result can be serialised.
259
+ *
260
+ * Everything else is copied as-is rather than field by field. The copy that describes and the
261
+ * copy that strips are built separately, since an extension bundles its own, so a list of fields
262
+ * here goes stale against a description made elsewhere, and the field just disappears.
263
+ */
264
+ export function withoutElements(nodes) {
265
+ return nodes.map(({ element, children, ...rest }) => ({
266
+ ...rest,
267
+ children: withoutElements(children),
268
+ }));
269
+ }
package/dist/dom.mjs ADDED
@@ -0,0 +1,183 @@
1
+ // src/dom.ts
2
+ var LOC_TAG = "__fx_loc";
3
+ function locationOf(element) {
4
+ return element[LOC_TAG];
5
+ }
6
+ var DOM_BUDGET = 200;
7
+ function describeElement(element) {
8
+ let out = element.tagName.toLowerCase();
9
+ if (element.id) out += `#${element.id}`;
10
+ const classes = element.classList;
11
+ if (classes.length > 0) {
12
+ out += `.${classes[0]}`;
13
+ if (classes.length > 1) out += `.${classes[1]}`;
14
+ }
15
+ return out;
16
+ }
17
+ function describeAll(graph, roots, writtenBy, kinds, extraFor) {
18
+ const owners = /* @__PURE__ */ new Map();
19
+ const writers = /* @__PURE__ */ new Map();
20
+ const rendered = /* @__PURE__ */ new Map();
21
+ for (const node of graph.values()) {
22
+ if (kinds.has(node.kind)) {
23
+ const found = roots(node.id);
24
+ rendered.set(node.id, found);
25
+ for (const element of found) if (!owners.has(element)) owners.set(element, node.id);
26
+ continue;
27
+ }
28
+ for (const element of writtenBy(node.id)) {
29
+ const held = writers.get(element);
30
+ if (held) held.push(node.id);
31
+ else writers.set(element, [node.id]);
32
+ }
33
+ }
34
+ const { claimed, containers } = claimOrphans(graph, rendered, writtenBy, kinds, owners);
35
+ const claims = /* @__PURE__ */ new Map();
36
+ for (const [element, id] of claimed) {
37
+ const held = claims.get(id);
38
+ if (held) held.push(element);
39
+ else claims.set(id, [element]);
40
+ }
41
+ const landing = landings(graph, rendered, writtenBy, kinds, claimed, containers);
42
+ const out = /* @__PURE__ */ new Map();
43
+ for (const node of graph.values()) {
44
+ if (!kinds.has(node.kind)) continue;
45
+ const budget = { left: DOM_BUDGET };
46
+ const walk = (element) => {
47
+ const owner = owners.get(element) ?? claimed.get(element);
48
+ const where = locationOf(element);
49
+ if (owner !== void 0 && owner !== node.id) {
50
+ return { label: describeElement(element), children: [], owner, element, ...where ? { at: where } : {} };
51
+ }
52
+ if (containers.has(element)) {
53
+ return { label: describeElement(element), children: [], container: true, element, ...where ? { at: where } : {} };
54
+ }
55
+ const children = [];
56
+ const kids = element.children;
57
+ for (let i = 0, n = kids.length; i < n && budget.left > 0; i++) {
58
+ budget.left -= 1;
59
+ children.push(walk(kids[i]));
60
+ }
61
+ const writes = writers.get(element);
62
+ const extra = extraFor?.(element);
63
+ const inside = landing.get(element)?.filter((id) => within(graph, id, node.id));
64
+ return {
65
+ label: describeElement(element),
66
+ children,
67
+ element,
68
+ ...where ? { at: where } : {},
69
+ ...writes?.length ? { writes } : {},
70
+ ...inside?.length ? { inside } : {},
71
+ ...extra ? { extra } : {}
72
+ };
73
+ };
74
+ out.set(node.id, [...rendered.get(node.id) ?? [], ...claims.get(node.id) ?? []].map(walk));
75
+ }
76
+ return out;
77
+ }
78
+ function within(graph, id, ancestor) {
79
+ const seen = /* @__PURE__ */ new Set();
80
+ for (let at = graph.get(id)?.createdIn; at !== void 0 && !seen.has(at); at = graph.get(at)?.createdIn) {
81
+ if (at === ancestor) return true;
82
+ seen.add(at);
83
+ }
84
+ return false;
85
+ }
86
+ function landings(graph, rendered, writtenBy, kinds, claimed, containers) {
87
+ const claimers = new Set(claimed.values());
88
+ const landing = /* @__PURE__ */ new Map();
89
+ for (const node of graph.values()) {
90
+ if (!kinds.has(node.kind) || (rendered.get(node.id) ?? []).length) continue;
91
+ if (claimers.has(node.id)) continue;
92
+ let shallowest;
93
+ let best = Infinity;
94
+ for (const element of writtenBy(node.id)) {
95
+ if (containers.has(element)) continue;
96
+ const depth = depthInDocument(element);
97
+ if (depth < best) {
98
+ best = depth;
99
+ shallowest = element;
100
+ }
101
+ }
102
+ if (!shallowest) continue;
103
+ const held = landing.get(shallowest);
104
+ if (held) held.push(node.id);
105
+ else landing.set(shallowest, [node.id]);
106
+ }
107
+ for (const [element, ids] of landing) {
108
+ landing.set(element, ids.filter((id) => !ids.some((other) => other !== id && within(graph, id, other))));
109
+ }
110
+ return landing;
111
+ }
112
+ function tagDepths(graph, kinds) {
113
+ const depth = /* @__PURE__ */ new Map();
114
+ const of = (id, seen) => {
115
+ const held = depth.get(id);
116
+ if (held !== void 0) return held;
117
+ if (seen.has(id)) return 0;
118
+ seen.add(id);
119
+ const parent = graph.get(id)?.createdIn;
120
+ const value = parent === void 0 ? 0 : of(parent, seen) + 1;
121
+ depth.set(id, value);
122
+ return value;
123
+ };
124
+ for (const node of graph.values()) if (kinds.has(node.kind)) of(node.id, /* @__PURE__ */ new Set());
125
+ return depth;
126
+ }
127
+ function depthInDocument(element) {
128
+ let steps = 0;
129
+ for (let at = element.parentElement; at; at = at.parentElement) steps++;
130
+ return steps;
131
+ }
132
+ function claimOrphans(graph, rendered, writtenBy, kinds, owners) {
133
+ const depth = tagDepths(graph, kinds);
134
+ const wraps = (element) => {
135
+ for (const owned of owners.keys()) if (element !== owned && element.contains(owned)) return true;
136
+ return false;
137
+ };
138
+ const writing = /* @__PURE__ */ new Map();
139
+ for (const node of graph.values()) {
140
+ if (!kinds.has(node.kind) || (rendered.get(node.id) ?? []).length) continue;
141
+ for (const element of writtenBy(node.id)) {
142
+ if (owners.has(element)) continue;
143
+ const held = writing.get(element);
144
+ if (held) held.push(node.id);
145
+ else writing.set(element, [node.id]);
146
+ }
147
+ }
148
+ const claimed = /* @__PURE__ */ new Map();
149
+ const containers = /* @__PURE__ */ new Set();
150
+ const covered = (element) => {
151
+ for (let at = element.parentElement; at; at = at.parentElement) {
152
+ if (owners.has(at) || claimed.has(at)) return true;
153
+ }
154
+ return false;
155
+ };
156
+ const order = [...writing.keys()].sort((a, b) => depthInDocument(a) - depthInDocument(b));
157
+ for (const element of order) {
158
+ if (covered(element)) continue;
159
+ const ids = writing.get(element);
160
+ const container = wraps(element);
161
+ const pick = ids.reduce((best, id) => {
162
+ const a = depth.get(id) ?? 0;
163
+ const b = depth.get(best) ?? 0;
164
+ return container ? a < b ? id : best : a > b ? id : best;
165
+ });
166
+ claimed.set(element, pick);
167
+ if (container) containers.add(element);
168
+ }
169
+ return { claimed, containers };
170
+ }
171
+ function withoutElements(nodes) {
172
+ return nodes.map(({ element, children, ...rest }) => ({
173
+ ...rest,
174
+ children: withoutElements(children)
175
+ }));
176
+ }
177
+ export {
178
+ DOM_BUDGET,
179
+ describeAll,
180
+ describeElement,
181
+ tagDepths,
182
+ withoutElements
183
+ };
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/export.ts
21
+ var export_exports = {};
22
+ __export(export_exports, {
23
+ exportGraph: () => exportGraph,
24
+ graphToJson: () => graphToJson
25
+ });
26
+ module.exports = __toCommonJS(export_exports);
27
+
28
+ // src/instrument.ts
29
+ var import_signal = require("@fluixi/reactive/signal");
30
+ var import_store = require("@fluixi/reactive/store");
31
+
32
+ // src/source.ts
33
+ var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
34
+ var host = globalThis;
35
+ var shared = host[MARKS] ?? {
36
+ pending: null,
37
+ expiring: false,
38
+ components: /* @__PURE__ */ new Map()
39
+ };
40
+ host[MARKS] = shared;
41
+
42
+ // src/format.ts
43
+ var MAX_DEPTH = 3;
44
+ var MAX_ENTRIES = 8;
45
+ function domName(v) {
46
+ if (typeof v?.nodeType !== "number" || typeof v.nodeName !== "string") return null;
47
+ return v.tagName ? `<${v.tagName.toLowerCase()}>` : `#${v.nodeName.toLowerCase()}`;
48
+ }
49
+ function fnName(v) {
50
+ return v.name ? `ƒ ${v.name}()` : "ƒ";
51
+ }
52
+ function className(v) {
53
+ const name = v.constructor?.name;
54
+ return name && name !== "Object" ? `${name} ` : "";
55
+ }
56
+ function primitive(v) {
57
+ if (v === null) return "null";
58
+ switch (typeof v) {
59
+ case "undefined":
60
+ return "undefined";
61
+ case "string":
62
+ return JSON.stringify(v);
63
+ case "number":
64
+ case "boolean":
65
+ return String(v);
66
+ case "bigint":
67
+ return `${v}n`;
68
+ case "symbol":
69
+ return v.toString();
70
+ case "function":
71
+ return fnName(v);
72
+ default:
73
+ return null;
74
+ }
75
+ }
76
+ function walk(value, depth, seen) {
77
+ const simple = primitive(value);
78
+ if (simple !== null) return simple;
79
+ const object = value;
80
+ if (seen.has(object)) return "[circular]";
81
+ const dom = domName(object);
82
+ if (dom) return dom;
83
+ if (object instanceof Date) return Number.isNaN(object.getTime()) ? "Invalid Date" : object.toISOString();
84
+ if (object instanceof RegExp) return String(object);
85
+ if (object instanceof Error) return `${object.name}: ${object.message}`;
86
+ if (object instanceof Promise) return "Promise";
87
+ if (ArrayBuffer.isView(object)) {
88
+ return `${className(object).trim()}(${object.length ?? ""})`;
89
+ }
90
+ if (depth >= MAX_DEPTH) return Array.isArray(object) ? "[…]" : "{…}";
91
+ seen.add(object);
92
+ try {
93
+ if (Array.isArray(object)) {
94
+ const shown2 = object.slice(0, MAX_ENTRIES).map((item) => walk(item, depth + 1, seen));
95
+ if (object.length > MAX_ENTRIES) shown2.push("…");
96
+ return `[${shown2.join(", ")}]`;
97
+ }
98
+ if (object instanceof Map) {
99
+ const shown2 = [];
100
+ for (const [k, v] of object) {
101
+ if (shown2.length === MAX_ENTRIES) {
102
+ shown2.push("…");
103
+ break;
104
+ }
105
+ shown2.push(`${walk(k, depth + 1, seen)} => ${walk(v, depth + 1, seen)}`);
106
+ }
107
+ return `Map(${object.size}) {${shown2.join(", ")}}`;
108
+ }
109
+ if (object instanceof Set) {
110
+ const shown2 = [];
111
+ for (const item of object) {
112
+ if (shown2.length === MAX_ENTRIES) {
113
+ shown2.push("…");
114
+ break;
115
+ }
116
+ shown2.push(walk(item, depth + 1, seen));
117
+ }
118
+ return `Set(${object.size}) {${shown2.join(", ")}}`;
119
+ }
120
+ const keys = Object.keys(object);
121
+ const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
122
+ let read;
123
+ try {
124
+ read = walk(object[key], depth + 1, seen);
125
+ } catch {
126
+ read = "[unreadable]";
127
+ }
128
+ return `${key}: ${read}`;
129
+ });
130
+ if (keys.length > MAX_ENTRIES) shown.push("…");
131
+ return `${className(object)}{${shown.join(", ")}}`;
132
+ } finally {
133
+ seen.delete(object);
134
+ }
135
+ }
136
+ function formatValue(value, limit = 240) {
137
+ let text;
138
+ try {
139
+ text = walk(value, 0, /* @__PURE__ */ new Set());
140
+ } catch {
141
+ text = "[unreadable]";
142
+ }
143
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
144
+ }
145
+
146
+ // src/instrument.ts
147
+ var CORE_STATE = { 0: "clean", 1: "check", 2: "dirty" };
148
+ function nodeVersion(n) {
149
+ return n.core && typeof n.core.version === "number" ? n.core.version : n.runs;
150
+ }
151
+ function nodeState(n) {
152
+ return n.core && typeof n.core.state === "number" ? CORE_STATE[n.core.state] : void 0;
153
+ }
154
+
155
+ // src/export.ts
156
+ var at = (source) => {
157
+ if (!source) return void 0;
158
+ const where = `${source.file ?? ""}:${source.line ?? ""}:${source.column ?? ""}`;
159
+ const out = source.compiled;
160
+ const same = out?.line === source.line && out?.column === source.column;
161
+ return out && !same ? `${where} (out ${out.line ?? ""}:${out.column ?? ""})` : where;
162
+ };
163
+ function naming(graph) {
164
+ const seen = /* @__PURE__ */ new Map();
165
+ for (const node of graph.values()) seen.set(node.label, (seen.get(node.label) ?? 0) + 1);
166
+ return (id) => {
167
+ const node = graph.get(id);
168
+ if (!node) return `#${id}`;
169
+ return (seen.get(node.label) ?? 0) > 1 ? `${node.label}#${node.id}` : node.label;
170
+ };
171
+ }
172
+ function exportGraph(graph, options = {}) {
173
+ const limit = options.limit ?? 400;
174
+ const name = naming(graph);
175
+ const nodes = [...graph.values()].map((node) => {
176
+ let value = node.detail ?? node.value;
177
+ if (node.read) {
178
+ try {
179
+ value = formatValue(node.read(), limit);
180
+ } catch {
181
+ }
182
+ }
183
+ const feeds = [...node.deps].map(name);
184
+ const wrote = [...node.writes].map(name);
185
+ const state = nodeState(node);
186
+ return {
187
+ id: node.id,
188
+ label: node.label,
189
+ kind: node.kind,
190
+ ...node.authored === false ? { authored: false } : {},
191
+ ...value ? { value } : {},
192
+ ...node.runs ? { runs: node.runs } : {},
193
+ // Only a node with a core has one; a static node would report a version of 0.
194
+ ...node.core?.version !== void 0 ? { version: nodeVersion(node) } : {},
195
+ ...state ? { state } : {},
196
+ ...feeds.length ? { reads: feeds } : {},
197
+ ...wrote.length ? { writes: wrote } : {},
198
+ ...node.createdIn !== void 0 ? { madeIn: name(node.createdIn) } : {},
199
+ ...at(node.source) ? { source: at(node.source) } : {},
200
+ ...at(node.declaredAt) ? { declaredAt: at(node.declaredAt) } : {},
201
+ ...at(node.usedAt) ? { usedAt: at(node.usedAt) } : {},
202
+ ...node.targets?.length ? {
203
+ updates: node.targets.map((target) => {
204
+ const what = target.name ? `${target.name} of ${target.element}` : target.element;
205
+ const where = at(target.source);
206
+ return where ? `${what} — ${where}` : what;
207
+ })
208
+ } : {},
209
+ ...node.setAt?.length ? { setAt: node.setAt.map((s) => at(s)).filter(Boolean) } : {}
210
+ };
211
+ });
212
+ return {
213
+ t: Date.now(),
214
+ from: options.fromSource ? "source" : "running application",
215
+ nodes,
216
+ ...options.events?.length ? { events: [...options.events] } : {}
217
+ };
218
+ }
219
+ function graphToJson(graph, options = {}) {
220
+ return JSON.stringify(exportGraph(graph, options), null, 2);
221
+ }