@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.
Files changed (72) hide show
  1. package/dist/callsite.cjs +9 -0
  2. package/dist/callsite.d.ts +1 -1
  3. package/dist/callsite.d.ts.map +1 -1
  4. package/dist/callsite.js +10 -1
  5. package/dist/callsite.mjs +9 -0
  6. package/dist/change-view.js +2 -2
  7. package/dist/describe.js +2 -2
  8. package/dist/detail-panel.d.ts +1 -1
  9. package/dist/detail-panel.d.ts.map +1 -1
  10. package/dist/detail-panel.js +1 -1
  11. package/dist/diff.js +1 -1
  12. package/dist/export.cjs +1 -0
  13. package/dist/export.d.ts +2 -2
  14. package/dist/export.d.ts.map +1 -1
  15. package/dist/export.js +1 -1
  16. package/dist/export.mjs +1 -0
  17. package/dist/float.d.ts +1 -1
  18. package/dist/float.js +3 -3
  19. package/dist/format.js +3 -3
  20. package/dist/graph-view.cjs +12 -3
  21. package/dist/graph-view.d.ts.map +1 -1
  22. package/dist/graph-view.js +11 -2
  23. package/dist/graph-view.mjs +12 -3
  24. package/dist/history.d.ts +2 -2
  25. package/dist/history.js +2 -2
  26. package/dist/hook.cjs +158 -19
  27. package/dist/hook.d.ts +3 -3
  28. package/dist/hook.js +6 -6
  29. package/dist/hook.mjs +158 -19
  30. package/dist/index.cjs +186 -29
  31. package/dist/index.mjs +186 -29
  32. package/dist/inspector.cjs +8 -4
  33. package/dist/inspector.d.ts +2 -2
  34. package/dist/inspector.js +8 -8
  35. package/dist/inspector.mjs +8 -4
  36. package/dist/instrument.cjs +9 -3
  37. package/dist/instrument.d.ts +16 -1
  38. package/dist/instrument.d.ts.map +1 -1
  39. package/dist/instrument.mjs +9 -3
  40. package/dist/kind-filter.cjs +5 -2
  41. package/dist/kind-filter.d.ts +2 -2
  42. package/dist/kind-filter.js +4 -4
  43. package/dist/kind-filter.mjs +5 -2
  44. package/dist/observe.cjs +157 -19
  45. package/dist/observe.d.ts.map +1 -1
  46. package/dist/observe.js +165 -16
  47. package/dist/observe.mjs +157 -19
  48. package/dist/palette.cjs +4 -1
  49. package/dist/palette.d.ts.map +1 -1
  50. package/dist/palette.js +3 -0
  51. package/dist/palette.mjs +4 -1
  52. package/dist/path.d.ts +2 -2
  53. package/dist/path.js +2 -2
  54. package/dist/plugins/index.cjs +1 -1
  55. package/dist/plugins/index.mjs +1 -1
  56. package/dist/source.cjs +18 -3
  57. package/dist/source.d.ts +18 -3
  58. package/dist/source.d.ts.map +1 -1
  59. package/dist/source.js +29 -7
  60. package/dist/source.mjs +18 -3
  61. package/dist/timeline.js +3 -3
  62. package/dist/tree.cjs +19 -4
  63. package/dist/tree.d.ts.map +1 -1
  64. package/dist/tree.js +21 -2
  65. package/dist/tree.mjs +19 -4
  66. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  67. package/dist/wire.cjs +3 -1
  68. package/dist/wire.d.ts +2 -0
  69. package/dist/wire.d.ts.map +1 -1
  70. package/dist/wire.js +2 -0
  71. package/dist/wire.mjs +3 -1
  72. 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
- function markReactiveSource(file, line, column, name) {
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
- ...site && site.external && !mark?.location ? { source: mapped(site.location) } : {}
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
- removed.push({ id, rev: ++revision });
1090
- revs.delete(id);
1091
- if (removed.length > REMOVED_LOG) removed.splice(0, removed.length - REMOVED_LOG);
1092
- history.disposed(id, graph.get(id)?.label);
1093
- graph.delete(id);
1094
- handed.delete(id);
1095
- raws.delete(id);
1096
- cores.delete(id);
1097
- rendered.delete(id);
1098
- setters.delete(id);
1099
- runsAtLastSample.delete(id);
1100
- unnamed.delete(id);
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 — 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
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 — `12:0/1/2`. Null clears it.
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 — two copies of the runtime each keep
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 — an extension injects
29
- // one before anything else runs and the application's agent loads another — and `inject`
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 — so an extension's copy starts watching first. The application's agent runs
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 — a dev server
99
- // agent polling and a browser panel open at the same time — and draining here gave
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
- function markReactiveSource(file, line, column, name) {
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
- ...site && site.external && !mark?.location ? { source: mapped(site.location) } : {}
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
- removed.push({ id, rev: ++revision });
1078
- revs.delete(id);
1079
- if (removed.length > REMOVED_LOG) removed.splice(0, removed.length - REMOVED_LOG);
1080
- history.disposed(id, graph.get(id)?.label);
1081
- graph.delete(id);
1082
- handed.delete(id);
1083
- raws.delete(id);
1084
- cores.delete(id);
1085
- rendered.delete(id);
1086
- setters.delete(id);
1087
- runsAtLastSample.delete(id);
1088
- unnamed.delete(id);
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,