@fluixi/devtools 0.2.0-alpha.6 → 1.0.0-alpha.99
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/LICENSE +1 -1
- package/dist/callsite.cjs +8 -1
- package/dist/callsite.d.ts.map +1 -1
- package/dist/callsite.js +12 -1
- package/dist/callsite.mjs +8 -1
- package/dist/diff.cjs +2 -0
- package/dist/diff.mjs +2 -0
- package/dist/export.cjs +2 -0
- package/dist/export.mjs +2 -0
- package/dist/format.cjs +2 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +6 -1
- package/dist/format.mjs +2 -0
- package/dist/hook.cjs +46 -16
- package/dist/hook.mjs +47 -16
- package/dist/index.cjs +47 -17
- package/dist/index.mjs +48 -17
- package/dist/inspector.cjs +2 -0
- package/dist/inspector.mjs +2 -0
- package/dist/instrument.cjs +2 -0
- package/dist/instrument.mjs +2 -0
- package/dist/observe.cjs +47 -16
- package/dist/observe.d.ts +7 -0
- package/dist/observe.d.ts.map +1 -1
- package/dist/observe.js +58 -22
- package/dist/observe.mjs +48 -16
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/wire.cjs +1 -1
- package/dist/wire.mjs +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/devtools
|
|
1
|
+
/*! @fluixi/devtools v1.0.0-alpha.99 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
|
|
3
3
|
// src/instrument.ts
|
|
4
4
|
import {
|
|
@@ -191,6 +191,8 @@ function walk(value, depth, seen) {
|
|
|
191
191
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
192
192
|
let read;
|
|
193
193
|
try {
|
|
194
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
195
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
194
196
|
read = walk(object[key], depth + 1, seen);
|
|
195
197
|
} catch {
|
|
196
198
|
read = "[unreadable]";
|
|
@@ -542,6 +544,7 @@ function createReactor() {
|
|
|
542
544
|
|
|
543
545
|
// src/observe.ts
|
|
544
546
|
import {
|
|
547
|
+
createRoot as createRoot2,
|
|
545
548
|
observeReactiveNodes,
|
|
546
549
|
untrack as untrack2
|
|
547
550
|
} from "@fluixi/reactive/signal";
|
|
@@ -600,7 +603,14 @@ function callSite(stack, origin) {
|
|
|
600
603
|
return fallback2 ? { location: { ...fallback2, external: true }, external: true } : void 0;
|
|
601
604
|
}
|
|
602
605
|
function currentCallSite(origin) {
|
|
603
|
-
|
|
606
|
+
const errors = Error;
|
|
607
|
+
const limit = errors.stackTraceLimit;
|
|
608
|
+
errors.stackTraceLimit = 50;
|
|
609
|
+
try {
|
|
610
|
+
return callSite(new Error().stack, origin);
|
|
611
|
+
} finally {
|
|
612
|
+
errors.stackTraceLimit = limit;
|
|
613
|
+
}
|
|
604
614
|
}
|
|
605
615
|
|
|
606
616
|
// src/history.ts
|
|
@@ -1607,6 +1617,7 @@ var PREFIX = {
|
|
|
1607
1617
|
service: "svc"
|
|
1608
1618
|
};
|
|
1609
1619
|
function readProps(props) {
|
|
1620
|
+
if (readOnce.has(props)) return readOnce.get(props);
|
|
1610
1621
|
const at3 = propsLocations(props);
|
|
1611
1622
|
const out = [];
|
|
1612
1623
|
for (const name of Object.keys(props)) {
|
|
@@ -1617,13 +1628,25 @@ function readProps(props) {
|
|
|
1617
1628
|
...where ? { at: { line: where[0], column: where[1] } } : {}
|
|
1618
1629
|
};
|
|
1619
1630
|
try {
|
|
1620
|
-
report.value = formatValue(
|
|
1631
|
+
report.value = formatValue(
|
|
1632
|
+
createRoot2((dispose) => {
|
|
1633
|
+
try {
|
|
1634
|
+
return untrack2(() => props[name]);
|
|
1635
|
+
} finally {
|
|
1636
|
+
dispose();
|
|
1637
|
+
}
|
|
1638
|
+
}),
|
|
1639
|
+
200
|
|
1640
|
+
);
|
|
1621
1641
|
} catch {
|
|
1622
1642
|
}
|
|
1623
1643
|
out.push(report);
|
|
1624
1644
|
}
|
|
1625
|
-
|
|
1645
|
+
const reports = out.length ? out : void 0;
|
|
1646
|
+
readOnce.set(props, reports);
|
|
1647
|
+
return reports;
|
|
1626
1648
|
}
|
|
1649
|
+
var readOnce = /* @__PURE__ */ new WeakMap();
|
|
1627
1650
|
function observeGraph(options = {}) {
|
|
1628
1651
|
installSourceMarker();
|
|
1629
1652
|
const origin = options.origin ?? (typeof location === "object" ? location.origin : void 0);
|
|
@@ -1631,7 +1654,7 @@ function observeGraph(options = {}) {
|
|
|
1631
1654
|
const claims = (node, value) => {
|
|
1632
1655
|
for (const dep of node.deps) {
|
|
1633
1656
|
const other = graph.get(dep);
|
|
1634
|
-
if (other?.read && other
|
|
1657
|
+
if (other?.read && readRaw(other) === value) return false;
|
|
1635
1658
|
}
|
|
1636
1659
|
return true;
|
|
1637
1660
|
};
|
|
@@ -1649,6 +1672,7 @@ function observeGraph(options = {}) {
|
|
|
1649
1672
|
const scopeOfTarget = /* @__PURE__ */ new WeakMap();
|
|
1650
1673
|
const fieldsOf = /* @__PURE__ */ new WeakMap();
|
|
1651
1674
|
let described = null;
|
|
1675
|
+
let descendants = null;
|
|
1652
1676
|
const rendered = /* @__PURE__ */ new Map();
|
|
1653
1677
|
const elementsIn = (value) => {
|
|
1654
1678
|
if (value instanceof Element) return [value];
|
|
@@ -2010,6 +2034,7 @@ function observeGraph(options = {}) {
|
|
|
2010
2034
|
graph,
|
|
2011
2035
|
sample() {
|
|
2012
2036
|
described = null;
|
|
2037
|
+
descendants = null;
|
|
2013
2038
|
const changed = [];
|
|
2014
2039
|
const moved = (id) => {
|
|
2015
2040
|
changed.push(id);
|
|
@@ -2065,7 +2090,7 @@ function observeGraph(options = {}) {
|
|
|
2065
2090
|
runsAtLastSample.set(node.id, node.runs);
|
|
2066
2091
|
continue;
|
|
2067
2092
|
}
|
|
2068
|
-
const raw = node
|
|
2093
|
+
const raw = readRaw(node);
|
|
2069
2094
|
if (recording) raws.set(node.id, raw);
|
|
2070
2095
|
edges(node.id, node);
|
|
2071
2096
|
const stamped = raw?.$name;
|
|
@@ -2140,17 +2165,8 @@ function observeGraph(options = {}) {
|
|
|
2140
2165
|
if (live.length) return live;
|
|
2141
2166
|
collect(id);
|
|
2142
2167
|
if (!live.length) {
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
let at3 = node.createdIn;
|
|
2146
|
-
while (at3 !== void 0 && !seen.has(at3)) {
|
|
2147
|
-
if (at3 === id) return true;
|
|
2148
|
-
seen.add(at3);
|
|
2149
|
-
at3 = graph.get(at3)?.createdIn;
|
|
2150
|
-
}
|
|
2151
|
-
return false;
|
|
2152
|
-
};
|
|
2153
|
-
for (const node of graph.values()) if (inside(node)) collect(node.id);
|
|
2168
|
+
descendants ??= descendantsByCreator(graph);
|
|
2169
|
+
for (const below of descendants.get(id) ?? []) collect(below);
|
|
2154
2170
|
}
|
|
2155
2171
|
return live;
|
|
2156
2172
|
},
|
|
@@ -2263,6 +2279,21 @@ function observeGraph(options = {}) {
|
|
|
2263
2279
|
}
|
|
2264
2280
|
return api;
|
|
2265
2281
|
}
|
|
2282
|
+
function descendantsByCreator(graph) {
|
|
2283
|
+
const out = /* @__PURE__ */ new Map();
|
|
2284
|
+
for (const node of graph.values()) {
|
|
2285
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2286
|
+
let at3 = node.createdIn;
|
|
2287
|
+
while (at3 !== void 0 && !seen.has(at3)) {
|
|
2288
|
+
seen.add(at3);
|
|
2289
|
+
let list = out.get(at3);
|
|
2290
|
+
if (!list) out.set(at3, list = []);
|
|
2291
|
+
list.push(node.id);
|
|
2292
|
+
at3 = graph.get(at3)?.createdIn;
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
return out;
|
|
2296
|
+
}
|
|
2266
2297
|
|
|
2267
2298
|
// src/highlight.ts
|
|
2268
2299
|
var LAYER = "fx-highlight-layer";
|
package/dist/inspector.cjs
CHANGED
|
@@ -122,6 +122,8 @@ function walk(value, depth, seen) {
|
|
|
122
122
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
123
123
|
let read;
|
|
124
124
|
try {
|
|
125
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
126
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
125
127
|
read = walk(object[key], depth + 1, seen);
|
|
126
128
|
} catch {
|
|
127
129
|
read = "[unreadable]";
|
package/dist/inspector.mjs
CHANGED
|
@@ -106,6 +106,8 @@ function walk(value, depth, seen) {
|
|
|
106
106
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
107
107
|
let read;
|
|
108
108
|
try {
|
|
109
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
110
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
109
111
|
read = walk(object[key], depth + 1, seen);
|
|
110
112
|
} catch {
|
|
111
113
|
read = "[unreadable]";
|
package/dist/instrument.cjs
CHANGED
|
@@ -194,6 +194,8 @@ function walk(value, depth, seen) {
|
|
|
194
194
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
195
195
|
let read;
|
|
196
196
|
try {
|
|
197
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
198
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
197
199
|
read = walk(object[key], depth + 1, seen);
|
|
198
200
|
} catch {
|
|
199
201
|
read = "[unreadable]";
|
package/dist/instrument.mjs
CHANGED
|
@@ -176,6 +176,8 @@ function walk(value, depth, seen) {
|
|
|
176
176
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
177
177
|
let read;
|
|
178
178
|
try {
|
|
179
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
180
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
179
181
|
read = walk(object[key], depth + 1, seen);
|
|
180
182
|
} catch {
|
|
181
183
|
read = "[unreadable]";
|
package/dist/observe.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/observe.ts
|
|
21
21
|
var observe_exports = {};
|
|
22
22
|
__export(observe_exports, {
|
|
23
|
+
descendantsByCreator: () => descendantsByCreator,
|
|
23
24
|
observeGraph: () => observeGraph
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(observe_exports);
|
|
@@ -173,7 +174,14 @@ function callSite(stack, origin) {
|
|
|
173
174
|
return fallback ? { location: { ...fallback, external: true }, external: true } : void 0;
|
|
174
175
|
}
|
|
175
176
|
function currentCallSite(origin) {
|
|
176
|
-
|
|
177
|
+
const errors = Error;
|
|
178
|
+
const limit = errors.stackTraceLimit;
|
|
179
|
+
errors.stackTraceLimit = 50;
|
|
180
|
+
try {
|
|
181
|
+
return callSite(new Error().stack, origin);
|
|
182
|
+
} finally {
|
|
183
|
+
errors.stackTraceLimit = limit;
|
|
184
|
+
}
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
// src/instrument.ts
|
|
@@ -262,6 +270,8 @@ function walk(value, depth, seen) {
|
|
|
262
270
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
263
271
|
let read;
|
|
264
272
|
try {
|
|
273
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
274
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
265
275
|
read = walk(object[key], depth + 1, seen);
|
|
266
276
|
} catch {
|
|
267
277
|
read = "[unreadable]";
|
|
@@ -832,6 +842,7 @@ var PREFIX = {
|
|
|
832
842
|
service: "svc"
|
|
833
843
|
};
|
|
834
844
|
function readProps(props) {
|
|
845
|
+
if (readOnce.has(props)) return readOnce.get(props);
|
|
835
846
|
const at = propsLocations(props);
|
|
836
847
|
const out = [];
|
|
837
848
|
for (const name of Object.keys(props)) {
|
|
@@ -842,13 +853,25 @@ function readProps(props) {
|
|
|
842
853
|
...where ? { at: { line: where[0], column: where[1] } } : {}
|
|
843
854
|
};
|
|
844
855
|
try {
|
|
845
|
-
report.value = formatValue(
|
|
856
|
+
report.value = formatValue(
|
|
857
|
+
(0, import_signal2.createRoot)((dispose) => {
|
|
858
|
+
try {
|
|
859
|
+
return (0, import_signal2.untrack)(() => props[name]);
|
|
860
|
+
} finally {
|
|
861
|
+
dispose();
|
|
862
|
+
}
|
|
863
|
+
}),
|
|
864
|
+
200
|
|
865
|
+
);
|
|
846
866
|
} catch {
|
|
847
867
|
}
|
|
848
868
|
out.push(report);
|
|
849
869
|
}
|
|
850
|
-
|
|
870
|
+
const reports = out.length ? out : void 0;
|
|
871
|
+
readOnce.set(props, reports);
|
|
872
|
+
return reports;
|
|
851
873
|
}
|
|
874
|
+
var readOnce = /* @__PURE__ */ new WeakMap();
|
|
852
875
|
function observeGraph(options = {}) {
|
|
853
876
|
installSourceMarker();
|
|
854
877
|
const origin = options.origin ?? (typeof location === "object" ? location.origin : void 0);
|
|
@@ -856,7 +879,7 @@ function observeGraph(options = {}) {
|
|
|
856
879
|
const claims = (node, value) => {
|
|
857
880
|
for (const dep of node.deps) {
|
|
858
881
|
const other = graph.get(dep);
|
|
859
|
-
if (other?.read && other
|
|
882
|
+
if (other?.read && readRaw(other) === value) return false;
|
|
860
883
|
}
|
|
861
884
|
return true;
|
|
862
885
|
};
|
|
@@ -874,6 +897,7 @@ function observeGraph(options = {}) {
|
|
|
874
897
|
const scopeOfTarget = /* @__PURE__ */ new WeakMap();
|
|
875
898
|
const fieldsOf = /* @__PURE__ */ new WeakMap();
|
|
876
899
|
let described = null;
|
|
900
|
+
let descendants = null;
|
|
877
901
|
const rendered = /* @__PURE__ */ new Map();
|
|
878
902
|
const elementsIn = (value) => {
|
|
879
903
|
if (value instanceof Element) return [value];
|
|
@@ -1235,6 +1259,7 @@ function observeGraph(options = {}) {
|
|
|
1235
1259
|
graph,
|
|
1236
1260
|
sample() {
|
|
1237
1261
|
described = null;
|
|
1262
|
+
descendants = null;
|
|
1238
1263
|
const changed = [];
|
|
1239
1264
|
const moved = (id) => {
|
|
1240
1265
|
changed.push(id);
|
|
@@ -1290,7 +1315,7 @@ function observeGraph(options = {}) {
|
|
|
1290
1315
|
runsAtLastSample.set(node.id, node.runs);
|
|
1291
1316
|
continue;
|
|
1292
1317
|
}
|
|
1293
|
-
const raw = node
|
|
1318
|
+
const raw = readRaw(node);
|
|
1294
1319
|
if (recording) raws.set(node.id, raw);
|
|
1295
1320
|
edges(node.id, node);
|
|
1296
1321
|
const stamped = raw?.$name;
|
|
@@ -1365,17 +1390,8 @@ function observeGraph(options = {}) {
|
|
|
1365
1390
|
if (live.length) return live;
|
|
1366
1391
|
collect(id);
|
|
1367
1392
|
if (!live.length) {
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
let at = node.createdIn;
|
|
1371
|
-
while (at !== void 0 && !seen.has(at)) {
|
|
1372
|
-
if (at === id) return true;
|
|
1373
|
-
seen.add(at);
|
|
1374
|
-
at = graph.get(at)?.createdIn;
|
|
1375
|
-
}
|
|
1376
|
-
return false;
|
|
1377
|
-
};
|
|
1378
|
-
for (const node of graph.values()) if (inside(node)) collect(node.id);
|
|
1393
|
+
descendants ??= descendantsByCreator(graph);
|
|
1394
|
+
for (const below of descendants.get(id) ?? []) collect(below);
|
|
1379
1395
|
}
|
|
1380
1396
|
return live;
|
|
1381
1397
|
},
|
|
@@ -1488,3 +1504,18 @@ function observeGraph(options = {}) {
|
|
|
1488
1504
|
}
|
|
1489
1505
|
return api;
|
|
1490
1506
|
}
|
|
1507
|
+
function descendantsByCreator(graph) {
|
|
1508
|
+
const out = /* @__PURE__ */ new Map();
|
|
1509
|
+
for (const node of graph.values()) {
|
|
1510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1511
|
+
let at = node.createdIn;
|
|
1512
|
+
while (at !== void 0 && !seen.has(at)) {
|
|
1513
|
+
seen.add(at);
|
|
1514
|
+
let list = out.get(at);
|
|
1515
|
+
if (!list) out.set(at, list = []);
|
|
1516
|
+
list.push(node.id);
|
|
1517
|
+
at = graph.get(at)?.createdIn;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return out;
|
|
1521
|
+
}
|
package/dist/observe.d.ts
CHANGED
|
@@ -77,4 +77,11 @@ export interface ObserveOptions {
|
|
|
77
77
|
mapSource?: (location: ReactiveSourceLocation) => ReactiveSourceLocation | undefined;
|
|
78
78
|
}
|
|
79
79
|
export declare function observeGraph(options?: ObserveOptions): ObservedGraph;
|
|
80
|
+
/**
|
|
81
|
+
* What every node created, at any depth, in graph order: the nodes whose `createdIn` chain
|
|
82
|
+
* passes through it. Built in one pass over the graph, so asking it for each tag of a page is
|
|
83
|
+
* linear; walking every node's chain once per tag made a sample quadratic, which on a page of a
|
|
84
|
+
* few thousand nodes took seconds on every keystroke.
|
|
85
|
+
*/
|
|
86
|
+
export declare function descendantsByCreator(graph: Map<number, RNode>): Map<number, number[]>;
|
|
80
87
|
//# sourceMappingURL=observe.d.ts.map
|
package/dist/observe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAUA,OAAO,
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAmE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG9D,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAmDhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACnC,gFAAgF;IAChF,MAAM,IAAI,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,6FAA6F;IAC7F,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,4EAA4E;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,8EAA8E;IAC9E,UAAU,IAAI,UAAU,EAAE,CAAC;IAC3B,qEAAqE;IACrE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IACnC,wEAAwE;IACxE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7C,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;IACrD,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,sBAAsB,GAAG,SAAS,CAAC;CACtF;AAgGD,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CA81BxE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAcrF"}
|
package/dist/observe.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
//
|
|
9
9
|
// The graph it fills is the same Map<number, RNode> createGraphView already draws, so a
|
|
10
10
|
// renderer does not care which of the two produced it.
|
|
11
|
-
import { observeReactiveNodes, untrack, } from '@fluixi/reactive/signal';
|
|
11
|
+
import { createRoot, observeReactiveNodes, untrack, } from '@fluixi/reactive/signal';
|
|
12
12
|
import { classSource, componentSource, dropReactiveSource, holeLocation, installSourceMarker, propsLocations, takeReactiveSource } from './source.js';
|
|
13
13
|
import { currentCallSite } from './callsite.js';
|
|
14
14
|
import { KIND_OF_BUILTIN } from './instrument.js';
|
|
@@ -91,14 +91,23 @@ const PREFIX = {
|
|
|
91
91
|
* app's modules load, which in practice means before the entry import.
|
|
92
92
|
*/
|
|
93
93
|
/**
|
|
94
|
-
* What a component was handed, read for display.
|
|
94
|
+
* What a component was handed, read for display, once per props object.
|
|
95
95
|
*
|
|
96
96
|
* Every prop is a getter over whatever the caller wrote, so reading one runs that
|
|
97
97
|
* expression. Untracked, or the read would subscribe whatever is sampling to it and the
|
|
98
|
-
* panel would drive the graph by looking at it.
|
|
99
|
-
*
|
|
98
|
+
* panel would drive the graph by looking at it. And only once: JSX in a prop compiles to a
|
|
99
|
+
* getter that makes a new memo on each read, which the next sample pulls, building the
|
|
100
|
+
* component again, and any other prop can reach such a getter (`when={local.trailing != null}`).
|
|
101
|
+
* Read on every sample, each one added another copy of those components to the graph.
|
|
102
|
+
* `children` is skipped: reading it builds the subtree.
|
|
103
|
+
*
|
|
104
|
+
* Any other getter can build one too (`Show`'s `fallback`), and what it builds is live: its
|
|
105
|
+
* effects run outside the component, so a context it reads is missing, and they keep running
|
|
106
|
+
* and throwing on every change. Each read happens in a root disposed as soon as it returns.
|
|
100
107
|
*/
|
|
101
108
|
function readProps(props) {
|
|
109
|
+
if (readOnce.has(props))
|
|
110
|
+
return readOnce.get(props);
|
|
102
111
|
const at = propsLocations(props);
|
|
103
112
|
const out = [];
|
|
104
113
|
for (const name of Object.keys(props)) {
|
|
@@ -110,15 +119,26 @@ function readProps(props) {
|
|
|
110
119
|
...(where ? { at: { line: where[0], column: where[1] } } : {}),
|
|
111
120
|
};
|
|
112
121
|
try {
|
|
113
|
-
report.value = formatValue(
|
|
122
|
+
report.value = formatValue(createRoot((dispose) => {
|
|
123
|
+
try {
|
|
124
|
+
return untrack(() => props[name]);
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
dispose();
|
|
128
|
+
}
|
|
129
|
+
}), 200);
|
|
114
130
|
}
|
|
115
131
|
catch {
|
|
116
132
|
// A getter that throws is still a prop worth naming.
|
|
117
133
|
}
|
|
118
134
|
out.push(report);
|
|
119
135
|
}
|
|
120
|
-
|
|
136
|
+
const reports = out.length ? out : undefined;
|
|
137
|
+
readOnce.set(props, reports);
|
|
138
|
+
return reports;
|
|
121
139
|
}
|
|
140
|
+
/** Each props object's reports, from its first read. */
|
|
141
|
+
const readOnce = new WeakMap();
|
|
122
142
|
export function observeGraph(options = {}) {
|
|
123
143
|
installSourceMarker();
|
|
124
144
|
const origin = options.origin ?? (typeof location === 'object' ? location.origin : undefined);
|
|
@@ -134,7 +154,7 @@ export function observeGraph(options = {}) {
|
|
|
134
154
|
const claims = (node, value) => {
|
|
135
155
|
for (const dep of node.deps) {
|
|
136
156
|
const other = graph.get(dep);
|
|
137
|
-
if (other?.read && other
|
|
157
|
+
if (other?.read && readRaw(other) === value)
|
|
138
158
|
return false;
|
|
139
159
|
}
|
|
140
160
|
return true;
|
|
@@ -189,6 +209,8 @@ export function observeGraph(options = {}) {
|
|
|
189
209
|
const fieldsOf = new WeakMap();
|
|
190
210
|
/** Cleared on each sample: the page has moved on. */
|
|
191
211
|
let described = null;
|
|
212
|
+
/** Per sample, like `described`: what each node created, at any depth. */
|
|
213
|
+
let descendants = null;
|
|
192
214
|
/**
|
|
193
215
|
* What each tag rendered, weakly.
|
|
194
216
|
*
|
|
@@ -704,6 +726,7 @@ export function observeGraph(options = {}) {
|
|
|
704
726
|
graph,
|
|
705
727
|
sample() {
|
|
706
728
|
described = null;
|
|
729
|
+
descendants = null;
|
|
707
730
|
const changed = [];
|
|
708
731
|
/** Recorded once here, so every consumer can be told about it at its own pace. */
|
|
709
732
|
const moved = (id) => {
|
|
@@ -780,7 +803,9 @@ export function observeGraph(options = {}) {
|
|
|
780
803
|
runsAtLastSample.set(node.id, node.runs);
|
|
781
804
|
continue;
|
|
782
805
|
}
|
|
783
|
-
|
|
806
|
+
// Guarded: a memo holding an error rethrows it on every read, and this runs on a
|
|
807
|
+
// timer, so an unguarded read threw the page's error ten times a second.
|
|
808
|
+
const raw = readRaw(node);
|
|
784
809
|
// For the next write to diff against; without it the first change has no entries.
|
|
785
810
|
if (recording)
|
|
786
811
|
raws.set(node.id, raw);
|
|
@@ -897,20 +922,9 @@ export function observeGraph(options = {}) {
|
|
|
897
922
|
// A value drives the element its binding was recorded against. A tag that returned
|
|
898
923
|
// nothing usable falls back to where the values inside it reach.
|
|
899
924
|
if (!live.length) {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
while (at !== undefined && !seen.has(at)) {
|
|
904
|
-
if (at === id)
|
|
905
|
-
return true;
|
|
906
|
-
seen.add(at);
|
|
907
|
-
at = graph.get(at)?.createdIn;
|
|
908
|
-
}
|
|
909
|
-
return false;
|
|
910
|
-
};
|
|
911
|
-
for (const node of graph.values())
|
|
912
|
-
if (inside(node))
|
|
913
|
-
collect(node.id);
|
|
925
|
+
descendants ??= descendantsByCreator(graph);
|
|
926
|
+
for (const below of descendants.get(id) ?? [])
|
|
927
|
+
collect(below);
|
|
914
928
|
}
|
|
915
929
|
return live;
|
|
916
930
|
},
|
|
@@ -1040,3 +1054,25 @@ export function observeGraph(options = {}) {
|
|
|
1040
1054
|
}
|
|
1041
1055
|
return api;
|
|
1042
1056
|
}
|
|
1057
|
+
/**
|
|
1058
|
+
* What every node created, at any depth, in graph order: the nodes whose `createdIn` chain
|
|
1059
|
+
* passes through it. Built in one pass over the graph, so asking it for each tag of a page is
|
|
1060
|
+
* linear; walking every node's chain once per tag made a sample quadratic, which on a page of a
|
|
1061
|
+
* few thousand nodes took seconds on every keystroke.
|
|
1062
|
+
*/
|
|
1063
|
+
export function descendantsByCreator(graph) {
|
|
1064
|
+
const out = new Map();
|
|
1065
|
+
for (const node of graph.values()) {
|
|
1066
|
+
const seen = new Set();
|
|
1067
|
+
let at = node.createdIn;
|
|
1068
|
+
while (at !== undefined && !seen.has(at)) {
|
|
1069
|
+
seen.add(at);
|
|
1070
|
+
let list = out.get(at);
|
|
1071
|
+
if (!list)
|
|
1072
|
+
out.set(at, (list = []));
|
|
1073
|
+
list.push(node.id);
|
|
1074
|
+
at = graph.get(at)?.createdIn;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return out;
|
|
1078
|
+
}
|
package/dist/observe.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/observe.ts
|
|
2
2
|
import {
|
|
3
|
+
createRoot as createRoot2,
|
|
3
4
|
observeReactiveNodes,
|
|
4
5
|
untrack as untrack2
|
|
5
6
|
} from "@fluixi/reactive/signal";
|
|
@@ -152,7 +153,14 @@ function callSite(stack, origin) {
|
|
|
152
153
|
return fallback ? { location: { ...fallback, external: true }, external: true } : void 0;
|
|
153
154
|
}
|
|
154
155
|
function currentCallSite(origin) {
|
|
155
|
-
|
|
156
|
+
const errors = Error;
|
|
157
|
+
const limit = errors.stackTraceLimit;
|
|
158
|
+
errors.stackTraceLimit = 50;
|
|
159
|
+
try {
|
|
160
|
+
return callSite(new Error().stack, origin);
|
|
161
|
+
} finally {
|
|
162
|
+
errors.stackTraceLimit = limit;
|
|
163
|
+
}
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
// src/instrument.ts
|
|
@@ -252,6 +260,8 @@ function walk(value, depth, seen) {
|
|
|
252
260
|
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
253
261
|
let read;
|
|
254
262
|
try {
|
|
263
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
264
|
+
if (descriptor?.get) return `${key}: [getter]`;
|
|
255
265
|
read = walk(object[key], depth + 1, seen);
|
|
256
266
|
} catch {
|
|
257
267
|
read = "[unreadable]";
|
|
@@ -822,6 +832,7 @@ var PREFIX = {
|
|
|
822
832
|
service: "svc"
|
|
823
833
|
};
|
|
824
834
|
function readProps(props) {
|
|
835
|
+
if (readOnce.has(props)) return readOnce.get(props);
|
|
825
836
|
const at = propsLocations(props);
|
|
826
837
|
const out = [];
|
|
827
838
|
for (const name of Object.keys(props)) {
|
|
@@ -832,13 +843,25 @@ function readProps(props) {
|
|
|
832
843
|
...where ? { at: { line: where[0], column: where[1] } } : {}
|
|
833
844
|
};
|
|
834
845
|
try {
|
|
835
|
-
report.value = formatValue(
|
|
846
|
+
report.value = formatValue(
|
|
847
|
+
createRoot2((dispose) => {
|
|
848
|
+
try {
|
|
849
|
+
return untrack2(() => props[name]);
|
|
850
|
+
} finally {
|
|
851
|
+
dispose();
|
|
852
|
+
}
|
|
853
|
+
}),
|
|
854
|
+
200
|
|
855
|
+
);
|
|
836
856
|
} catch {
|
|
837
857
|
}
|
|
838
858
|
out.push(report);
|
|
839
859
|
}
|
|
840
|
-
|
|
860
|
+
const reports = out.length ? out : void 0;
|
|
861
|
+
readOnce.set(props, reports);
|
|
862
|
+
return reports;
|
|
841
863
|
}
|
|
864
|
+
var readOnce = /* @__PURE__ */ new WeakMap();
|
|
842
865
|
function observeGraph(options = {}) {
|
|
843
866
|
installSourceMarker();
|
|
844
867
|
const origin = options.origin ?? (typeof location === "object" ? location.origin : void 0);
|
|
@@ -846,7 +869,7 @@ function observeGraph(options = {}) {
|
|
|
846
869
|
const claims = (node, value) => {
|
|
847
870
|
for (const dep of node.deps) {
|
|
848
871
|
const other = graph.get(dep);
|
|
849
|
-
if (other?.read && other
|
|
872
|
+
if (other?.read && readRaw(other) === value) return false;
|
|
850
873
|
}
|
|
851
874
|
return true;
|
|
852
875
|
};
|
|
@@ -864,6 +887,7 @@ function observeGraph(options = {}) {
|
|
|
864
887
|
const scopeOfTarget = /* @__PURE__ */ new WeakMap();
|
|
865
888
|
const fieldsOf = /* @__PURE__ */ new WeakMap();
|
|
866
889
|
let described = null;
|
|
890
|
+
let descendants = null;
|
|
867
891
|
const rendered = /* @__PURE__ */ new Map();
|
|
868
892
|
const elementsIn = (value) => {
|
|
869
893
|
if (value instanceof Element) return [value];
|
|
@@ -1225,6 +1249,7 @@ function observeGraph(options = {}) {
|
|
|
1225
1249
|
graph,
|
|
1226
1250
|
sample() {
|
|
1227
1251
|
described = null;
|
|
1252
|
+
descendants = null;
|
|
1228
1253
|
const changed = [];
|
|
1229
1254
|
const moved = (id) => {
|
|
1230
1255
|
changed.push(id);
|
|
@@ -1280,7 +1305,7 @@ function observeGraph(options = {}) {
|
|
|
1280
1305
|
runsAtLastSample.set(node.id, node.runs);
|
|
1281
1306
|
continue;
|
|
1282
1307
|
}
|
|
1283
|
-
const raw = node
|
|
1308
|
+
const raw = readRaw(node);
|
|
1284
1309
|
if (recording) raws.set(node.id, raw);
|
|
1285
1310
|
edges(node.id, node);
|
|
1286
1311
|
const stamped = raw?.$name;
|
|
@@ -1355,17 +1380,8 @@ function observeGraph(options = {}) {
|
|
|
1355
1380
|
if (live.length) return live;
|
|
1356
1381
|
collect(id);
|
|
1357
1382
|
if (!live.length) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
let at = node.createdIn;
|
|
1361
|
-
while (at !== void 0 && !seen.has(at)) {
|
|
1362
|
-
if (at === id) return true;
|
|
1363
|
-
seen.add(at);
|
|
1364
|
-
at = graph.get(at)?.createdIn;
|
|
1365
|
-
}
|
|
1366
|
-
return false;
|
|
1367
|
-
};
|
|
1368
|
-
for (const node of graph.values()) if (inside(node)) collect(node.id);
|
|
1383
|
+
descendants ??= descendantsByCreator(graph);
|
|
1384
|
+
for (const below of descendants.get(id) ?? []) collect(below);
|
|
1369
1385
|
}
|
|
1370
1386
|
return live;
|
|
1371
1387
|
},
|
|
@@ -1478,6 +1494,22 @@ function observeGraph(options = {}) {
|
|
|
1478
1494
|
}
|
|
1479
1495
|
return api;
|
|
1480
1496
|
}
|
|
1497
|
+
function descendantsByCreator(graph) {
|
|
1498
|
+
const out = /* @__PURE__ */ new Map();
|
|
1499
|
+
for (const node of graph.values()) {
|
|
1500
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1501
|
+
let at = node.createdIn;
|
|
1502
|
+
while (at !== void 0 && !seen.has(at)) {
|
|
1503
|
+
seen.add(at);
|
|
1504
|
+
let list = out.get(at);
|
|
1505
|
+
if (!list) out.set(at, list = []);
|
|
1506
|
+
list.push(node.id);
|
|
1507
|
+
at = graph.get(at)?.createdIn;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
return out;
|
|
1511
|
+
}
|
|
1481
1512
|
export {
|
|
1513
|
+
descendantsByCreator,
|
|
1482
1514
|
observeGraph
|
|
1483
1515
|
};
|
package/dist/plugins/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/devtools
|
|
1
|
+
/*! @fluixi/devtools v1.0.0-alpha.99 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
package/dist/plugins/index.mjs
CHANGED