@fluixi/devtools 0.2.0-alpha.5 → 0.2.0-alpha.7

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 (50) hide show
  1. package/dist/callsite.cjs +9 -0
  2. package/dist/callsite.d.ts.map +1 -1
  3. package/dist/callsite.js +9 -0
  4. package/dist/callsite.mjs +9 -0
  5. package/dist/export.cjs +1 -0
  6. package/dist/export.mjs +1 -0
  7. package/dist/graph-view.cjs +12 -3
  8. package/dist/graph-view.d.ts.map +1 -1
  9. package/dist/graph-view.js +11 -2
  10. package/dist/graph-view.mjs +12 -3
  11. package/dist/hook.cjs +173 -21
  12. package/dist/hook.mjs +174 -21
  13. package/dist/index.cjs +199 -29
  14. package/dist/index.mjs +200 -29
  15. package/dist/inspector.cjs +6 -2
  16. package/dist/inspector.js +1 -1
  17. package/dist/inspector.mjs +6 -2
  18. package/dist/instrument.cjs +9 -3
  19. package/dist/instrument.d.ts +16 -1
  20. package/dist/instrument.d.ts.map +1 -1
  21. package/dist/instrument.mjs +9 -3
  22. package/dist/kind-filter.cjs +5 -2
  23. package/dist/kind-filter.js +3 -3
  24. package/dist/kind-filter.mjs +5 -2
  25. package/dist/observe.cjs +172 -21
  26. package/dist/observe.d.ts.map +1 -1
  27. package/dist/observe.js +191 -22
  28. package/dist/observe.mjs +173 -21
  29. package/dist/palette.cjs +4 -1
  30. package/dist/palette.d.ts.map +1 -1
  31. package/dist/palette.js +3 -0
  32. package/dist/palette.mjs +4 -1
  33. package/dist/plugins/index.cjs +1 -1
  34. package/dist/plugins/index.mjs +1 -1
  35. package/dist/source.cjs +18 -3
  36. package/dist/source.d.ts +16 -1
  37. package/dist/source.d.ts.map +1 -1
  38. package/dist/source.js +25 -3
  39. package/dist/source.mjs +18 -3
  40. package/dist/tree.cjs +19 -4
  41. package/dist/tree.d.ts.map +1 -1
  42. package/dist/tree.js +21 -2
  43. package/dist/tree.mjs +19 -4
  44. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  45. package/dist/wire.cjs +3 -1
  46. package/dist/wire.d.ts +2 -0
  47. package/dist/wire.d.ts.map +1 -1
  48. package/dist/wire.js +2 -0
  49. package/dist/wire.mjs +3 -1
  50. package/package.json +2 -2
