@fluixi/devtools 0.2.0-alpha.4 → 0.2.0-alpha.6
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/dist/callsite.cjs +9 -0
- package/dist/callsite.d.ts +1 -1
- package/dist/callsite.d.ts.map +1 -1
- package/dist/callsite.js +10 -1
- package/dist/callsite.mjs +9 -0
- package/dist/change-view.js +2 -2
- package/dist/describe.js +2 -2
- package/dist/detail-panel.d.ts +1 -1
- package/dist/detail-panel.d.ts.map +1 -1
- package/dist/detail-panel.js +1 -1
- package/dist/diff.js +1 -1
- package/dist/export.cjs +1 -0
- package/dist/export.d.ts +2 -2
- package/dist/export.d.ts.map +1 -1
- package/dist/export.js +1 -1
- package/dist/export.mjs +1 -0
- package/dist/float.d.ts +1 -1
- package/dist/float.js +3 -3
- package/dist/format.js +3 -3
- package/dist/graph-view.cjs +12 -3
- package/dist/graph-view.d.ts.map +1 -1
- package/dist/graph-view.js +11 -2
- package/dist/graph-view.mjs +12 -3
- package/dist/history.d.ts +2 -2
- package/dist/history.js +2 -2
- package/dist/hook.cjs +158 -19
- package/dist/hook.d.ts +3 -3
- package/dist/hook.js +6 -6
- package/dist/hook.mjs +158 -19
- package/dist/index.cjs +186 -29
- package/dist/index.mjs +186 -29
- package/dist/inspector.cjs +8 -4
- package/dist/inspector.d.ts +2 -2
- package/dist/inspector.js +8 -8
- package/dist/inspector.mjs +8 -4
- package/dist/instrument.cjs +9 -3
- package/dist/instrument.d.ts +16 -1
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.mjs +9 -3
- package/dist/kind-filter.cjs +5 -2
- package/dist/kind-filter.d.ts +2 -2
- package/dist/kind-filter.js +4 -4
- package/dist/kind-filter.mjs +5 -2
- package/dist/observe.cjs +157 -19
- package/dist/observe.d.ts.map +1 -1
- package/dist/observe.js +165 -16
- package/dist/observe.mjs +157 -19
- package/dist/palette.cjs +4 -1
- package/dist/palette.d.ts.map +1 -1
- package/dist/palette.js +3 -0
- package/dist/palette.mjs +4 -1
- package/dist/path.d.ts +2 -2
- package/dist/path.js +2 -2
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.mjs +1 -1
- package/dist/source.cjs +18 -3
- package/dist/source.d.ts +18 -3
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +29 -7
- package/dist/source.mjs +18 -3
- package/dist/timeline.js +3 -3
- package/dist/tree.cjs +19 -4
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +21 -2
- package/dist/tree.mjs +19 -4
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/wire.cjs +3 -1
- package/dist/wire.d.ts +2 -0
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +2 -0
- package/dist/wire.mjs +3 -1
- package/package.json +8 -2
package/dist/hook.cjs
CHANGED
|
@@ -207,6 +207,7 @@ var import_signal2 = require("@fluixi/reactive/signal");
|
|
|
207
207
|
// src/source.ts
|
|
208
208
|
var MARKER = "__fx_source";
|
|
209
209
|
var COMPONENT_MARKER = "__fx_component";
|
|
210
|
+
var CLASS_MARKER = "__fx_class";
|
|
210
211
|
var HOLE_MARKER = "__fx_hole";
|
|
211
212
|
var PROPS_MARKER = "__fx_props";
|
|
212
213
|
var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
|
|
@@ -217,12 +218,16 @@ var shared = host[MARKS] ?? {
|
|
|
217
218
|
components: /* @__PURE__ */ new Map()
|
|
218
219
|
};
|
|
219
220
|
host[MARKS] = shared;
|
|
220
|
-
|
|
221
|
+
shared.classes ??= /* @__PURE__ */ new WeakMap();
|
|
222
|
+
function markReactiveSource(file, line, column, name, self) {
|
|
221
223
|
const location2 = locate(file, line, column);
|
|
222
224
|
if (shared.pending && location2.external && !shared.pending.location?.external) return;
|
|
223
|
-
shared.pending = { name, location: location2 };
|
|
225
|
+
shared.pending = self && typeof self === "object" ? { name, location: location2, self } : { name, location: location2 };
|
|
224
226
|
shared.expiring = false;
|
|
225
227
|
}
|
|
228
|
+
function dropReactiveSource() {
|
|
229
|
+
shared.pending = null;
|
|
230
|
+
}
|
|
226
231
|
function locate(file, line, column) {
|
|
227
232
|
const external = !!file && (/^([a-zA-Z]:)?[\\/]/.test(file) || file.includes("node_modules/"));
|
|
228
233
|
return external ? { file, line, column, external } : { file, line, column };
|
|
@@ -236,13 +241,19 @@ function markComponentSource(name, file, line, column) {
|
|
|
236
241
|
}
|
|
237
242
|
if (!seen || seen.file !== file || seen.line !== line) shared.components.set(name, null);
|
|
238
243
|
}
|
|
244
|
+
function markClassSource(constructor, file, line, column) {
|
|
245
|
+
if (typeof constructor === "function") shared.classes.set(constructor, locate(file, line, column));
|
|
246
|
+
}
|
|
247
|
+
function classSource(constructor) {
|
|
248
|
+
return typeof constructor === "function" ? shared.classes.get(constructor) : void 0;
|
|
249
|
+
}
|
|
239
250
|
function componentSource(name) {
|
|
240
251
|
return shared.components.get(name) ?? void 0;
|
|
241
252
|
}
|
|
242
253
|
function takeReactiveSource() {
|
|
243
254
|
const mark = shared.pending;
|
|
244
255
|
if (mark) {
|
|
245
|
-
if (mark.name !== void 0) shared.pending = { location: mark.location };
|
|
256
|
+
if (mark.name !== void 0 || mark.self) shared.pending = { location: mark.location };
|
|
246
257
|
if (!shared.expiring) {
|
|
247
258
|
shared.expiring = true;
|
|
248
259
|
queueMicrotask(() => {
|
|
@@ -282,6 +293,7 @@ function holeLocation(accessor) {
|
|
|
282
293
|
function installSourceMarker() {
|
|
283
294
|
if (typeof host[MARKER] !== "function") host[MARKER] = markReactiveSource;
|
|
284
295
|
if (typeof host[COMPONENT_MARKER] !== "function") host[COMPONENT_MARKER] = markComponentSource;
|
|
296
|
+
if (typeof host[CLASS_MARKER] !== "function") host[CLASS_MARKER] = markClassSource;
|
|
285
297
|
if (typeof host[HOLE_MARKER] !== "function") host[HOLE_MARKER] = markHole;
|
|
286
298
|
if (typeof host[PROPS_MARKER] !== "function") host[PROPS_MARKER] = markProps;
|
|
287
299
|
}
|
|
@@ -293,6 +305,15 @@ var INTERNAL = [
|
|
|
293
305
|
"/packages/dom/",
|
|
294
306
|
"/packages/core/",
|
|
295
307
|
"/packages/devtools/",
|
|
308
|
+
"/packages/web-components/",
|
|
309
|
+
"/packages/auth/",
|
|
310
|
+
"/packages/oauth2/",
|
|
311
|
+
"/packages/session/",
|
|
312
|
+
"/packages/router/",
|
|
313
|
+
"/packages/head/",
|
|
314
|
+
"/packages/start/",
|
|
315
|
+
"/packages/server/",
|
|
316
|
+
"/packages/template-runtime/",
|
|
296
317
|
"/@fluixi/",
|
|
297
318
|
"node_modules",
|
|
298
319
|
"fluixi-devtools",
|
|
@@ -672,7 +693,10 @@ var KIND_COLOR = {
|
|
|
672
693
|
binding: "#5eead4",
|
|
673
694
|
setter: "#fb7185",
|
|
674
695
|
group: "#8a90a2",
|
|
675
|
-
element: "#8a90a2"
|
|
696
|
+
element: "#8a90a2",
|
|
697
|
+
"custom-element": "#2dd4bf",
|
|
698
|
+
module: "#facc15",
|
|
699
|
+
service: "#60a5fa"
|
|
676
700
|
};
|
|
677
701
|
var kindVar = (kind) => `--fx-kind-${kind}`;
|
|
678
702
|
var kindColor = (kind) => `var(${kindVar(kind)}, ${KIND_COLOR[kind]})`;
|
|
@@ -689,7 +713,11 @@ var TREE_KINDS = /* @__PURE__ */ new Set([
|
|
|
689
713
|
"handler",
|
|
690
714
|
// A component a plugin recognised as providing a context. Still a tag the author wrote,
|
|
691
715
|
// so leaving it out took it and everything it rendered out of the tree.
|
|
692
|
-
"provider"
|
|
716
|
+
"provider",
|
|
717
|
+
// Scopes the runtime reported: what their signals and memos belong to.
|
|
718
|
+
"custom-element",
|
|
719
|
+
"module",
|
|
720
|
+
"service"
|
|
693
721
|
]);
|
|
694
722
|
var TREE_CSS = `
|
|
695
723
|
.fx-tree-row {
|
|
@@ -805,7 +833,11 @@ var PREFIX = {
|
|
|
805
833
|
// A plugin's, and it names them itself.
|
|
806
834
|
directive: "d",
|
|
807
835
|
context: "ctx",
|
|
808
|
-
provider: "p"
|
|
836
|
+
provider: "p",
|
|
837
|
+
// Scopes are always named by what opened them.
|
|
838
|
+
"custom-element": "el",
|
|
839
|
+
module: "mod",
|
|
840
|
+
service: "svc"
|
|
809
841
|
};
|
|
810
842
|
function readProps(props) {
|
|
811
843
|
const at = propsLocations(props);
|
|
@@ -845,6 +877,10 @@ function observeGraph(options = {}) {
|
|
|
845
877
|
const boundTo = /* @__PURE__ */ new WeakMap();
|
|
846
878
|
const drivenBy = /* @__PURE__ */ new WeakMap();
|
|
847
879
|
let reaches = /* @__PURE__ */ new Map();
|
|
880
|
+
const SCOPE_KINDS = /* @__PURE__ */ new Set(["custom-element", "module", "service"]);
|
|
881
|
+
const scopeIds = /* @__PURE__ */ new WeakMap();
|
|
882
|
+
const scopeOfTarget = /* @__PURE__ */ new WeakMap();
|
|
883
|
+
const fieldsOf = /* @__PURE__ */ new WeakMap();
|
|
848
884
|
let described = null;
|
|
849
885
|
const rendered = /* @__PURE__ */ new Map();
|
|
850
886
|
const elementsIn = (value) => {
|
|
@@ -941,7 +977,9 @@ function observeGraph(options = {}) {
|
|
|
941
977
|
// Mapped, unlike `mark`: these two came off a stack, so they are positions in the
|
|
942
978
|
// compiled file until a host translates them.
|
|
943
979
|
...site && !site.external ? { usedAt: mapped(site.location) } : {},
|
|
944
|
-
|
|
980
|
+
// Not inside a scope: an element's prop is made by the package for the element, and
|
|
981
|
+
// the package's line says less than the scope it sits in already does.
|
|
982
|
+
...site && site.external && !mark?.location && !report.scope ? { source: mapped(site.location) } : {}
|
|
945
983
|
};
|
|
946
984
|
const owner = ancestor(report.parents);
|
|
947
985
|
if (owner !== void 0) node.createdIn = owner;
|
|
@@ -951,6 +989,28 @@ function observeGraph(options = {}) {
|
|
|
951
989
|
node.createdIn = originId;
|
|
952
990
|
if (from.source) node.source = from.source;
|
|
953
991
|
}
|
|
992
|
+
const scopeId = report.scope ? scopeIds.get(report.scope) : void 0;
|
|
993
|
+
if (scopeId !== void 0) {
|
|
994
|
+
node.scope = scopeId;
|
|
995
|
+
const creator = node.createdIn !== void 0 ? graph.get(node.createdIn) : void 0;
|
|
996
|
+
const insideAlready = node.createdIn === scopeId || creator?.scope === scopeId;
|
|
997
|
+
if (!insideAlready) node.createdIn = scopeId;
|
|
998
|
+
} else if (node.createdIn !== void 0) {
|
|
999
|
+
const creator = graph.get(node.createdIn);
|
|
1000
|
+
const inherited = creator && SCOPE_KINDS.has(creator.kind) ? creator.id : creator?.scope;
|
|
1001
|
+
if (inherited !== void 0) node.scope = inherited;
|
|
1002
|
+
}
|
|
1003
|
+
const self = mark?.self;
|
|
1004
|
+
if (self) {
|
|
1005
|
+
const list = fieldsOf.get(self);
|
|
1006
|
+
if (list) list.push(id);
|
|
1007
|
+
else fieldsOf.set(self, [id]);
|
|
1008
|
+
const open = scopeOfTarget.get(self);
|
|
1009
|
+
if (open !== void 0 && graph.has(open)) {
|
|
1010
|
+
node.scope = open;
|
|
1011
|
+
node.createdIn = open;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
954
1014
|
if (kind !== "effect" && typeof handle === "function") {
|
|
955
1015
|
const read = handle;
|
|
956
1016
|
node.read = () => (0, import_signal2.untrack)(read);
|
|
@@ -1086,20 +1146,90 @@ function observeGraph(options = {}) {
|
|
|
1086
1146
|
internals.delete(target);
|
|
1087
1147
|
const id = ids.get(target);
|
|
1088
1148
|
if (id === void 0) return;
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1149
|
+
forget(id);
|
|
1150
|
+
},
|
|
1151
|
+
scope(scope, info, parent) {
|
|
1152
|
+
dropReactiveSource();
|
|
1153
|
+
const id = seq++;
|
|
1154
|
+
const kind = info.kind === "element" ? "custom-element" : info.kind;
|
|
1155
|
+
const parentId = parent ? scopeIds.get(parent) : void 0;
|
|
1156
|
+
const found = currentCallSite(origin);
|
|
1157
|
+
const site = found && !/\0|__x00__|^virtual:/.test(found.location.file ?? "") ? found : void 0;
|
|
1158
|
+
const node = {
|
|
1159
|
+
id,
|
|
1160
|
+
label: info.name,
|
|
1161
|
+
kind,
|
|
1162
|
+
// The author named the element, the module and the service; none of them is plumbing.
|
|
1163
|
+
authored: true,
|
|
1164
|
+
deps: /* @__PURE__ */ new Set(),
|
|
1165
|
+
writes: /* @__PURE__ */ new Set(),
|
|
1166
|
+
runs: 0,
|
|
1167
|
+
lastPulse: 0,
|
|
1168
|
+
...info.detail ? { value: info.detail, detail: info.detail } : {},
|
|
1169
|
+
...parentId !== void 0 ? { scope: parentId, createdIn: parentId } : {}
|
|
1170
|
+
};
|
|
1171
|
+
const target = info.target;
|
|
1172
|
+
if (kind === "custom-element") {
|
|
1173
|
+
const defined = target ? classSource(target.constructor) : void 0;
|
|
1174
|
+
if (defined) node.declaredAt = defined;
|
|
1175
|
+
} else if (site && !site.external) {
|
|
1176
|
+
node.usedAt = mapped(site.location);
|
|
1177
|
+
}
|
|
1178
|
+
scopeIds.set(scope, id);
|
|
1179
|
+
if (target && typeof target === "object" && target.nodeType === 1) {
|
|
1180
|
+
rendered.set(id, [new WeakRef(target)]);
|
|
1181
|
+
}
|
|
1182
|
+
graph.set(id, node);
|
|
1183
|
+
history.created(id, node.createdIn, node.label);
|
|
1184
|
+
if (target && typeof target === "object") {
|
|
1185
|
+
scopeOfTarget.set(target, id);
|
|
1186
|
+
for (const field of fieldsOf.get(target) ?? []) {
|
|
1187
|
+
const made = graph.get(field);
|
|
1188
|
+
if (!made) continue;
|
|
1189
|
+
made.scope = id;
|
|
1190
|
+
made.createdIn = id;
|
|
1191
|
+
revs.set(field, ++revision);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
},
|
|
1195
|
+
scopeEnded(scope) {
|
|
1196
|
+
const id = scopeIds.get(scope);
|
|
1197
|
+
if (id === void 0) return;
|
|
1198
|
+
const ended = /* @__PURE__ */ new Set([id]);
|
|
1199
|
+
for (let grew = true; grew; ) {
|
|
1200
|
+
grew = false;
|
|
1201
|
+
for (const [other, node] of graph) {
|
|
1202
|
+
if (!ended.has(other) && node.scope !== void 0 && ended.has(node.scope)) {
|
|
1203
|
+
ended.add(other);
|
|
1204
|
+
grew = true;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
for (const gone of ended) forget(gone);
|
|
1209
|
+
},
|
|
1210
|
+
scopeAdopted(scope, parent) {
|
|
1211
|
+
const node = graph.get(scopeIds.get(scope) ?? -1);
|
|
1212
|
+
const parentId = scopeIds.get(parent);
|
|
1213
|
+
if (!node || parentId === void 0 || parentId === node.id) return;
|
|
1214
|
+
node.scope = parentId;
|
|
1215
|
+
node.createdIn = parentId;
|
|
1216
|
+
revs.set(node.id, ++revision);
|
|
1101
1217
|
}
|
|
1102
1218
|
});
|
|
1219
|
+
function forget(id) {
|
|
1220
|
+
removed.push({ id, rev: ++revision });
|
|
1221
|
+
revs.delete(id);
|
|
1222
|
+
if (removed.length > REMOVED_LOG) removed.splice(0, removed.length - REMOVED_LOG);
|
|
1223
|
+
history.disposed(id, graph.get(id)?.label);
|
|
1224
|
+
graph.delete(id);
|
|
1225
|
+
handed.delete(id);
|
|
1226
|
+
raws.delete(id);
|
|
1227
|
+
cores.delete(id);
|
|
1228
|
+
rendered.delete(id);
|
|
1229
|
+
setters.delete(id);
|
|
1230
|
+
runsAtLastSample.delete(id);
|
|
1231
|
+
unnamed.delete(id);
|
|
1232
|
+
}
|
|
1103
1233
|
const edges = (id, node) => {
|
|
1104
1234
|
const sources = cores.get(id)?.sources;
|
|
1105
1235
|
node.deps.clear();
|
|
@@ -1119,6 +1249,14 @@ function observeGraph(options = {}) {
|
|
|
1119
1249
|
revs.set(id, ++revision);
|
|
1120
1250
|
};
|
|
1121
1251
|
const now = Date.now();
|
|
1252
|
+
for (const [id, node] of graph) {
|
|
1253
|
+
if (node.kind !== "custom-element" || node.usedAt) continue;
|
|
1254
|
+
const element = rendered.get(id)?.[0]?.deref();
|
|
1255
|
+
const written = element ? element.__fx_loc : void 0;
|
|
1256
|
+
if (!written?.file) continue;
|
|
1257
|
+
node.usedAt = { file: written.file, line: written.line, column: written.column };
|
|
1258
|
+
revs.set(id, ++revision);
|
|
1259
|
+
}
|
|
1122
1260
|
const bindings = /* @__PURE__ */ new Map();
|
|
1123
1261
|
const drives = /* @__PURE__ */ new Map();
|
|
1124
1262
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -1457,6 +1595,7 @@ function serializeGraph(graph, now = Date.now(), options = {}) {
|
|
|
1457
1595
|
declaredAt: node.declaredAt,
|
|
1458
1596
|
usedAt: node.usedAt,
|
|
1459
1597
|
createdIn: node.createdIn,
|
|
1598
|
+
scope: node.scope,
|
|
1460
1599
|
bindings: node.bindings,
|
|
1461
1600
|
targets: node.targets,
|
|
1462
1601
|
setAt: node.setAt,
|
package/dist/hook.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export interface DevtoolsHook {
|
|
|
5
5
|
* Called by the runtime when it loads.
|
|
6
6
|
*
|
|
7
7
|
* `watch` is how the caller says it brought its own devtools. Two copies live on a page
|
|
8
|
-
* routinely
|
|
9
|
-
* agent loads another
|
|
8
|
+
* routinely: a browser extension injects one at document_start and an application's own
|
|
9
|
+
* agent loads another: and the first to arrive owns the hook. Without this the graph is
|
|
10
10
|
* built by whichever copy got there first, which for an installed extension is a build
|
|
11
11
|
* that knows nothing of the compiler that made the application.
|
|
12
12
|
*/
|
|
@@ -48,7 +48,7 @@ export interface DevtoolsHook {
|
|
|
48
48
|
*
|
|
49
49
|
* A number is a node, and covers everywhere it reaches. A string is one element, written
|
|
50
50
|
* as the tree keys them: the tag's id, the index of the root it rendered, then a child
|
|
51
|
-
* index per step
|
|
51
|
+
* index per step: `12:0/1/2`. Null clears it.
|
|
52
52
|
*/
|
|
53
53
|
highlight(target: number | string | null): void;
|
|
54
54
|
}
|
package/dist/hook.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// A browser extension or a dev-server injection runs this before the application loads. It
|
|
4
4
|
// leaves a global behind; when the app's copy of @fluixi/reactive is first evaluated, the
|
|
5
5
|
// runtime finds it and hands over its own `observeReactiveNodes`. The graph is then built
|
|
6
|
-
// from the app's framework rather than this bundle's
|
|
6
|
+
// from the app's framework rather than this bundle's, two copies of the runtime each keep
|
|
7
7
|
// their own nodes, so watching the wrong one shows an empty graph.
|
|
8
8
|
//
|
|
9
9
|
// The app imports nothing and knows nothing about this. It also works against a production
|
|
@@ -25,8 +25,8 @@ export function installDevtoolsHook() {
|
|
|
25
25
|
const host = globalThis;
|
|
26
26
|
const existing = host[HOOK];
|
|
27
27
|
if (existing) {
|
|
28
|
-
// Counted, not complained about. Two copies is the ordinary case
|
|
29
|
-
// one before anything else runs and the application's agent loads another
|
|
28
|
+
// Counted, not complained about. Two copies is the ordinary case, an extension injects
|
|
29
|
+
// one before anything else runs and the application's agent loads another, and `inject`
|
|
30
30
|
// sorts out which of them ends up watching.
|
|
31
31
|
existing.copies = (existing.copies ?? 1) + 1;
|
|
32
32
|
return existing;
|
|
@@ -47,7 +47,7 @@ export function installDevtoolsHook() {
|
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
// The runtime injects the moment it is evaluated, and it brings no devtools of its
|
|
50
|
-
// own
|
|
50
|
+
// own: so an extension's copy starts watching first. The application's agent runs
|
|
51
51
|
// straight after, before any of its own modules have made a node, and hands over an
|
|
52
52
|
// observer that matches the compiler that built it. That one takes over.
|
|
53
53
|
if (owned || !runtime.watch)
|
|
@@ -95,8 +95,8 @@ export function installDevtoolsHook() {
|
|
|
95
95
|
// Detection is shared and has to run: it is what notices anything moved at all.
|
|
96
96
|
const changed = observed.sample();
|
|
97
97
|
const cursor = observed.revision;
|
|
98
|
-
// Kept, not handed out once. The hook can have more than one reader
|
|
99
|
-
// agent polling and a browser panel open at the same time
|
|
98
|
+
// Kept, not handed out once. The hook can have more than one reader, a dev server
|
|
99
|
+
// agent polling and a browser panel open at the same time, and draining here gave
|
|
100
100
|
// each of them whichever events the other had not taken yet. Every event carries a
|
|
101
101
|
// seq, so a reader keeps what is new to it.
|
|
102
102
|
history.push(...observed.takeEvents());
|
package/dist/hook.mjs
CHANGED
|
@@ -184,6 +184,7 @@ import {
|
|
|
184
184
|
// src/source.ts
|
|
185
185
|
var MARKER = "__fx_source";
|
|
186
186
|
var COMPONENT_MARKER = "__fx_component";
|
|
187
|
+
var CLASS_MARKER = "__fx_class";
|
|
187
188
|
var HOLE_MARKER = "__fx_hole";
|
|
188
189
|
var PROPS_MARKER = "__fx_props";
|
|
189
190
|
var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
|
|
@@ -194,12 +195,16 @@ var shared = host[MARKS] ?? {
|
|
|
194
195
|
components: /* @__PURE__ */ new Map()
|
|
195
196
|
};
|
|
196
197
|
host[MARKS] = shared;
|
|
197
|
-
|
|
198
|
+
shared.classes ??= /* @__PURE__ */ new WeakMap();
|
|
199
|
+
function markReactiveSource(file, line, column, name, self) {
|
|
198
200
|
const location2 = locate(file, line, column);
|
|
199
201
|
if (shared.pending && location2.external && !shared.pending.location?.external) return;
|
|
200
|
-
shared.pending = { name, location: location2 };
|
|
202
|
+
shared.pending = self && typeof self === "object" ? { name, location: location2, self } : { name, location: location2 };
|
|
201
203
|
shared.expiring = false;
|
|
202
204
|
}
|
|
205
|
+
function dropReactiveSource() {
|
|
206
|
+
shared.pending = null;
|
|
207
|
+
}
|
|
203
208
|
function locate(file, line, column) {
|
|
204
209
|
const external = !!file && (/^([a-zA-Z]:)?[\\/]/.test(file) || file.includes("node_modules/"));
|
|
205
210
|
return external ? { file, line, column, external } : { file, line, column };
|
|
@@ -213,13 +218,19 @@ function markComponentSource(name, file, line, column) {
|
|
|
213
218
|
}
|
|
214
219
|
if (!seen || seen.file !== file || seen.line !== line) shared.components.set(name, null);
|
|
215
220
|
}
|
|
221
|
+
function markClassSource(constructor, file, line, column) {
|
|
222
|
+
if (typeof constructor === "function") shared.classes.set(constructor, locate(file, line, column));
|
|
223
|
+
}
|
|
224
|
+
function classSource(constructor) {
|
|
225
|
+
return typeof constructor === "function" ? shared.classes.get(constructor) : void 0;
|
|
226
|
+
}
|
|
216
227
|
function componentSource(name) {
|
|
217
228
|
return shared.components.get(name) ?? void 0;
|
|
218
229
|
}
|
|
219
230
|
function takeReactiveSource() {
|
|
220
231
|
const mark = shared.pending;
|
|
221
232
|
if (mark) {
|
|
222
|
-
if (mark.name !== void 0) shared.pending = { location: mark.location };
|
|
233
|
+
if (mark.name !== void 0 || mark.self) shared.pending = { location: mark.location };
|
|
223
234
|
if (!shared.expiring) {
|
|
224
235
|
shared.expiring = true;
|
|
225
236
|
queueMicrotask(() => {
|
|
@@ -259,6 +270,7 @@ function holeLocation(accessor) {
|
|
|
259
270
|
function installSourceMarker() {
|
|
260
271
|
if (typeof host[MARKER] !== "function") host[MARKER] = markReactiveSource;
|
|
261
272
|
if (typeof host[COMPONENT_MARKER] !== "function") host[COMPONENT_MARKER] = markComponentSource;
|
|
273
|
+
if (typeof host[CLASS_MARKER] !== "function") host[CLASS_MARKER] = markClassSource;
|
|
262
274
|
if (typeof host[HOLE_MARKER] !== "function") host[HOLE_MARKER] = markHole;
|
|
263
275
|
if (typeof host[PROPS_MARKER] !== "function") host[PROPS_MARKER] = markProps;
|
|
264
276
|
}
|
|
@@ -270,6 +282,15 @@ var INTERNAL = [
|
|
|
270
282
|
"/packages/dom/",
|
|
271
283
|
"/packages/core/",
|
|
272
284
|
"/packages/devtools/",
|
|
285
|
+
"/packages/web-components/",
|
|
286
|
+
"/packages/auth/",
|
|
287
|
+
"/packages/oauth2/",
|
|
288
|
+
"/packages/session/",
|
|
289
|
+
"/packages/router/",
|
|
290
|
+
"/packages/head/",
|
|
291
|
+
"/packages/start/",
|
|
292
|
+
"/packages/server/",
|
|
293
|
+
"/packages/template-runtime/",
|
|
273
294
|
"/@fluixi/",
|
|
274
295
|
"node_modules",
|
|
275
296
|
"fluixi-devtools",
|
|
@@ -660,7 +681,10 @@ var KIND_COLOR = {
|
|
|
660
681
|
binding: "#5eead4",
|
|
661
682
|
setter: "#fb7185",
|
|
662
683
|
group: "#8a90a2",
|
|
663
|
-
element: "#8a90a2"
|
|
684
|
+
element: "#8a90a2",
|
|
685
|
+
"custom-element": "#2dd4bf",
|
|
686
|
+
module: "#facc15",
|
|
687
|
+
service: "#60a5fa"
|
|
664
688
|
};
|
|
665
689
|
var kindVar = (kind) => `--fx-kind-${kind}`;
|
|
666
690
|
var kindColor = (kind) => `var(${kindVar(kind)}, ${KIND_COLOR[kind]})`;
|
|
@@ -677,7 +701,11 @@ var TREE_KINDS = /* @__PURE__ */ new Set([
|
|
|
677
701
|
"handler",
|
|
678
702
|
// A component a plugin recognised as providing a context. Still a tag the author wrote,
|
|
679
703
|
// so leaving it out took it and everything it rendered out of the tree.
|
|
680
|
-
"provider"
|
|
704
|
+
"provider",
|
|
705
|
+
// Scopes the runtime reported: what their signals and memos belong to.
|
|
706
|
+
"custom-element",
|
|
707
|
+
"module",
|
|
708
|
+
"service"
|
|
681
709
|
]);
|
|
682
710
|
var TREE_CSS = `
|
|
683
711
|
.fx-tree-row {
|
|
@@ -793,7 +821,11 @@ var PREFIX = {
|
|
|
793
821
|
// A plugin's, and it names them itself.
|
|
794
822
|
directive: "d",
|
|
795
823
|
context: "ctx",
|
|
796
|
-
provider: "p"
|
|
824
|
+
provider: "p",
|
|
825
|
+
// Scopes are always named by what opened them.
|
|
826
|
+
"custom-element": "el",
|
|
827
|
+
module: "mod",
|
|
828
|
+
service: "svc"
|
|
797
829
|
};
|
|
798
830
|
function readProps(props) {
|
|
799
831
|
const at = propsLocations(props);
|
|
@@ -833,6 +865,10 @@ function observeGraph(options = {}) {
|
|
|
833
865
|
const boundTo = /* @__PURE__ */ new WeakMap();
|
|
834
866
|
const drivenBy = /* @__PURE__ */ new WeakMap();
|
|
835
867
|
let reaches = /* @__PURE__ */ new Map();
|
|
868
|
+
const SCOPE_KINDS = /* @__PURE__ */ new Set(["custom-element", "module", "service"]);
|
|
869
|
+
const scopeIds = /* @__PURE__ */ new WeakMap();
|
|
870
|
+
const scopeOfTarget = /* @__PURE__ */ new WeakMap();
|
|
871
|
+
const fieldsOf = /* @__PURE__ */ new WeakMap();
|
|
836
872
|
let described = null;
|
|
837
873
|
const rendered = /* @__PURE__ */ new Map();
|
|
838
874
|
const elementsIn = (value) => {
|
|
@@ -929,7 +965,9 @@ function observeGraph(options = {}) {
|
|
|
929
965
|
// Mapped, unlike `mark`: these two came off a stack, so they are positions in the
|
|
930
966
|
// compiled file until a host translates them.
|
|
931
967
|
...site && !site.external ? { usedAt: mapped(site.location) } : {},
|
|
932
|
-
|
|
968
|
+
// Not inside a scope: an element's prop is made by the package for the element, and
|
|
969
|
+
// the package's line says less than the scope it sits in already does.
|
|
970
|
+
...site && site.external && !mark?.location && !report.scope ? { source: mapped(site.location) } : {}
|
|
933
971
|
};
|
|
934
972
|
const owner = ancestor(report.parents);
|
|
935
973
|
if (owner !== void 0) node.createdIn = owner;
|
|
@@ -939,6 +977,28 @@ function observeGraph(options = {}) {
|
|
|
939
977
|
node.createdIn = originId;
|
|
940
978
|
if (from.source) node.source = from.source;
|
|
941
979
|
}
|
|
980
|
+
const scopeId = report.scope ? scopeIds.get(report.scope) : void 0;
|
|
981
|
+
if (scopeId !== void 0) {
|
|
982
|
+
node.scope = scopeId;
|
|
983
|
+
const creator = node.createdIn !== void 0 ? graph.get(node.createdIn) : void 0;
|
|
984
|
+
const insideAlready = node.createdIn === scopeId || creator?.scope === scopeId;
|
|
985
|
+
if (!insideAlready) node.createdIn = scopeId;
|
|
986
|
+
} else if (node.createdIn !== void 0) {
|
|
987
|
+
const creator = graph.get(node.createdIn);
|
|
988
|
+
const inherited = creator && SCOPE_KINDS.has(creator.kind) ? creator.id : creator?.scope;
|
|
989
|
+
if (inherited !== void 0) node.scope = inherited;
|
|
990
|
+
}
|
|
991
|
+
const self = mark?.self;
|
|
992
|
+
if (self) {
|
|
993
|
+
const list = fieldsOf.get(self);
|
|
994
|
+
if (list) list.push(id);
|
|
995
|
+
else fieldsOf.set(self, [id]);
|
|
996
|
+
const open = scopeOfTarget.get(self);
|
|
997
|
+
if (open !== void 0 && graph.has(open)) {
|
|
998
|
+
node.scope = open;
|
|
999
|
+
node.createdIn = open;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
942
1002
|
if (kind !== "effect" && typeof handle === "function") {
|
|
943
1003
|
const read = handle;
|
|
944
1004
|
node.read = () => untrack2(read);
|
|
@@ -1074,20 +1134,90 @@ function observeGraph(options = {}) {
|
|
|
1074
1134
|
internals.delete(target);
|
|
1075
1135
|
const id = ids.get(target);
|
|
1076
1136
|
if (id === void 0) return;
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1137
|
+
forget(id);
|
|
1138
|
+
},
|
|
1139
|
+
scope(scope, info, parent) {
|
|
1140
|
+
dropReactiveSource();
|
|
1141
|
+
const id = seq++;
|
|
1142
|
+
const kind = info.kind === "element" ? "custom-element" : info.kind;
|
|
1143
|
+
const parentId = parent ? scopeIds.get(parent) : void 0;
|
|
1144
|
+
const found = currentCallSite(origin);
|
|
1145
|
+
const site = found && !/\0|__x00__|^virtual:/.test(found.location.file ?? "") ? found : void 0;
|
|
1146
|
+
const node = {
|
|
1147
|
+
id,
|
|
1148
|
+
label: info.name,
|
|
1149
|
+
kind,
|
|
1150
|
+
// The author named the element, the module and the service; none of them is plumbing.
|
|
1151
|
+
authored: true,
|
|
1152
|
+
deps: /* @__PURE__ */ new Set(),
|
|
1153
|
+
writes: /* @__PURE__ */ new Set(),
|
|
1154
|
+
runs: 0,
|
|
1155
|
+
lastPulse: 0,
|
|
1156
|
+
...info.detail ? { value: info.detail, detail: info.detail } : {},
|
|
1157
|
+
...parentId !== void 0 ? { scope: parentId, createdIn: parentId } : {}
|
|
1158
|
+
};
|
|
1159
|
+
const target = info.target;
|
|
1160
|
+
if (kind === "custom-element") {
|
|
1161
|
+
const defined = target ? classSource(target.constructor) : void 0;
|
|
1162
|
+
if (defined) node.declaredAt = defined;
|
|
1163
|
+
} else if (site && !site.external) {
|
|
1164
|
+
node.usedAt = mapped(site.location);
|
|
1165
|
+
}
|
|
1166
|
+
scopeIds.set(scope, id);
|
|
1167
|
+
if (target && typeof target === "object" && target.nodeType === 1) {
|
|
1168
|
+
rendered.set(id, [new WeakRef(target)]);
|
|
1169
|
+
}
|
|
1170
|
+
graph.set(id, node);
|
|
1171
|
+
history.created(id, node.createdIn, node.label);
|
|
1172
|
+
if (target && typeof target === "object") {
|
|
1173
|
+
scopeOfTarget.set(target, id);
|
|
1174
|
+
for (const field of fieldsOf.get(target) ?? []) {
|
|
1175
|
+
const made = graph.get(field);
|
|
1176
|
+
if (!made) continue;
|
|
1177
|
+
made.scope = id;
|
|
1178
|
+
made.createdIn = id;
|
|
1179
|
+
revs.set(field, ++revision);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
},
|
|
1183
|
+
scopeEnded(scope) {
|
|
1184
|
+
const id = scopeIds.get(scope);
|
|
1185
|
+
if (id === void 0) return;
|
|
1186
|
+
const ended = /* @__PURE__ */ new Set([id]);
|
|
1187
|
+
for (let grew = true; grew; ) {
|
|
1188
|
+
grew = false;
|
|
1189
|
+
for (const [other, node] of graph) {
|
|
1190
|
+
if (!ended.has(other) && node.scope !== void 0 && ended.has(node.scope)) {
|
|
1191
|
+
ended.add(other);
|
|
1192
|
+
grew = true;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
for (const gone of ended) forget(gone);
|
|
1197
|
+
},
|
|
1198
|
+
scopeAdopted(scope, parent) {
|
|
1199
|
+
const node = graph.get(scopeIds.get(scope) ?? -1);
|
|
1200
|
+
const parentId = scopeIds.get(parent);
|
|
1201
|
+
if (!node || parentId === void 0 || parentId === node.id) return;
|
|
1202
|
+
node.scope = parentId;
|
|
1203
|
+
node.createdIn = parentId;
|
|
1204
|
+
revs.set(node.id, ++revision);
|
|
1089
1205
|
}
|
|
1090
1206
|
});
|
|
1207
|
+
function forget(id) {
|
|
1208
|
+
removed.push({ id, rev: ++revision });
|
|
1209
|
+
revs.delete(id);
|
|
1210
|
+
if (removed.length > REMOVED_LOG) removed.splice(0, removed.length - REMOVED_LOG);
|
|
1211
|
+
history.disposed(id, graph.get(id)?.label);
|
|
1212
|
+
graph.delete(id);
|
|
1213
|
+
handed.delete(id);
|
|
1214
|
+
raws.delete(id);
|
|
1215
|
+
cores.delete(id);
|
|
1216
|
+
rendered.delete(id);
|
|
1217
|
+
setters.delete(id);
|
|
1218
|
+
runsAtLastSample.delete(id);
|
|
1219
|
+
unnamed.delete(id);
|
|
1220
|
+
}
|
|
1091
1221
|
const edges = (id, node) => {
|
|
1092
1222
|
const sources = cores.get(id)?.sources;
|
|
1093
1223
|
node.deps.clear();
|
|
@@ -1107,6 +1237,14 @@ function observeGraph(options = {}) {
|
|
|
1107
1237
|
revs.set(id, ++revision);
|
|
1108
1238
|
};
|
|
1109
1239
|
const now = Date.now();
|
|
1240
|
+
for (const [id, node] of graph) {
|
|
1241
|
+
if (node.kind !== "custom-element" || node.usedAt) continue;
|
|
1242
|
+
const element = rendered.get(id)?.[0]?.deref();
|
|
1243
|
+
const written = element ? element.__fx_loc : void 0;
|
|
1244
|
+
if (!written?.file) continue;
|
|
1245
|
+
node.usedAt = { file: written.file, line: written.line, column: written.column };
|
|
1246
|
+
revs.set(id, ++revision);
|
|
1247
|
+
}
|
|
1110
1248
|
const bindings = /* @__PURE__ */ new Map();
|
|
1111
1249
|
const drives = /* @__PURE__ */ new Map();
|
|
1112
1250
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -1445,6 +1583,7 @@ function serializeGraph(graph, now = Date.now(), options = {}) {
|
|
|
1445
1583
|
declaredAt: node.declaredAt,
|
|
1446
1584
|
usedAt: node.usedAt,
|
|
1447
1585
|
createdIn: node.createdIn,
|
|
1586
|
+
scope: node.scope,
|
|
1448
1587
|
bindings: node.bindings,
|
|
1449
1588
|
targets: node.targets,
|
|
1450
1589
|
setAt: node.setAt,
|