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

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 (91) hide show
  1. package/dist/callsite.cjs +72 -0
  2. package/dist/callsite.d.ts +1 -1
  3. package/dist/callsite.js +1 -1
  4. package/dist/callsite.mjs +51 -0
  5. package/dist/change-view.cjs +134 -0
  6. package/dist/change-view.js +2 -2
  7. package/dist/change-view.mjs +111 -0
  8. package/dist/copy.cjs +63 -0
  9. package/dist/copy.mjs +42 -0
  10. package/dist/describe.cjs +55 -0
  11. package/dist/describe.js +2 -2
  12. package/dist/describe.mjs +34 -0
  13. package/dist/detail-panel.cjs +307 -0
  14. package/dist/detail-panel.d.ts +1 -1
  15. package/dist/detail-panel.d.ts.map +1 -1
  16. package/dist/detail-panel.js +1 -1
  17. package/dist/detail-panel.mjs +284 -0
  18. package/dist/diff.cjs +225 -0
  19. package/dist/diff.js +1 -1
  20. package/dist/diff.mjs +202 -0
  21. package/dist/dom.cjs +204 -0
  22. package/dist/dom.mjs +183 -0
  23. package/dist/export.cjs +221 -0
  24. package/dist/export.d.ts +2 -2
  25. package/dist/export.d.ts.map +1 -1
  26. package/dist/export.js +1 -1
  27. package/dist/export.mjs +209 -0
  28. package/dist/float.cjs +232 -0
  29. package/dist/float.d.ts +1 -1
  30. package/dist/float.js +3 -3
  31. package/dist/float.mjs +211 -0
  32. package/dist/format.cjs +175 -0
  33. package/dist/format.js +3 -3
  34. package/dist/format.mjs +154 -0
  35. package/dist/graph-view.cjs +893 -0
  36. package/dist/graph-view.mjs +870 -0
  37. package/dist/highlight.cjs +140 -0
  38. package/dist/highlight.mjs +119 -0
  39. package/dist/history.cjs +95 -0
  40. package/dist/history.d.ts +2 -2
  41. package/dist/history.js +2 -2
  42. package/dist/history.mjs +74 -0
  43. package/dist/hook.cjs +1562 -0
  44. package/dist/hook.d.ts +3 -3
  45. package/dist/hook.js +6 -6
  46. package/dist/hook.mjs +1553 -0
  47. package/dist/index.cjs +4552 -0
  48. package/dist/index.mjs +4544 -0
  49. package/dist/inspector.cjs +688 -0
  50. package/dist/inspector.d.ts +2 -2
  51. package/dist/inspector.js +7 -7
  52. package/dist/inspector.mjs +676 -0
  53. package/dist/instrument.cjs +497 -0
  54. package/dist/instrument.mjs +487 -0
  55. package/dist/kind-filter.cjs +172 -0
  56. package/dist/kind-filter.d.ts +2 -2
  57. package/dist/kind-filter.js +1 -1
  58. package/dist/kind-filter.mjs +151 -0
  59. package/dist/menu.cjs +141 -0
  60. package/dist/menu.mjs +120 -0
  61. package/dist/observe.cjs +1352 -0
  62. package/dist/observe.mjs +1345 -0
  63. package/dist/palette.cjs +52 -0
  64. package/dist/palette.mjs +31 -0
  65. package/dist/path.cjs +45 -0
  66. package/dist/path.d.ts +2 -2
  67. package/dist/path.js +2 -2
  68. package/dist/path.mjs +24 -0
  69. package/dist/plugin.cjs +87 -0
  70. package/dist/plugin.mjs +66 -0
  71. package/dist/plugins/context.cjs +98 -0
  72. package/dist/plugins/context.mjs +75 -0
  73. package/dist/plugins/directives.cjs +98 -0
  74. package/dist/plugins/directives.mjs +75 -0
  75. package/dist/plugins/index.cjs +162 -0
  76. package/dist/plugins/index.mjs +140 -0
  77. package/dist/source.cjs +111 -0
  78. package/dist/source.d.ts +2 -2
  79. package/dist/source.js +4 -4
  80. package/dist/source.mjs +90 -0
  81. package/dist/timeline.cjs +350 -0
  82. package/dist/timeline.js +3 -3
  83. package/dist/timeline.mjs +327 -0
  84. package/dist/tree.cjs +574 -0
  85. package/dist/tree.mjs +551 -0
  86. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  87. package/dist/value-pane.cjs +223 -0
  88. package/dist/value-pane.mjs +200 -0
  89. package/dist/wire.cjs +109 -0
  90. package/dist/wire.mjs +89 -0
  91. package/package.json +19 -6