package/dist/hook.mjs CHANGED
@@ -177,6 +177,7 @@ function withoutElements(nodes) {
177
177
 
178
178
  // src/observe.ts
179
179
  import {
180
+ createRoot as createRoot2,
180
181
  observeReactiveNodes,
181
182
  untrack as untrack2
182
183
  } from "@fluixi/reactive/signal";
@@ -184,6 +185,7 @@ import {
184
185
  // src/source.ts
185
186
  var MARKER = "__fx_source";
186
187
  var COMPONENT_MARKER = "__fx_component";
188
+ var CLASS_MARKER = "__fx_class";
187
189
  var HOLE_MARKER = "__fx_hole";
188
190
  var PROPS_MARKER = "__fx_props";
189
191
  var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
@@ -194,12 +196,16 @@ var shared = host[MARKS] ?? {
194
196
  components: /* @__PURE__ */ new Map()
195
197
  };
196
198
  host[MARKS] = shared;
197
- function markReactiveSource(file, line, column, name) {
199
+ shared.classes ??= /* @__PURE__ */ new WeakMap();
200
+ function markReactiveSource(file, line, column, name, self) {
198
201
  const location2 = locate(file, line, column);
199
202
  if (shared.pending && location2.external && !shared.pending.location?.external) return;
200
- shared.pending = { name, location: location2 };
203
+ shared.pending = self && typeof self === "object" ? { name, location: location2, self } : { name, location: location2 };
201
204
  shared.expiring = false;
202
205
  }
206
+ function dropReactiveSource() {
207
+ shared.pending = null;
208
+ }
203
209
  function locate(file, line, column) {
204
210
  const external = !!file && (/^([a-zA-Z]:)?[\\/]/.test(file) || file.includes("node_modules/"));
205
211
  return external ? { file, line, column, external } : { file, line, column };
@@ -213,13 +219,19 @@ function markComponentSource(name, file, line, column) {
213
219
  }
214
220
  if (!seen || seen.file !== file || seen.line !== line) shared.components.set(name, null);
215
221
  }
222
+ function markClassSource(constructor, file, line, column) {
223
+ if (typeof constructor === "function") shared.classes.set(constructor, locate(file, line, column));
224
+ }
225
+ function classSource(constructor) {
226
+ return typeof constructor === "function" ? shared.classes.get(constructor) : void 0;
227
+ }
216
228
  function componentSource(name) {
217
229
  return shared.components.get(name) ?? void 0;
218
230
  }
219
231
  function takeReactiveSource() {
220
232
  const mark = shared.pending;
221
233
  if (mark) {
222
- if (mark.name !== void 0) shared.pending = { location: mark.location };
234
+ if (mark.name !== void 0 || mark.self) shared.pending = { location: mark.location };
223
235
  if (!shared.expiring) {
224
236
  shared.expiring = true;
225
237
  queueMicrotask(() => {
@@ -259,6 +271,7 @@ function holeLocation(accessor) {
259
271
  function installSourceMarker() {
260
272
  if (typeof host[MARKER] !== "function") host[MARKER] = markReactiveSource;
261
273
  if (typeof host[COMPONENT_MARKER] !== "function") host[COMPONENT_MARKER] = markComponentSource;
274
+ if (typeof host[CLASS_MARKER] !== "function") host[CLASS_MARKER] = markClassSource;
262
275
  if (typeof host[HOLE_MARKER] !== "function") host[HOLE_MARKER] = markHole;
263
276
  if (typeof host[PROPS_MARKER] !== "function") host[PROPS_MARKER] = markProps;
264
277
  }
@@ -270,6 +283,15 @@ var INTERNAL = [
270
283
  "/packages/dom/",
271
284
  "/packages/core/",
272
285
  "/packages/devtools/",
286
+ "/packages/web-components/",
287
+ "/packages/auth/",
288
+ "/packages/oauth2/",
289
+ "/packages/session/",
290
+ "/packages/router/",
291
+ "/packages/head/",
292
+ "/packages/start/",
293
+ "/packages/server/",
294
+ "/packages/template-runtime/",
273
295
  "/@fluixi/",
274
296
  "node_modules",
275
297
  "fluixi-devtools",
@@ -660,7 +682,10 @@ var KIND_COLOR = {
660
682
  binding: "#5eead4",
661
683
  setter: "#fb7185",
662
684
  group: "#8a90a2",
663
- element: "#8a90a2"
685
+ element: "#8a90a2",
686
+ "custom-element": "#2dd4bf",
687
+ module: "#facc15",
688
+ service: "#60a5fa"
664
689
  };
665
690
  var kindVar = (kind) => `--fx-kind-${kind}`;
666
691
  var kindColor = (kind) => `var(${kindVar(kind)}, ${KIND_COLOR[kind]})`;
@@ -677,7 +702,11 @@ var TREE_KINDS = /* @__PURE__ */ new Set([
677
702
  "handler",
678
703
  // A component a plugin recognised as providing a context. Still a tag the author wrote,
679
704
  // so leaving it out took it and everything it rendered out of the tree.
680
- "provider"
705
+ "provider",
706
+ // Scopes the runtime reported: what their signals and memos belong to.
707
+ "custom-element",
708
+ "module",
709
+ "service"
681
710
  ]);
682
711
  var TREE_CSS = `
683
712
  .fx-tree-row {
@@ -793,9 +822,14 @@ var PREFIX = {
793
822
  // A plugin's, and it names them itself.
794
823
  directive: "d",
795
824
  context: "ctx",
796
- provider: "p"
825
+ provider: "p",
826
+ // Scopes are always named by what opened them.
827
+ "custom-element": "el",
828
+ module: "mod",
829
+ service: "svc"
797
830
  };
798
831
  function readProps(props) {
832
+ if (readOnce.has(props)) return readOnce.get(props);
799
833
  const at = propsLocations(props);
800
834
  const out = [];
801
835
  for (const name of Object.keys(props)) {
@@ -806,13 +840,25 @@ function readProps(props) {
806
840
  ...where ? { at: { line: where[0], column: where[1] } } : {}
807
841
  };
808
842
  try {
809
- report.value = formatValue(untrack2(() => props[name]), 200);
843
+ report.value = formatValue(
844
+ createRoot2((dispose) => {
845
+ try {
846
+ return untrack2(() => props[name]);
847
+ } finally {
848
+ dispose();
849
+ }
850
+ }),
851
+ 200
852
+ );
810
853
  } catch {
811
854
  }
812
855
  out.push(report);
813
856
  }
814
- return out.length ? out : void 0;
857
+ const reports = out.length ? out : void 0;
858
+ readOnce.set(props, reports);
859
+ return reports;
815
860
  }
861
+ var readOnce = /* @__PURE__ */ new WeakMap();
816
862
  function observeGraph(options = {}) {
817
863
  installSourceMarker();
818
864
  const origin = options.origin ?? (typeof location === "object" ? location.origin : void 0);
@@ -833,6 +879,10 @@ function observeGraph(options = {}) {
833
879
  const boundTo = /* @__PURE__ */ new WeakMap();
834
880
  const drivenBy = /* @__PURE__ */ new WeakMap();
835
881
  let reaches = /* @__PURE__ */ new Map();
882
+ const SCOPE_KINDS = /* @__PURE__ */ new Set(["custom-element", "module", "service"]);
883
+ const scopeIds = /* @__PURE__ */ new WeakMap();
884
+ const scopeOfTarget = /* @__PURE__ */ new WeakMap();
885
+ const fieldsOf = /* @__PURE__ */ new WeakMap();
836
886
  let described = null;
837
887
  const rendered = /* @__PURE__ */ new Map();
838
888
  const elementsIn = (value) => {
@@ -929,7 +979,9 @@ function observeGraph(options = {}) {
929
979
  // Mapped, unlike `mark`: these two came off a stack, so they are positions in the
930
980
  // compiled file until a host translates them.
931
981
  ...site && !site.external ? { usedAt: mapped(site.location) } : {},
932
- ...site && site.external && !mark?.location ? { source: mapped(site.location) } : {}
982
+ // Not inside a scope: an element's prop is made by the package for the element, and
983
+ // the package's line says less than the scope it sits in already does.
984
+ ...site && site.external && !mark?.location && !report.scope ? { source: mapped(site.location) } : {}
933
985
  };
934
986
  const owner = ancestor(report.parents);
935
987
  if (owner !== void 0) node.createdIn = owner;
@@ -939,6 +991,28 @@ function observeGraph(options = {}) {
939
991
  node.createdIn = originId;
940
992
  if (from.source) node.source = from.source;
941
993
  }
994
+ const scopeId = report.scope ? scopeIds.get(report.scope) : void 0;
995
+ if (scopeId !== void 0) {
996
+ node.scope = scopeId;
997
+ const creator = node.createdIn !== void 0 ? graph.get(node.createdIn) : void 0;
998
+ const insideAlready = node.createdIn === scopeId || creator?.scope === scopeId;
999
+ if (!insideAlready) node.createdIn = scopeId;
1000
+ } else if (node.createdIn !== void 0) {
1001
+ const creator = graph.get(node.createdIn);
1002
+ const inherited = creator && SCOPE_KINDS.has(creator.kind) ? creator.id : creator?.scope;
1003
+ if (inherited !== void 0) node.scope = inherited;
1004
+ }
1005
+ const self = mark?.self;
1006
+ if (self) {
1007
+ const list = fieldsOf.get(self);
1008
+ if (list) list.push(id);
1009
+ else fieldsOf.set(self, [id]);
1010
+ const open = scopeOfTarget.get(self);
1011
+ if (open !== void 0 && graph.has(open)) {
1012
+ node.scope = open;
1013
+ node.createdIn = open;
1014
+ }
1015
+ }
942
1016
  if (kind !== "effect" && typeof handle === "function") {
943
1017
  const read = handle;
944
1018
  node.read = () => untrack2(read);
@@ -1074,20 +1148,90 @@ function observeGraph(options = {}) {
1074
1148
  internals.delete(target);
1075
1149
  const id = ids.get(target);
1076
1150
  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);
1151
+ forget(id);
1152
+ },
1153
+ scope(scope, info, parent) {
1154
+ dropReactiveSource();
1155
+ const id = seq++;
1156
+ const kind = info.kind === "element" ? "custom-element" : info.kind;
1157
+ const parentId = parent ? scopeIds.get(parent) : void 0;
1158
+ const found = currentCallSite(origin);
1159
+ const site = found && !/\0|__x00__|^virtual:/.test(found.location.file ?? "") ? found : void 0;
1160
+ const node = {
1161
+ id,
1162
+ label: info.name,
1163
+ kind,
1164
+ // The author named the element, the module and the service; none of them is plumbing.
1165
+ authored: true,
1166
+ deps: /* @__PURE__ */ new Set(),
1167
+ writes: /* @__PURE__ */ new Set(),
1168
+ runs: 0,
1169
+ lastPulse: 0,
1170
+ ...info.detail ? { value: info.detail, detail: info.detail } : {},
1171
+ ...parentId !== void 0 ? { scope: parentId, createdIn: parentId } : {}
1172
+ };
1173
+ const target = info.target;
1174
+ if (kind === "custom-element") {
1175
+ const defined = target ? classSource(target.constructor) : void 0;
1176
+ if (defined) node.declaredAt = defined;
1177
+ } else if (site && !site.external) {
1178
+ node.usedAt = mapped(site.location);
1179
+ }
1180
+ scopeIds.set(scope, id);
1181
+ if (target && typeof target === "object" && target.nodeType === 1) {
1182
+ rendered.set(id, [new WeakRef(target)]);
1183
+ }
1184
+ graph.set(id, node);
1185
+ history.created(id, node.createdIn, node.label);
1186
+ if (target && typeof target === "object") {
1187
+ scopeOfTarget.set(target, id);
1188
+ for (const field of fieldsOf.get(target) ?? []) {
1189
+ const made = graph.get(field);
1190
+ if (!made) continue;
1191
+ made.scope = id;
1192
+ made.createdIn = id;
1193
+ revs.set(field, ++revision);
1194
+ }
1195
+ }
1196
+ },
1197
+ scopeEnded(scope) {
1198
+ const id = scopeIds.get(scope);
1199
+ if (id === void 0) return;
1200
+ const ended = /* @__PURE__ */ new Set([id]);
1201
+ for (let grew = true; grew; ) {
1202
+ grew = false;
1203
+ for (const [other, node] of graph) {
1204
+ if (!ended.has(other) && node.scope !== void 0 && ended.has(node.scope)) {
1205
+ ended.add(other);
1206
+ grew = true;
1207
+ }
1208
+ }
1209
+ }
1210
+ for (const gone of ended) forget(gone);
1211
+ },
1212
+ scopeAdopted(scope, parent) {
1213
+ const node = graph.get(scopeIds.get(scope) ?? -1);
1214
+ const parentId = scopeIds.get(parent);
1215
+ if (!node || parentId === void 0 || parentId === node.id) return;
1216
+ node.scope = parentId;
1217
+ node.createdIn = parentId;
1218
+ revs.set(node.id, ++revision);
1089
1219
  }
1090
1220
  });
1221
+ function forget(id) {
1222
+ removed.push({ id, rev: ++revision });
1223
+ revs.delete(id);
1224
+ if (removed.length > REMOVED_LOG) removed.splice(0, removed.length - REMOVED_LOG);
1225
+ history.disposed(id, graph.get(id)?.label);
1226
+ graph.delete(id);
1227
+ handed.delete(id);
1228
+ raws.delete(id);
1229
+ cores.delete(id);
1230
+ rendered.delete(id);
1231
+ setters.delete(id);
1232
+ runsAtLastSample.delete(id);
1233
+ unnamed.delete(id);
1234
+ }
1091
1235
  const edges = (id, node) => {
1092
1236
  const sources = cores.get(id)?.sources;
1093
1237
  node.deps.clear();
@@ -1107,6 +1251,14 @@ function observeGraph(options = {}) {
1107
1251
  revs.set(id, ++revision);
1108
1252
  };
1109
1253
  const now = Date.now();
1254
+ for (const [id, node] of graph) {
1255
+ if (node.kind !== "custom-element" || node.usedAt) continue;
1256
+ const element = rendered.get(id)?.[0]?.deref();
1257
+ const written = element ? element.__fx_loc : void 0;
1258
+ if (!written?.file) continue;
1259
+ node.usedAt = { file: written.file, line: written.line, column: written.column };
1260
+ revs.set(id, ++revision);
1261
+ }
1110
1262
  const bindings = /* @__PURE__ */ new Map();
1111
1263
  const drives = /* @__PURE__ */ new Map();
1112
1264
  const seen = /* @__PURE__ */ new Map();
@@ -1445,6 +1597,7 @@ function serializeGraph(graph, now = Date.now(), options = {}) {
1445
1597
  declaredAt: node.declaredAt,
1446
1598
  usedAt: node.usedAt,
1447
1599
  createdIn: node.createdIn,
1600
+ scope: node.scope,
1448
1601
  bindings: node.bindings,
1449
1602
  targets: node.targets,
1450
1603
  setAt: node.setAt,