@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.
- package/README.md +80 -2
- package/dist/callsite.cjs +72 -0
- package/dist/callsite.d.ts +22 -0
- package/dist/callsite.d.ts.map +1 -0
- package/dist/callsite.js +82 -0
- package/dist/callsite.mjs +51 -0
- package/dist/change-view.cjs +134 -0
- package/dist/change-view.d.ts +10 -0
- package/dist/change-view.d.ts.map +1 -0
- package/dist/change-view.js +102 -0
- package/dist/change-view.mjs +111 -0
- package/dist/copy.cjs +63 -0
- package/dist/copy.d.ts +9 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +52 -0
- package/dist/copy.mjs +42 -0
- package/dist/describe.cjs +55 -0
- package/dist/describe.d.ts +3 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +47 -0
- package/dist/describe.mjs +34 -0
- package/dist/detail-panel.cjs +307 -0
- package/dist/detail-panel.d.ts +17 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +217 -0
- package/dist/detail-panel.mjs +284 -0
- package/dist/diff.cjs +225 -0
- package/dist/diff.d.ts +31 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +132 -0
- package/dist/diff.mjs +202 -0
- package/dist/dom.cjs +204 -0
- package/dist/dom.d.ts +81 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +269 -0
- package/dist/dom.mjs +183 -0
- package/dist/export.cjs +221 -0
- package/dist/export.d.ts +55 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +90 -0
- package/dist/export.mjs +209 -0
- package/dist/float.cjs +232 -0
- package/dist/float.d.ts +54 -0
- package/dist/float.d.ts.map +1 -0
- package/dist/float.js +256 -0
- package/dist/float.mjs +211 -0
- package/dist/format.cjs +175 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +188 -0
- package/dist/format.mjs +154 -0
- package/dist/graph-view.cjs +893 -0
- package/dist/graph-view.d.ts +79 -2
- package/dist/graph-view.d.ts.map +1 -1
- package/dist/graph-view.js +866 -50
- package/dist/graph-view.mjs +870 -0
- package/dist/highlight.cjs +140 -0
- package/dist/highlight.d.ts +56 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +154 -0
- package/dist/highlight.mjs +119 -0
- package/dist/history.cjs +95 -0
- package/dist/history.d.ts +59 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +85 -0
- package/dist/history.mjs +74 -0
- package/dist/hook.cjs +1562 -0
- package/dist/hook.d.ts +60 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +142 -0
- package/dist/hook.mjs +1553 -0
- package/dist/index.cjs +4552 -0
- package/dist/index.d.ts +44 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.mjs +4544 -0
- package/dist/inspector.cjs +688 -0
- package/dist/inspector.d.ts +60 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/inspector.js +415 -0
- package/dist/inspector.mjs +676 -0
- package/dist/instrument.cjs +497 -0
- package/dist/instrument.d.ts +147 -5
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +164 -44
- package/dist/instrument.mjs +487 -0
- package/dist/kind-filter.cjs +172 -0
- package/dist/kind-filter.d.ts +39 -0
- package/dist/kind-filter.d.ts.map +1 -0
- package/dist/kind-filter.js +151 -0
- package/dist/kind-filter.mjs +151 -0
- package/dist/menu.cjs +141 -0
- package/dist/menu.d.ts +37 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +125 -0
- package/dist/menu.mjs +120 -0
- package/dist/observe.cjs +1352 -0
- package/dist/observe.d.ts +80 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +893 -0
- package/dist/observe.mjs +1345 -0
- package/dist/palette.cjs +52 -0
- package/dist/palette.d.ts +11 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +27 -0
- package/dist/palette.mjs +31 -0
- package/dist/path.cjs +45 -0
- package/dist/path.d.ts +19 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +49 -0
- package/dist/path.mjs +24 -0
- package/dist/plugin.cjs +87 -0
- package/dist/plugin.d.ts +121 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +74 -0
- package/dist/plugin.mjs +66 -0
- package/dist/plugins/context.cjs +98 -0
- package/dist/plugins/context.d.ts +10 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +80 -0
- package/dist/plugins/context.mjs +75 -0
- package/dist/plugins/directives.cjs +98 -0
- package/dist/plugins/directives.d.ts +25 -0
- package/dist/plugins/directives.d.ts.map +1 -0
- package/dist/plugins/directives.js +78 -0
- package/dist/plugins/directives.mjs +75 -0
- package/dist/plugins/index.cjs +162 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +9 -0
- package/dist/plugins/index.mjs +140 -0
- package/dist/source.cjs +111 -0
- package/dist/source.d.ts +72 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +153 -0
- package/dist/source.mjs +90 -0
- package/dist/timeline.cjs +350 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +271 -0
- package/dist/timeline.mjs +327 -0
- package/dist/tree.cjs +574 -0
- package/dist/tree.d.ts +128 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +645 -0
- package/dist/tree.mjs +551 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/value-pane.cjs +223 -0
- package/dist/value-pane.d.ts +10 -0
- package/dist/value-pane.d.ts.map +1 -0
- package/dist/value-pane.js +61 -0
- package/dist/value-pane.mjs +200 -0
- package/dist/wire.cjs +109 -0
- package/dist/wire.d.ts +100 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +93 -0
- package/dist/wire.mjs +89 -0
- package/package.json +17 -5
package/dist/instrument.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../src/instrument.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../src/instrument.ts"],"names":[],"mappings":"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"}
|
package/dist/instrument.js
CHANGED
|
@@ -3,9 +3,25 @@
|
|
|
3
3
|
// into a graph. A read is a subscription, so edges come from real reads; writes (setX) made inside
|
|
4
4
|
// a consumer become write edges. Nodes carry the live core node so the inspector reads the real
|
|
5
5
|
// version + CLEAN/CHECK/DIRTY state, and onCleanup removes a node when its owner disposes.
|
|
6
|
-
import { createSignal, createMemo, createEffect, createResource, createRoot, untrack, onCleanup, Signal, } from '@fluixi/reactive/signal';
|
|
6
|
+
import { createSignal, createMemo, createEffect, createResource, createRoot, untrack, onCleanup, getOwner, runWithOwner, Signal, } from '@fluixi/reactive/signal';
|
|
7
7
|
import { createStore } from '@fluixi/reactive/store';
|
|
8
|
+
import { componentSource, installSourceMarker, takeReactiveSource } from './source.js';
|
|
9
|
+
import { formatValue, shorten } from './format.js';
|
|
8
10
|
const $NODE = Symbol.for('signal-node');
|
|
11
|
+
/**
|
|
12
|
+
* The names the compiler supplies without an import, and what each one is. A control-flow
|
|
13
|
+
* tag stamps its name the same way an author's component does, so without this `Match` and
|
|
14
|
+
* `Switch` are drawn as components the author wrote.
|
|
15
|
+
*
|
|
16
|
+
* Mirrors `resolve/builtins.ts` in @fluixi/compiler. Not imported from there: this package
|
|
17
|
+
* runs beside the application, and the compiler is not on that side of the wall.
|
|
18
|
+
*/
|
|
19
|
+
export const KIND_OF_BUILTIN = {
|
|
20
|
+
Show: 'control', For: 'control', Index: 'control', Switch: 'control', Match: 'control',
|
|
21
|
+
Portal: 'control', Dynamic: 'control', ErrorBoundary: 'control',
|
|
22
|
+
Suspense: 'control', SuspenseList: 'control', Await: 'control',
|
|
23
|
+
Router: 'router', Outlet: 'router', Redirect: 'router', Link: 'router',
|
|
24
|
+
};
|
|
9
25
|
const CORE_STATE = { 0: 'clean', 1: 'check', 2: 'dirty' };
|
|
10
26
|
/** The real version (signals/memos) or recompute count fallback. */
|
|
11
27
|
export function nodeVersion(n) {
|
|
@@ -15,28 +31,51 @@ export function nodeVersion(n) {
|
|
|
15
31
|
export function nodeState(n) {
|
|
16
32
|
return n.core && typeof n.core.state === 'number' ? CORE_STATE[n.core.state] : undefined;
|
|
17
33
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return JSON.stringify(v);
|
|
22
|
-
if (typeof v === 'function')
|
|
23
|
-
return 'ƒ';
|
|
24
|
-
if (typeof v === 'bigint')
|
|
25
|
-
return `${v}n`;
|
|
26
|
-
if (typeof v === 'object' && v)
|
|
27
|
-
return JSON.stringify(v);
|
|
28
|
-
return String(v);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return '?';
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
const short = (s, n = 18) => (s.length > n ? s.slice(0, n - 1) + '…' : s);
|
|
34
|
+
// Kept as the names the rest of this package already uses.
|
|
35
|
+
export const fmt = (v) => formatValue(v);
|
|
36
|
+
export const short = (s, n = 18) => shorten(s, n);
|
|
35
37
|
export function createReactor() {
|
|
38
|
+
installSourceMarker();
|
|
36
39
|
const graph = new Map();
|
|
40
|
+
/** Run counts as of the last sample, so a node with no readable value can still pulse. */
|
|
41
|
+
const runsAtLastSample = new Map();
|
|
42
|
+
/** Nodes still carrying a positional label, so a better one can replace it later. */
|
|
43
|
+
const unnamed = new Set();
|
|
37
44
|
const consumerStack = [];
|
|
38
45
|
let seq = 0;
|
|
39
46
|
let dispose = () => { };
|
|
47
|
+
// The root's owner, kept so a node created after `run` returned still has somewhere to
|
|
48
|
+
// hang its cleanup. A project's modules load asynchronously, so most registration lands
|
|
49
|
+
// well after the synchronous setup. With no owner, `onCleanup` runs immediately and the
|
|
50
|
+
// node disappears the moment it is made, which is why the graph came up empty.
|
|
51
|
+
let rootOwner = null;
|
|
52
|
+
/**
|
|
53
|
+
* Whether this node is the wrapper that made the stamped value, rather than one further
|
|
54
|
+
* down that only passes it along.
|
|
55
|
+
*
|
|
56
|
+
* `$name` is set on what a component returns, so it travels with the value: every memo
|
|
57
|
+
* holding it looks like the component. The one that made it is the one none of its
|
|
58
|
+
* dependencies already has. Otherwise a component under `Suspense` draws twice.
|
|
59
|
+
*/
|
|
60
|
+
const claims = (node, value) => {
|
|
61
|
+
for (const dep of node.deps) {
|
|
62
|
+
const other = graph.get(dep);
|
|
63
|
+
if (other?.read && other.read() === value)
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
};
|
|
68
|
+
/** Remove a node when whatever created it goes away, or when the reactor is torn down. */
|
|
69
|
+
const forget = (id) => {
|
|
70
|
+
const owner = getOwner() ?? rootOwner;
|
|
71
|
+
if (owner) {
|
|
72
|
+
runWithOwner(owner, () => onCleanup(() => {
|
|
73
|
+
graph.delete(id);
|
|
74
|
+
runsAtLastSample.delete(id);
|
|
75
|
+
unnamed.delete(id);
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
40
79
|
const recordRead = (sourceId) => {
|
|
41
80
|
const c = consumerStack[consumerStack.length - 1];
|
|
42
81
|
if (c != null)
|
|
@@ -47,24 +86,34 @@ export function createReactor() {
|
|
|
47
86
|
if (c != null && c !== targetId)
|
|
48
87
|
graph.get(c)?.writes.add(targetId);
|
|
49
88
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
89
|
+
// Every tracked primitive comes through here, so it is the one place a mark is taken. An
|
|
90
|
+
// explicit `{ name }` wins; otherwise the node borrows the variable name the compiler
|
|
91
|
+
// read, which is why `const count = signal(0)` shows as `count` rather than `s0`.
|
|
92
|
+
const base = (id, named, kind, fallback) => {
|
|
93
|
+
const mark = takeReactiveSource();
|
|
94
|
+
if (!named && !mark?.name)
|
|
95
|
+
unnamed.add(id);
|
|
96
|
+
return {
|
|
97
|
+
id,
|
|
98
|
+
label: named ?? mark?.name ?? fallback,
|
|
99
|
+
kind,
|
|
100
|
+
deps: new Set(),
|
|
101
|
+
writes: new Set(),
|
|
102
|
+
runs: 0,
|
|
103
|
+
lastPulse: 0,
|
|
104
|
+
...(mark?.location ? { source: mark.location } : {}),
|
|
105
|
+
};
|
|
106
|
+
};
|
|
59
107
|
const trackedCreateSignal = (value, options) => {
|
|
60
108
|
const id = seq++;
|
|
61
109
|
const [get, set] = createSignal(value, options);
|
|
62
|
-
const node = base(id, options?.name
|
|
110
|
+
const node = base(id, options?.name, 'state', `s${id}`);
|
|
63
111
|
node.read = () => untrack(get);
|
|
64
|
-
node.
|
|
112
|
+
node.detail = formatValue(value);
|
|
113
|
+
node.value = shorten(node.detail);
|
|
65
114
|
node.core = get[$NODE] ?? null;
|
|
66
115
|
graph.set(id, node);
|
|
67
|
-
|
|
116
|
+
forget(id);
|
|
68
117
|
const read = () => {
|
|
69
118
|
recordRead(id);
|
|
70
119
|
return get();
|
|
@@ -75,11 +124,11 @@ export function createReactor() {
|
|
|
75
124
|
};
|
|
76
125
|
return [read, write];
|
|
77
126
|
};
|
|
78
|
-
const trackedCreateMemo = (fn, options) => {
|
|
127
|
+
const trackedCreateMemo = (fn, value, options) => {
|
|
79
128
|
const id = seq++;
|
|
80
|
-
const node = base(id, options?.name
|
|
129
|
+
const node = base(id, options?.name, 'memo', `m${id}`);
|
|
81
130
|
graph.set(id, node);
|
|
82
|
-
|
|
131
|
+
forget(id);
|
|
83
132
|
const m = createMemo(() => {
|
|
84
133
|
node.core ??= Signal.subtle.currentComputed(); // capture the live Computed
|
|
85
134
|
node.deps.clear();
|
|
@@ -92,7 +141,7 @@ export function createReactor() {
|
|
|
92
141
|
finally {
|
|
93
142
|
consumerStack.pop();
|
|
94
143
|
}
|
|
95
|
-
});
|
|
144
|
+
}, value, options);
|
|
96
145
|
node.read = () => untrack(m);
|
|
97
146
|
return () => {
|
|
98
147
|
recordRead(id);
|
|
@@ -101,9 +150,9 @@ export function createReactor() {
|
|
|
101
150
|
};
|
|
102
151
|
const trackedCreateEffect = (fn, options) => {
|
|
103
152
|
const id = seq++;
|
|
104
|
-
const node = base(id, options?.name
|
|
153
|
+
const node = base(id, options?.name, 'effect', `e${id}`);
|
|
105
154
|
graph.set(id, node);
|
|
106
|
-
|
|
155
|
+
forget(id);
|
|
107
156
|
createEffect(() => {
|
|
108
157
|
node.core ??= Signal.subtle.currentComputed();
|
|
109
158
|
node.deps.clear();
|
|
@@ -122,7 +171,7 @@ export function createReactor() {
|
|
|
122
171
|
const trackedCreateStore = (initial, options) => {
|
|
123
172
|
const id = seq++;
|
|
124
173
|
const [proxy, setter] = createStore(initial, { immutable: true, ...options });
|
|
125
|
-
const node = base(id, options?.name
|
|
174
|
+
const node = base(id, options?.name, 'store', `store${id}`);
|
|
126
175
|
node.read = () => {
|
|
127
176
|
try {
|
|
128
177
|
return untrack(() => JSON.stringify(proxy));
|
|
@@ -133,7 +182,7 @@ export function createReactor() {
|
|
|
133
182
|
};
|
|
134
183
|
node.value = '{…}';
|
|
135
184
|
graph.set(id, node);
|
|
136
|
-
|
|
185
|
+
forget(id);
|
|
137
186
|
const recording = new Proxy(proxy, {
|
|
138
187
|
get(t, p, r) {
|
|
139
188
|
recordRead(id);
|
|
@@ -150,7 +199,7 @@ export function createReactor() {
|
|
|
150
199
|
const id = seq++;
|
|
151
200
|
const last = args[args.length - 1];
|
|
152
201
|
const name = last && typeof last === 'object' && !Array.isArray(last) && typeof last !== 'function' ? last.name : undefined;
|
|
153
|
-
const node = base(id, name
|
|
202
|
+
const node = base(id, name, 'resource', `res${id}`);
|
|
154
203
|
const [data, actions] = createResource(...args);
|
|
155
204
|
node.read = () => {
|
|
156
205
|
try {
|
|
@@ -162,7 +211,7 @@ export function createReactor() {
|
|
|
162
211
|
};
|
|
163
212
|
node.value = '⏳ loading';
|
|
164
213
|
graph.set(id, node);
|
|
165
|
-
|
|
214
|
+
forget(id);
|
|
166
215
|
const accessor = (() => {
|
|
167
216
|
recordRead(id);
|
|
168
217
|
return data();
|
|
@@ -172,38 +221,109 @@ export function createReactor() {
|
|
|
172
221
|
}
|
|
173
222
|
return [accessor, actions];
|
|
174
223
|
};
|
|
224
|
+
// The short API is the long one with a handle around it. `signal` is
|
|
225
|
+
// `Object.assign(createSignal(...), { set })`, `memo` and `effect` are the same function
|
|
226
|
+
// under another name. Deriving them keeps one definition of what tracking means, instead
|
|
227
|
+
// of a second copy of the node bookkeeping that drifts from the first.
|
|
228
|
+
const trackedSignal = (value, options) => {
|
|
229
|
+
const [read, write] = trackedCreateSignal(value, options);
|
|
230
|
+
Object.defineProperty(read, 'set', { value: write });
|
|
231
|
+
return read;
|
|
232
|
+
};
|
|
233
|
+
const trackedMemo = trackedCreateMemo;
|
|
234
|
+
const trackedEffect = trackedCreateEffect;
|
|
235
|
+
const trackedStore = (initial, options) => {
|
|
236
|
+
const [state, set] = trackedCreateStore(initial, options);
|
|
237
|
+
// A wrapper rather than assigning onto the state: the proxy is the tracking boundary,
|
|
238
|
+
// and writing a key through it would read as a state change.
|
|
239
|
+
return new Proxy(state, {
|
|
240
|
+
get: (target, key) => (key === 'set' ? set : target[key]),
|
|
241
|
+
has: (target, key) => key === 'set' || Reflect.has(target, key),
|
|
242
|
+
});
|
|
243
|
+
};
|
|
244
|
+
const trackedResource = (...args) => {
|
|
245
|
+
const [accessor, controls] = trackedCreateResource(...args);
|
|
246
|
+
return Object.assign(accessor, controls);
|
|
247
|
+
};
|
|
175
248
|
const api = {
|
|
176
249
|
createSignal: trackedCreateSignal,
|
|
177
250
|
createMemo: trackedCreateMemo,
|
|
178
251
|
createEffect: trackedCreateEffect,
|
|
179
252
|
createStore: trackedCreateStore,
|
|
180
253
|
createResource: trackedCreateResource,
|
|
254
|
+
signal: trackedSignal,
|
|
255
|
+
memo: trackedMemo,
|
|
256
|
+
store: trackedStore,
|
|
257
|
+
effect: trackedEffect,
|
|
258
|
+
resource: trackedResource
|
|
181
259
|
};
|
|
182
260
|
return {
|
|
183
261
|
graph,
|
|
184
262
|
run(setup) {
|
|
185
263
|
dispose();
|
|
186
264
|
graph.clear();
|
|
265
|
+
runsAtLastSample.clear();
|
|
266
|
+
unnamed.clear();
|
|
187
267
|
seq = 0;
|
|
188
268
|
consumerStack.length = 0;
|
|
189
269
|
createRoot((d) => {
|
|
190
270
|
dispose = d;
|
|
271
|
+
rootOwner = getOwner();
|
|
191
272
|
setup(api);
|
|
192
273
|
});
|
|
193
274
|
},
|
|
194
275
|
sample() {
|
|
195
276
|
const changed = [];
|
|
196
|
-
|
|
277
|
+
// Date.now rather than performance.now: the reactor may run in one realm and the view
|
|
278
|
+
// in another, which an iframe preview does, and each realm's performance
|
|
279
|
+
// clock has its own origin, so the age the view computed was nonsense and nothing
|
|
280
|
+
// ever pulsed.
|
|
281
|
+
const now = Date.now();
|
|
197
282
|
for (const node of graph.values()) {
|
|
198
|
-
|
|
283
|
+
// An effect has no value to read, so what marks it as having done something is the
|
|
284
|
+
// run count the wrapper keeps. Without this an effect never pulsed.
|
|
285
|
+
if (!node.read) {
|
|
286
|
+
const seen = runsAtLastSample.get(node.id);
|
|
287
|
+
if (seen !== undefined && node.runs > seen) {
|
|
288
|
+
node.lastPulse = now;
|
|
289
|
+
changed.push(node.id);
|
|
290
|
+
}
|
|
291
|
+
runsAtLastSample.set(node.id, node.runs);
|
|
199
292
|
continue;
|
|
200
|
-
|
|
201
|
-
|
|
293
|
+
}
|
|
294
|
+
const raw = node.read();
|
|
295
|
+
// The compiler wraps each component in a memo, and `createComponent` stamps the
|
|
296
|
+
// component's name on what it returns. A memo that has no name of its own is that
|
|
297
|
+
// wrapper, so it can say `Counter` rather than `m5`.
|
|
298
|
+
// The runtime stamps a component's name on what it returned, so a memo holding
|
|
299
|
+
// that is the wrapper the compiler put round a component. Not gated on the node
|
|
300
|
+
// being unnamed: the compiler marks the tag with the component's name too, which
|
|
301
|
+
// would leave the node named and never recognised.
|
|
302
|
+
const stamped = raw?.$name;
|
|
303
|
+
if (node.kind === 'memo' && typeof stamped === 'string' && stamped && claims(node, raw)) {
|
|
304
|
+
// Still a memo underneath. This only says so, so a renderer can draw it as what
|
|
305
|
+
// the author wrote rather than as the wrapper around it.
|
|
306
|
+
node.kind = KIND_OF_BUILTIN[stamped] ?? 'component';
|
|
307
|
+
// `source` stays what it is for every other node: where this one was created,
|
|
308
|
+
// which for a wrapper is where the tag was written. Where the component itself
|
|
309
|
+
// lives is a second fact, and it stands in for the first when nothing marked it.
|
|
310
|
+
node.declaredAt = componentSource(stamped);
|
|
311
|
+
node.source ??= node.declaredAt;
|
|
312
|
+
if (unnamed.has(node.id)) {
|
|
313
|
+
node.label = stamped;
|
|
314
|
+
unnamed.delete(node.id);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const detail = formatValue(raw);
|
|
318
|
+
const next = shorten(detail);
|
|
319
|
+
if (next !== node.value || detail !== node.detail) {
|
|
320
|
+
node.detail = detail;
|
|
202
321
|
node.value = next;
|
|
203
322
|
node.runs++;
|
|
204
323
|
node.lastPulse = now;
|
|
205
324
|
changed.push(node.id);
|
|
206
325
|
}
|
|
326
|
+
runsAtLastSample.set(node.id, node.runs);
|
|
207
327
|
}
|
|
208
328
|
return changed;
|
|
209
329
|
},
|