@@ -0,0 +1,162 @@
1
+ /*! @fluixi/devtools v0.2.0-alpha.5 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/plugins/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ CONTEXT: () => NAME2,
25
+ DIRECTIVES: () => NAME,
26
+ contextPlugin: () => contextPlugin,
27
+ directivesPlugin: () => directivesPlugin
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/plugin.ts
32
+ var plugins = [];
33
+ function registerDevtoolsPlugin(plugin) {
34
+ const at = plugins.findIndex((p) => p.name === plugin.name);
35
+ if (at === -1) plugins.push(plugin);
36
+ else plugins[at] = plugin;
37
+ }
38
+
39
+ // src/plugins/directives.ts
40
+ var NAME = "directives";
41
+ function directivesOn(extra) {
42
+ return extra?.[NAME] ?? [];
43
+ }
44
+ function directiveBadge(notes) {
45
+ if (!notes.length) return void 0;
46
+ const first = notes[0];
47
+ const short = first.kind === "ref" ? "ref" : label(first);
48
+ return notes.length > 1 ? `${short} +${notes.length - 1}` : short;
49
+ }
50
+ function directiveRows(notes) {
51
+ return notes.map((note) => ({
52
+ label: label(note),
53
+ value: note.element,
54
+ ...note.at ? { at: note.at } : {}
55
+ }));
56
+ }
57
+ var label = (note) => note.kind === "ref" ? `ref ${note.name}` : `${note.kind}:${note.name}`;
58
+ var directivesPlugin = {
59
+ name: NAME,
60
+ collect(ctx) {
61
+ ctx.onDirective((report) => {
62
+ if (!report.target) return;
63
+ const held = ctx.elementAnnotation(report.target) ?? [];
64
+ const already = held.some((n) => n.kind === report.kind && n.name === report.name);
65
+ if (already) return;
66
+ held.push({
67
+ kind: report.kind,
68
+ name: report.name,
69
+ element: report.element,
70
+ ...report.at ? { at: report.at } : {}
71
+ });
72
+ ctx.annotateElement(report.target, held);
73
+ });
74
+ },
75
+ rows(node) {
76
+ const notes = node.extra?.[NAME];
77
+ if (!notes?.length) return [];
78
+ return notes.map((note) => ({
79
+ label: label(note),
80
+ value: note.element,
81
+ ...note.at ? { at: note.at } : {}
82
+ }));
83
+ },
84
+ elementRows(extra) {
85
+ return directiveRows(directivesOn(extra));
86
+ },
87
+ elementBadge(extra) {
88
+ return directiveBadge(directivesOn(extra));
89
+ },
90
+ badge(node) {
91
+ const notes = node.extra?.[NAME];
92
+ if (!notes?.length) return void 0;
93
+ const first = notes[0];
94
+ const short = first.kind === "ref" ? "ref" : label(first);
95
+ return notes.length > 1 ? `${short} +${notes.length - 1}` : short;
96
+ }
97
+ };
98
+ registerDevtoolsPlugin(directivesPlugin);
99
+
100
+ // src/format.ts
101
+ function shorten(text, limit = 18) {
102
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
103
+ }
104
+
105
+ // src/plugins/context.ts
106
+ var NAME2 = "context";
107
+ var contextPlugin = {
108
+ name: NAME2,
109
+ collect(ctx) {
110
+ const nodes = /* @__PURE__ */ new Map();
111
+ ctx.onContext((report) => {
112
+ if (report.owner === void 0) return;
113
+ let node = nodes.get(report.id);
114
+ if (node === void 0) {
115
+ const label2 = report.name === "context" && report.ownerLabel ? `${report.ownerLabel} context` : report.name;
116
+ node = ctx.add({
117
+ label: label2,
118
+ kind: "context",
119
+ // A context is created at module scope with nothing running, so the only line it
120
+ // can carry is the one that provided or read it.
121
+ ...report.at ? { source: report.at } : {},
122
+ // The router's own contexts are the framework's, and belong in its card rather
123
+ // than beside the ones the application wrote.
124
+ authored: report.at?.external !== true,
125
+ // Under whoever provided it. A context read with no provider above it belongs to
126
+ // the reader, which is the honest place for a default value.
127
+ createdIn: report.owner,
128
+ // Short on the card, whole in the inspector, the way every other node works.
129
+ ...report.value !== void 0 ? { value: shorten(report.value), detail: report.value } : {}
130
+ });
131
+ nodes.set(report.id, node);
132
+ }
133
+ if (report.kind === "provide") ctx.retype(report.owner, "provider");
134
+ const held = ctx.annotation(report.owner) ?? [];
135
+ const already = held.some((n) => n.name === report.name && n.kind === report.kind);
136
+ if (already) return;
137
+ held.push({
138
+ name: report.name,
139
+ kind: report.kind,
140
+ ...report.value !== void 0 ? { value: report.value } : {}
141
+ });
142
+ ctx.annotate(report.owner, held);
143
+ });
144
+ },
145
+ rows(node) {
146
+ const notes = node.extra?.[NAME2];
147
+ if (!notes?.length) return [];
148
+ return notes.map((note) => ({
149
+ label: note.kind === "provide" ? `provides ${note.name}` : `reads ${note.name}`,
150
+ ...note.value !== void 0 ? { value: note.value } : {}
151
+ }));
152
+ },
153
+ badge(node) {
154
+ const notes = node.extra?.[NAME2];
155
+ if (!notes?.length) return void 0;
156
+ const given = notes.filter((n) => n.kind === "provide");
157
+ if (given.length === 1) return `provides ${given[0].name}`;
158
+ if (given.length > 1) return `provides ${given.length}`;
159
+ return notes.length === 1 ? `reads ${notes[0].name}` : `reads ${notes.length}`;
160
+ }
161
+ };
162
+ registerDevtoolsPlugin(contextPlugin);
@@ -0,0 +1,140 @@
1
+ /*! @fluixi/devtools v0.2.0-alpha.5 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+
3
+ // src/plugin.ts
4
+ var plugins = [];
5
+ function registerDevtoolsPlugin(plugin) {
6
+ const at = plugins.findIndex((p) => p.name === plugin.name);
7
+ if (at === -1) plugins.push(plugin);
8
+ else plugins[at] = plugin;
9
+ }
10
+
11
+ // src/plugins/directives.ts
12
+ var NAME = "directives";
13
+ function directivesOn(extra) {
14
+ return extra?.[NAME] ?? [];
15
+ }
16
+ function directiveBadge(notes) {
17
+ if (!notes.length) return void 0;
18
+ const first = notes[0];
19
+ const short = first.kind === "ref" ? "ref" : label(first);
20
+ return notes.length > 1 ? `${short} +${notes.length - 1}` : short;
21
+ }
22
+ function directiveRows(notes) {
23
+ return notes.map((note) => ({
24
+ label: label(note),
25
+ value: note.element,
26
+ ...note.at ? { at: note.at } : {}
27
+ }));
28
+ }
29
+ var label = (note) => note.kind === "ref" ? `ref ${note.name}` : `${note.kind}:${note.name}`;
30
+ var directivesPlugin = {
31
+ name: NAME,
32
+ collect(ctx) {
33
+ ctx.onDirective((report) => {
34
+ if (!report.target) return;
35
+ const held = ctx.elementAnnotation(report.target) ?? [];
36
+ const already = held.some((n) => n.kind === report.kind && n.name === report.name);
37
+ if (already) return;
38
+ held.push({
39
+ kind: report.kind,
40
+ name: report.name,
41
+ element: report.element,
42
+ ...report.at ? { at: report.at } : {}
43
+ });
44
+ ctx.annotateElement(report.target, held);
45
+ });
46
+ },
47
+ rows(node) {
48
+ const notes = node.extra?.[NAME];
49
+ if (!notes?.length) return [];
50
+ return notes.map((note) => ({
51
+ label: label(note),
52
+ value: note.element,
53
+ ...note.at ? { at: note.at } : {}
54
+ }));
55
+ },
56
+ elementRows(extra) {
57
+ return directiveRows(directivesOn(extra));
58
+ },
59
+ elementBadge(extra) {
60
+ return directiveBadge(directivesOn(extra));
61
+ },
62
+ badge(node) {
63
+ const notes = node.extra?.[NAME];
64
+ if (!notes?.length) return void 0;
65
+ const first = notes[0];
66
+ const short = first.kind === "ref" ? "ref" : label(first);
67
+ return notes.length > 1 ? `${short} +${notes.length - 1}` : short;
68
+ }
69
+ };
70
+ registerDevtoolsPlugin(directivesPlugin);
71
+
72
+ // src/format.ts
73
+ function shorten(text, limit = 18) {
74
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
75
+ }
76
+
77
+ // src/plugins/context.ts
78
+ var NAME2 = "context";
79
+ var contextPlugin = {
80
+ name: NAME2,
81
+ collect(ctx) {
82
+ const nodes = /* @__PURE__ */ new Map();
83
+ ctx.onContext((report) => {
84
+ if (report.owner === void 0) return;
85
+ let node = nodes.get(report.id);
86
+ if (node === void 0) {
87
+ const label2 = report.name === "context" && report.ownerLabel ? `${report.ownerLabel} context` : report.name;
88
+ node = ctx.add({
89
+ label: label2,
90
+ kind: "context",
91
+ // A context is created at module scope with nothing running, so the only line it
92
+ // can carry is the one that provided or read it.
93
+ ...report.at ? { source: report.at } : {},
94
+ // The router's own contexts are the framework's, and belong in its card rather
95
+ // than beside the ones the application wrote.
96
+ authored: report.at?.external !== true,
97
+ // Under whoever provided it. A context read with no provider above it belongs to
98
+ // the reader, which is the honest place for a default value.
99
+ createdIn: report.owner,
100
+ // Short on the card, whole in the inspector, the way every other node works.
101
+ ...report.value !== void 0 ? { value: shorten(report.value), detail: report.value } : {}
102
+ });
103
+ nodes.set(report.id, node);
104
+ }
105
+ if (report.kind === "provide") ctx.retype(report.owner, "provider");
106
+ const held = ctx.annotation(report.owner) ?? [];
107
+ const already = held.some((n) => n.name === report.name && n.kind === report.kind);
108
+ if (already) return;
109
+ held.push({
110
+ name: report.name,
111
+ kind: report.kind,
112
+ ...report.value !== void 0 ? { value: report.value } : {}
113
+ });
114
+ ctx.annotate(report.owner, held);
115
+ });
116
+ },
117
+ rows(node) {
118
+ const notes = node.extra?.[NAME2];
119
+ if (!notes?.length) return [];
120
+ return notes.map((note) => ({
121
+ label: note.kind === "provide" ? `provides ${note.name}` : `reads ${note.name}`,
122
+ ...note.value !== void 0 ? { value: note.value } : {}
123
+ }));
124
+ },
125
+ badge(node) {
126
+ const notes = node.extra?.[NAME2];
127
+ if (!notes?.length) return void 0;
128
+ const given = notes.filter((n) => n.kind === "provide");
129
+ if (given.length === 1) return `provides ${given[0].name}`;
130
+ if (given.length > 1) return `provides ${given.length}`;
131
+ return notes.length === 1 ? `reads ${notes[0].name}` : `reads ${notes.length}`;
132
+ }
133
+ };
134
+ registerDevtoolsPlugin(contextPlugin);
135
+ export {
136
+ NAME2 as CONTEXT,
137
+ NAME as DIRECTIVES,
138
+ contextPlugin,
139
+ directivesPlugin
140
+ };
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/source.ts
21
+ var source_exports = {};
22
+ __export(source_exports, {
23
+ componentSource: () => componentSource,
24
+ holeLocation: () => holeLocation,
25
+ installSourceMarker: () => installSourceMarker,
26
+ markComponentSource: () => markComponentSource,
27
+ markReactiveSource: () => markReactiveSource,
28
+ propsLocations: () => propsLocations,
29
+ takeReactiveSource: () => takeReactiveSource
30
+ });
31
+ module.exports = __toCommonJS(source_exports);
32
+ var MARKER = "__fx_source";
33
+ var COMPONENT_MARKER = "__fx_component";
34
+ var HOLE_MARKER = "__fx_hole";
35
+ var PROPS_MARKER = "__fx_props";
36
+ var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
37
+ var host = globalThis;
38
+ var shared = host[MARKS] ?? {
39
+ pending: null,
40
+ expiring: false,
41
+ components: /* @__PURE__ */ new Map()
42
+ };
43
+ host[MARKS] = shared;
44
+ function markReactiveSource(file, line, column, name) {
45
+ const location = locate(file, line, column);
46
+ if (shared.pending && location.external && !shared.pending.location?.external) return;
47
+ shared.pending = { name, location };
48
+ shared.expiring = false;
49
+ }
50
+ function locate(file, line, column) {
51
+ const external = !!file && (/^([a-zA-Z]:)?[\\/]/.test(file) || file.includes("node_modules/"));
52
+ return external ? { file, line, column, external } : { file, line, column };
53
+ }
54
+ function markComponentSource(name, file, line, column) {
55
+ const seen = shared.components.get(name);
56
+ const next = locate(file, line, column);
57
+ if (seen === void 0) {
58
+ shared.components.set(name, next);
59
+ return;
60
+ }
61
+ if (!seen || seen.file !== file || seen.line !== line) shared.components.set(name, null);
62
+ }
63
+ function componentSource(name) {
64
+ return shared.components.get(name) ?? void 0;
65
+ }
66
+ function takeReactiveSource() {
67
+ const mark = shared.pending;
68
+ if (mark) {
69
+ if (mark.name !== void 0) shared.pending = { location: mark.location };
70
+ if (!shared.expiring) {
71
+ shared.expiring = true;
72
+ queueMicrotask(() => {
73
+ shared.expiring = false;
74
+ shared.pending = null;
75
+ });
76
+ }
77
+ }
78
+ return mark;
79
+ }
80
+ var HOLES = /* @__PURE__ */ new WeakMap();
81
+ var HOLE_TAG = "__fx_at";
82
+ function markHole(accessor, line, column, name) {
83
+ if (accessor && (typeof accessor === "object" || typeof accessor === "function")) {
84
+ const at = name === void 0 ? { line, column } : { line, column, name };
85
+ HOLES.set(accessor, at);
86
+ try {
87
+ Object.defineProperty(accessor, HOLE_TAG, { value: at, configurable: true });
88
+ } catch {
89
+ }
90
+ }
91
+ shared.pending = null;
92
+ return accessor;
93
+ }
94
+ var PROPS = /* @__PURE__ */ new WeakMap();
95
+ function markProps(props, at) {
96
+ if (props && typeof props === "object") PROPS.set(props, at);
97
+ return props;
98
+ }
99
+ function propsLocations(props) {
100
+ return props && typeof props === "object" ? PROPS.get(props) : void 0;
101
+ }
102
+ function holeLocation(accessor) {
103
+ if (!accessor || typeof accessor !== "object" && typeof accessor !== "function") return void 0;
104
+ return HOLES.get(accessor) ?? accessor[HOLE_TAG];
105
+ }
106
+ function installSourceMarker() {
107
+ if (typeof host[MARKER] !== "function") host[MARKER] = markReactiveSource;
108
+ if (typeof host[COMPONENT_MARKER] !== "function") host[COMPONENT_MARKER] = markComponentSource;
109
+ if (typeof host[HOLE_MARKER] !== "function") host[HOLE_MARKER] = markHole;
110
+ if (typeof host[PROPS_MARKER] !== "function") host[PROPS_MARKER] = markProps;
111
+ }
package/dist/source.d.ts CHANGED
@@ -25,7 +25,7 @@ export interface ReactiveSourceLocation {
25
25
  *
26
26
  * Both are worth having. The original says which component and which file; the compiled one
27
27
  * says which of that component's bindings, because a template's holes all map back to the
28
- * position the template opens at one entry per emitted root is all the map has. Until
28
+ * position the template opens at: one entry per emitted root is all the map has. Until
29
29
  * that changes, the compiled line is the only thing that tells two bindings apart.
30
30
  */
31
31
  compiled?: {
@@ -42,7 +42,7 @@ export interface ReactiveSourceMetadata {
42
42
  * Where each component was declared, by name.
43
43
  *
44
44
  * The graph sees the memo the compiler wraps a component in, and all that memo carries back
45
- * is the name stamped on what the component returned so name is the only key available.
45
+ * is the name stamped on what the component returned, so name is the only key available.
46
46
  * Two components sharing a name are recorded as ambiguous and reported as unknown, since a
47
47
  * location pointing at the wrong file is worse than none.
48
48
  */
package/dist/source.js CHANGED
@@ -25,7 +25,7 @@ host[MARKS] = shared;
25
25
  * Where each component was declared, by name.
26
26
  *
27
27
  * The graph sees the memo the compiler wraps a component in, and all that memo carries back
28
- * is the name stamped on what the component returned so name is the only key available.
28
+ * is the name stamped on what the component returned, so name is the only key available.
29
29
  * Two components sharing a name are recorded as ambiguous and reported as unknown, since a
30
30
  * location pointing at the wrong file is worse than none.
31
31
  */
@@ -79,7 +79,7 @@ export function takeReactiveSource() {
79
79
  const mark = shared.pending;
80
80
  if (mark) {
81
81
  // The variable name belongs to the node the author was declaring, not to the ones the
82
- // framework built underneath it `cart`, then two unnamed signals at the same line.
82
+ // framework built underneath it: `cart`, then two unnamed signals at the same line.
83
83
  if (mark.name !== undefined)
84
84
  shared.pending = { location: mark.location };
85
85
  if (!shared.expiring) {
@@ -117,8 +117,8 @@ function markHole(accessor, line, column, name) {
117
117
  }
118
118
  }
119
119
  // The template is being built, so whatever declaration left a mark is finished with. A
120
- // mark outlives the statement that set it on purpose a store's key signals are made
121
- // inside the call and belong to its line but a component body is one long synchronous
120
+ // mark outlives the statement that set it on purpose, a store's key signals are made
121
+ // inside the call and belong to its line: but a component body is one long synchronous
122
122
  // run, and without this every node the template makes claimed the last signal's position.
123
123
  shared.pending = null;
124
124
  return accessor;
@@ -0,0 +1,90 @@
1
+ // src/source.ts
2
+ var MARKER = "__fx_source";
3
+ var COMPONENT_MARKER = "__fx_component";
4
+ var HOLE_MARKER = "__fx_hole";
5
+ var PROPS_MARKER = "__fx_props";
6
+ var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
7
+ var host = globalThis;
8
+ var shared = host[MARKS] ?? {
9
+ pending: null,
10
+ expiring: false,
11
+ components: /* @__PURE__ */ new Map()
12
+ };
13
+ host[MARKS] = shared;
14
+ function markReactiveSource(file, line, column, name) {
15
+ const location = locate(file, line, column);
16
+ if (shared.pending && location.external && !shared.pending.location?.external) return;
17
+ shared.pending = { name, location };
18
+ shared.expiring = false;
19
+ }
20
+ function locate(file, line, column) {
21
+ const external = !!file && (/^([a-zA-Z]:)?[\\/]/.test(file) || file.includes("node_modules/"));
22
+ return external ? { file, line, column, external } : { file, line, column };
23
+ }
24
+ function markComponentSource(name, file, line, column) {
25
+ const seen = shared.components.get(name);
26
+ const next = locate(file, line, column);
27
+ if (seen === void 0) {
28
+ shared.components.set(name, next);
29
+ return;
30
+ }
31
+ if (!seen || seen.file !== file || seen.line !== line) shared.components.set(name, null);
32
+ }
33
+ function componentSource(name) {
34
+ return shared.components.get(name) ?? void 0;
35
+ }
36
+ function takeReactiveSource() {
37
+ const mark = shared.pending;
38
+ if (mark) {
39
+ if (mark.name !== void 0) shared.pending = { location: mark.location };
40
+ if (!shared.expiring) {
41
+ shared.expiring = true;
42
+ queueMicrotask(() => {
43
+ shared.expiring = false;
44
+ shared.pending = null;
45
+ });
46
+ }
47
+ }
48
+ return mark;
49
+ }
50
+ var HOLES = /* @__PURE__ */ new WeakMap();
51
+ var HOLE_TAG = "__fx_at";
52
+ function markHole(accessor, line, column, name) {
53
+ if (accessor && (typeof accessor === "object" || typeof accessor === "function")) {
54
+ const at = name === void 0 ? { line, column } : { line, column, name };
55
+ HOLES.set(accessor, at);
56
+ try {
57
+ Object.defineProperty(accessor, HOLE_TAG, { value: at, configurable: true });
58
+ } catch {
59
+ }
60
+ }
61
+ shared.pending = null;
62
+ return accessor;
63
+ }
64
+ var PROPS = /* @__PURE__ */ new WeakMap();
65
+ function markProps(props, at) {
66
+ if (props && typeof props === "object") PROPS.set(props, at);
67
+ return props;
68
+ }
69
+ function propsLocations(props) {
70
+ return props && typeof props === "object" ? PROPS.get(props) : void 0;
71
+ }
72
+ function holeLocation(accessor) {
73
+ if (!accessor || typeof accessor !== "object" && typeof accessor !== "function") return void 0;
74
+ return HOLES.get(accessor) ?? accessor[HOLE_TAG];
75
+ }
76
+ function installSourceMarker() {
77
+ if (typeof host[MARKER] !== "function") host[MARKER] = markReactiveSource;
78
+ if (typeof host[COMPONENT_MARKER] !== "function") host[COMPONENT_MARKER] = markComponentSource;
79
+ if (typeof host[HOLE_MARKER] !== "function") host[HOLE_MARKER] = markHole;
80
+ if (typeof host[PROPS_MARKER] !== "function") host[PROPS_MARKER] = markProps;
81
+ }
82
+ export {
83
+ componentSource,
84
+ holeLocation,
85
+ installSourceMarker,
86
+ markComponentSource,
87
+ markReactiveSource,
88
+ propsLocations,
89
+ takeReactiveSource
90
+ };