@treelocator/runtime 0.1.8 → 0.3.0

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 (58) hide show
  1. package/dist/adapters/createTreeNode.js +41 -4
  2. package/dist/adapters/nextjs/parseNextjsDataAttributes.d.ts +31 -0
  3. package/dist/adapters/nextjs/parseNextjsDataAttributes.js +106 -0
  4. package/dist/adapters/phoenix/__tests__/parsePhoenixComments.test.d.ts +4 -0
  5. package/dist/adapters/phoenix/__tests__/parsePhoenixComments.test.js +218 -0
  6. package/dist/adapters/phoenix/detectPhoenix.d.ts +11 -0
  7. package/dist/adapters/phoenix/detectPhoenix.js +38 -0
  8. package/dist/adapters/phoenix/index.d.ts +10 -0
  9. package/dist/adapters/phoenix/index.js +9 -0
  10. package/dist/adapters/phoenix/parsePhoenixComments.d.ts +35 -0
  11. package/dist/adapters/phoenix/parsePhoenixComments.js +131 -0
  12. package/dist/adapters/phoenix/types.d.ts +16 -0
  13. package/dist/adapters/phoenix/types.js +1 -0
  14. package/dist/adapters/react/findDebugSource.d.ts +13 -0
  15. package/dist/adapters/react/findDebugSource.js +37 -0
  16. package/dist/adapters/react/findFiberByHtmlElement.js +23 -1
  17. package/dist/adapters/react/getFiberLabel.js +2 -1
  18. package/dist/adapters/react/resolveSourceMap.d.ts +29 -0
  19. package/dist/adapters/react/resolveSourceMap.js +236 -0
  20. package/dist/browserApi.d.ts +4 -4
  21. package/dist/browserApi.js +13 -15
  22. package/dist/components/MaybeOutline.js +65 -3
  23. package/dist/components/Runtime.js +13 -0
  24. package/dist/functions/enrichAncestrySourceMaps.d.ts +7 -0
  25. package/dist/functions/enrichAncestrySourceMaps.js +80 -0
  26. package/dist/functions/formatAncestryChain.d.ts +3 -0
  27. package/dist/functions/formatAncestryChain.js +104 -15
  28. package/dist/functions/formatAncestryChain.test.js +26 -20
  29. package/dist/functions/normalizeFilePath.d.ts +14 -0
  30. package/dist/functions/normalizeFilePath.js +40 -0
  31. package/dist/output.css +87 -15
  32. package/dist/types/ServerComponentInfo.d.ts +14 -0
  33. package/dist/types/ServerComponentInfo.js +1 -0
  34. package/package.json +4 -3
  35. package/src/adapters/createTreeNode.ts +44 -3
  36. package/src/adapters/nextjs/parseNextjsDataAttributes.ts +112 -0
  37. package/src/adapters/phoenix/__tests__/parsePhoenixComments.test.ts +264 -0
  38. package/src/adapters/phoenix/detectPhoenix.ts +44 -0
  39. package/src/adapters/phoenix/index.ts +11 -0
  40. package/src/adapters/phoenix/parsePhoenixComments.ts +140 -0
  41. package/src/adapters/phoenix/types.ts +16 -0
  42. package/src/adapters/react/findDebugSource.ts +40 -0
  43. package/src/adapters/react/findFiberByHtmlElement.ts +26 -1
  44. package/src/adapters/react/getFiberLabel.ts +2 -1
  45. package/src/adapters/react/reactAdapter.ts +2 -1
  46. package/src/adapters/react/resolveSourceMap.ts +316 -0
  47. package/src/browserApi.ts +27 -25
  48. package/src/components/MaybeOutline.tsx +63 -4
  49. package/src/components/Runtime.tsx +15 -0
  50. package/src/functions/enrichAncestrySourceMaps.ts +103 -0
  51. package/src/functions/formatAncestryChain.test.ts +26 -20
  52. package/src/functions/formatAncestryChain.ts +121 -15
  53. package/src/functions/normalizeFilePath.ts +41 -0
  54. package/src/types/ServerComponentInfo.ts +14 -0
  55. package/.turbo/turbo-build.log +0 -30
  56. package/.turbo/turbo-test.log +0 -19
  57. package/.turbo/turbo-ts.log +0 -4
  58. package/LICENSE +0 -22
@@ -0,0 +1,103 @@
1
+ import { AncestryItem } from "./formatAncestryChain";
2
+ import { resolveSourceLocation, parseDebugStack } from "../adapters/react/resolveSourceMap";
3
+ import { normalizeFilePath } from "./normalizeFilePath";
4
+
5
+ /**
6
+ * Check if any DOM element has React 19 fibers (with _debugStack instead of _debugSource).
7
+ */
8
+ function isReact19Environment(): boolean {
9
+ const el = document.querySelector("[class]") || document.body;
10
+ if (!el) return false;
11
+
12
+ const fiberKey = Object.keys(el).find((k) => k.startsWith("__reactFiber$"));
13
+ if (!fiberKey) return false;
14
+
15
+ const fiber = (el as any)[fiberKey];
16
+ return !fiber?._debugSource && !!(fiber as any)?._debugStack;
17
+ }
18
+
19
+ /**
20
+ * Walk a fiber's _debugOwner chain and collect _debugStack stack traces for each component.
21
+ * Returns a map from component name to its parsed stack location.
22
+ */
23
+ function collectFiberStacks(
24
+ element: HTMLElement
25
+ ): Map<string, { url: string; line: number; column: number }> {
26
+ const stacks = new Map<string, { url: string; line: number; column: number }>();
27
+
28
+ const fiberKey = Object.keys(element).find((k) =>
29
+ k.startsWith("__reactFiber$")
30
+ );
31
+ if (!fiberKey) return stacks;
32
+
33
+ let fiber = (element as any)[fiberKey];
34
+
35
+ // Collect stacks from the fiber itself and its _debugOwner chain
36
+ while (fiber) {
37
+ const debugStack = fiber._debugStack;
38
+ if (debugStack?.stack) {
39
+ const parsed = parseDebugStack(debugStack.stack);
40
+ if (parsed) {
41
+ const name =
42
+ fiber.type?.name || fiber.type?.displayName || fiber.type;
43
+ if (typeof name === "string") {
44
+ stacks.set(name, parsed);
45
+ }
46
+ }
47
+ }
48
+ fiber = fiber._debugOwner || null;
49
+ }
50
+
51
+ return stacks;
52
+ }
53
+
54
+ /**
55
+ * Enrich ancestry items that are missing filePath by resolving via source maps.
56
+ * This is an async operation that fetches source maps for React 19 environments.
57
+ * For React 18 (where _debugSource exists), this is a no-op.
58
+ */
59
+ export async function enrichAncestryWithSourceMaps(
60
+ items: AncestryItem[],
61
+ element?: HTMLElement
62
+ ): Promise<AncestryItem[]> {
63
+ // Skip if all items already have file paths, or not React 19
64
+ const needsEnrichment = items.some((item) => item.componentName && !item.filePath);
65
+ if (!needsEnrichment || !isReact19Environment()) {
66
+ return items;
67
+ }
68
+
69
+ // Collect _debugStack info from the DOM element's fiber chain
70
+ const stacks = element ? collectFiberStacks(element) : new Map();
71
+
72
+ // Resolve source maps in parallel for items missing filePath
73
+ const enriched = await Promise.all(
74
+ items.map(async (item) => {
75
+ if (item.filePath || !item.componentName) return item;
76
+
77
+ // Find the stack trace for this component
78
+ const stack = stacks.get(item.componentName);
79
+ if (!stack) return item;
80
+
81
+ try {
82
+ const source = await resolveSourceLocation(
83
+ stack.url,
84
+ stack.line,
85
+ stack.column
86
+ );
87
+ if (source) {
88
+ return {
89
+ ...item,
90
+ filePath: normalizeFilePath(source.fileName),
91
+ line: source.lineNumber,
92
+ };
93
+ }
94
+ } catch {
95
+ // Source map resolution failed — keep item as-is
96
+ }
97
+
98
+ return item;
99
+ })
100
+ );
101
+
102
+ return enriched;
103
+ }
@@ -6,46 +6,49 @@ import {
6
6
  } from "./formatAncestryChain";
7
7
 
8
8
  describe("formatAncestryChain", () => {
9
- it("formats basic ancestry without ID or nth-child", () => {
9
+ it("uses component name only at component boundaries", () => {
10
10
  const items: AncestryItem[] = [
11
11
  { elementName: "button", componentName: "Button" },
12
12
  { elementName: "div", componentName: "App" },
13
13
  ];
14
14
 
15
15
  const result = formatAncestryChain(items);
16
+ // App is root (component boundary), Button is different component (boundary)
16
17
  expect(result).toBe(
17
- `div in App
18
- └─ button in Button`
18
+ `App
19
+ └─ Button`
19
20
  );
20
21
  });
21
22
 
22
- it("includes ID when present", () => {
23
+ it("shows element name when same component as parent", () => {
23
24
  const items: AncestryItem[] = [
24
- { elementName: "button", componentName: "Button", id: "submit-btn" },
25
+ { elementName: "button", componentName: "App", id: "submit-btn" },
25
26
  { elementName: "div", componentName: "App" },
26
27
  ];
27
28
 
28
29
  const result = formatAncestryChain(items);
30
+ // Both are in App, so second item shows element name not component name
29
31
  expect(result).toBe(
30
- `div in App
31
- └─ button#submit-btn in Button`
32
+ `App
33
+ └─ button#submit-btn`
32
34
  );
33
35
  });
34
36
 
35
- it("includes nth-child when present", () => {
37
+ it("includes nth-child with component name at boundary", () => {
36
38
  const items: AncestryItem[] = [
37
39
  { elementName: "li", componentName: "ListItem", nthChild: 3 },
38
40
  { elementName: "ul", componentName: "List" },
39
41
  ];
40
42
 
41
43
  const result = formatAncestryChain(items);
44
+ // Different components = boundaries
42
45
  expect(result).toBe(
43
- `ul in List
44
- └─ li:nth-child(3) in ListItem`
46
+ `List
47
+ └─ ListItem:nth-child(3)`
45
48
  );
46
49
  });
47
50
 
48
- it("includes both nth-child and ID when present", () => {
51
+ it("includes both nth-child and ID at component boundary", () => {
49
52
  const items: AncestryItem[] = [
50
53
  {
51
54
  elementName: "li",
@@ -58,12 +61,12 @@ describe("formatAncestryChain", () => {
58
61
 
59
62
  const result = formatAncestryChain(items);
60
63
  expect(result).toBe(
61
- `ul in List
62
- └─ li:nth-child(2)#special-item in ListItem`
64
+ `List
65
+ └─ ListItem:nth-child(2)#special-item`
63
66
  );
64
67
  });
65
68
 
66
- it("includes file location when present", () => {
69
+ it("includes file location at component boundary", () => {
67
70
  const items: AncestryItem[] = [
68
71
  {
69
72
  elementName: "button",
@@ -75,7 +78,8 @@ describe("formatAncestryChain", () => {
75
78
  ];
76
79
 
77
80
  const result = formatAncestryChain(items);
78
- expect(result).toBe("button#save in Button at src/Button.tsx:42");
81
+ // First item is always a boundary (no previous item)
82
+ expect(result).toBe("Button#save at src/Button.tsx:42");
79
83
  });
80
84
 
81
85
  it("formats element without component name", () => {
@@ -92,7 +96,7 @@ describe("formatAncestryChain", () => {
92
96
  expect(result).toBe("");
93
97
  });
94
98
 
95
- it("shows all owner components when ownerComponents is provided", () => {
99
+ it("uses innermost component as display name with outer components in chain", () => {
96
100
  const items: AncestryItem[] = [
97
101
  {
98
102
  elementName: "div",
@@ -117,13 +121,14 @@ describe("formatAncestryChain", () => {
117
121
  ];
118
122
 
119
123
  const result = formatAncestryChain(items);
124
+ // GlassPanel (innermost) is the display name, Sidebar (outer) shown in "in"
120
125
  expect(result).toBe(
121
- `div in App at src/App.jsx:104
122
- └─ div#sidebar-panel in Sidebar > GlassPanel at src/components/game/Sidebar.jsx:78`
126
+ `App at src/App.jsx:104
127
+ └─ GlassPanel#sidebar-panel in Sidebar at src/components/game/Sidebar.jsx:78`
123
128
  );
124
129
  });
125
130
 
126
- it("shows single owner component without arrow when only one in chain", () => {
131
+ it("uses component name as display name when only one in chain", () => {
127
132
  const items: AncestryItem[] = [
128
133
  {
129
134
  elementName: "button",
@@ -135,6 +140,7 @@ describe("formatAncestryChain", () => {
135
140
  ];
136
141
 
137
142
  const result = formatAncestryChain(items);
138
- expect(result).toBe("button in Button at src/Button.tsx:10");
143
+ // Single component becomes the display name, no "in X" needed
144
+ expect(result).toBe("Button at src/Button.tsx:10");
139
145
  });
140
146
  });
@@ -1,4 +1,8 @@
1
1
  import { TreeNode, TreeNodeComponent, TreeNodeElement } from "../types/TreeNode";
2
+ import { ServerComponentInfo } from "../types/ServerComponentInfo";
3
+ import { parsePhoenixServerComponents } from "../adapters/phoenix/parsePhoenixComments";
4
+ import { parseNextjsServerComponents } from "../adapters/nextjs/parseNextjsDataAttributes";
5
+ import { normalizeFilePath } from "./normalizeFilePath";
2
6
 
3
7
  export interface OwnerComponentInfo {
4
8
  name: string;
@@ -15,6 +19,8 @@ export interface AncestryItem {
15
19
  nthChild?: number; // 1-indexed, only set when there are ambiguous siblings
16
20
  /** All owner components from outermost (Sidebar) to innermost (GlassPanel) */
17
21
  ownerComponents?: OwnerComponentInfo[];
22
+ /** Server-side components (Phoenix LiveView, Rails, Next.js RSC, etc.) */
23
+ serverComponents?: ServerComponentInfo[];
18
24
  }
19
25
 
20
26
  // Elements to exclude from ancestry (not useful for debugging)
@@ -49,7 +55,7 @@ function treeNodeComponentToOwnerInfo(
49
55
  ): OwnerComponentInfo {
50
56
  return {
51
57
  name: comp.label,
52
- filePath: comp.callLink?.fileName,
58
+ filePath: comp.callLink?.fileName ? normalizeFilePath(comp.callLink.fileName) : undefined,
53
59
  line: comp.callLink?.lineNumber,
54
60
  };
55
61
  }
@@ -82,6 +88,23 @@ export function collectAncestry(node: TreeNode): AncestryItem[] {
82
88
  if (nthChild !== undefined) {
83
89
  item.nthChild = nthChild;
84
90
  }
91
+
92
+ // Parse server components from various sources
93
+ // 1. Phoenix LiveView (HTML comments)
94
+ const phoenixComponents = parsePhoenixServerComponents(element);
95
+
96
+ // 2. Next.js Server Components (data-locatorjs attributes)
97
+ const nextjsComponents = parseNextjsServerComponents(element);
98
+
99
+ // Combine all server components
100
+ const allServerComponents = [
101
+ ...(phoenixComponents || []),
102
+ ...(nextjsComponents || []),
103
+ ];
104
+
105
+ if (allServerComponents.length > 0) {
106
+ item.serverComponents = allServerComponents;
107
+ }
85
108
  }
86
109
  }
87
110
 
@@ -93,7 +116,7 @@ export function collectAncestry(node: TreeNode): AncestryItem[] {
93
116
  // Use outermost component as the primary component name
94
117
  item.componentName = outermost.label;
95
118
  if (outermost.callLink) {
96
- item.filePath = outermost.callLink.fileName;
119
+ item.filePath = normalizeFilePath(outermost.callLink.fileName);
97
120
  item.line = outermost.callLink.lineNumber;
98
121
  }
99
122
  } else {
@@ -102,19 +125,19 @@ export function collectAncestry(node: TreeNode): AncestryItem[] {
102
125
  if (component) {
103
126
  item.componentName = component.label;
104
127
  if (component.callLink) {
105
- item.filePath = component.callLink.fileName;
128
+ item.filePath = normalizeFilePath(component.callLink.fileName);
106
129
  item.line = component.callLink.lineNumber;
107
130
  }
108
131
  }
109
132
  }
110
133
 
111
134
  if (!item.filePath && source) {
112
- item.filePath = source.fileName;
135
+ item.filePath = normalizeFilePath(source.fileName);
113
136
  item.line = source.lineNumber;
114
137
  }
115
138
 
116
- // Only include items that have useful info (component name or file path)
117
- if (item.componentName || item.filePath) {
139
+ // Only include items that have useful info (component name, file path, or server components)
140
+ if (item.componentName || item.filePath || item.serverComponents) {
118
141
  items.push(item);
119
142
  }
120
143
 
@@ -138,8 +161,36 @@ export function formatAncestryChain(items: AncestryItem[]): string {
138
161
  const indent = " ".repeat(index);
139
162
  const prefix = index === 0 ? "" : "└─ ";
140
163
 
141
- // Build element selector: elementName:nth-child(n)#id
142
- let selector = item.elementName;
164
+ // Get the previous item's component to detect component boundaries
165
+ const prevItem = index > 0 ? reversed[index - 1] : null;
166
+ const prevComponentName = prevItem?.componentName || prevItem?.ownerComponents?.[prevItem.ownerComponents.length - 1]?.name;
167
+
168
+ // Get current item's innermost component
169
+ const currentComponentName = item.ownerComponents?.[item.ownerComponents.length - 1]?.name || item.componentName;
170
+
171
+ // Determine the display name for the element
172
+ // Use component name ONLY when crossing a component boundary (root element of a component)
173
+ // This prevents "App -> App:nth-child(5)" when both are just elements inside App
174
+ let displayName = item.elementName;
175
+ let outerComponents: string[] = [];
176
+ const isComponentBoundary = currentComponentName && currentComponentName !== prevComponentName;
177
+
178
+ if (isComponentBoundary) {
179
+ if (item.ownerComponents && item.ownerComponents.length > 0) {
180
+ // Use innermost component as display name, show outer ones in "in X > Y"
181
+ const innermost = item.ownerComponents[item.ownerComponents.length - 1];
182
+ if (innermost) {
183
+ displayName = innermost.name;
184
+ // Outer components (excluding innermost)
185
+ outerComponents = item.ownerComponents.slice(0, -1).map((c) => c.name);
186
+ }
187
+ } else if (item.componentName) {
188
+ displayName = item.componentName;
189
+ }
190
+ }
191
+
192
+ // Build element selector: displayName:nth-child(n)#id
193
+ let selector = displayName;
143
194
  if (item.nthChild !== undefined) {
144
195
  selector += `:nth-child(${item.nthChild})`;
145
196
  }
@@ -149,15 +200,70 @@ export function formatAncestryChain(items: AncestryItem[]): string {
149
200
 
150
201
  let description = selector;
151
202
 
152
- // Show all owner components if available (Sidebar > GlassPanel)
153
- if (item.ownerComponents && item.ownerComponents.length > 0) {
154
- const componentChain = item.ownerComponents.map((c) => c.name).join(" > ");
155
- description = `${selector} in ${componentChain}`;
156
- } else if (item.componentName) {
157
- description = `${selector} in ${item.componentName}`;
203
+ // Build component description parts
204
+ const parts: string[] = [];
205
+
206
+ // Server components (Phoenix/Next.js/Rails/etc.)
207
+ if (item.serverComponents && item.serverComponents.length > 0) {
208
+ // Group server components by framework (detected by file extension)
209
+ const phoenixComponents = item.serverComponents.filter((sc) =>
210
+ sc.filePath.match(/\.(ex|exs|heex)$/)
211
+ );
212
+ const nextjsComponents = item.serverComponents.filter((sc) =>
213
+ sc.filePath.match(/\.(tsx?|jsx?)$/)
214
+ );
215
+
216
+ // Format Phoenix components
217
+ if (phoenixComponents.length > 0) {
218
+ const names = phoenixComponents
219
+ .filter((sc) => sc.type === "component")
220
+ .map((sc) => sc.name);
221
+ if (names.length > 0) {
222
+ parts.push(`[Phoenix: ${names.join(" > ")}]`);
223
+ }
224
+ }
225
+
226
+ // Format Next.js components
227
+ if (nextjsComponents.length > 0) {
228
+ const names = nextjsComponents
229
+ .filter((sc) => sc.type === "component")
230
+ .map((sc) => sc.name);
231
+ if (names.length > 0) {
232
+ parts.push(`[Next.js: ${names.join(" > ")}]`);
233
+ }
234
+ }
235
+ }
236
+
237
+ // Client components - show outer components for context (if any)
238
+ if (outerComponents.length > 0) {
239
+ parts.push(`in ${outerComponents.join(" > ")}`);
240
+ }
241
+
242
+ if (parts.length > 0) {
243
+ description = `${selector} ${parts.join(" ")}`;
244
+ }
245
+
246
+ // Build location string
247
+ const locationParts: string[] = [];
248
+
249
+ // Server component locations
250
+ if (item.serverComponents && item.serverComponents.length > 0) {
251
+ item.serverComponents.forEach((sc) => {
252
+ const prefix = sc.type === "caller" ? " (called from)" : "";
253
+ locationParts.push(`${sc.filePath}:${sc.line}${prefix}`);
254
+ });
255
+ }
256
+
257
+ // Client component location (only add if different from server components)
258
+ if (item.filePath) {
259
+ const clientLocation = `${item.filePath}:${item.line}`;
260
+ // Only add if this location isn't already in the list
261
+ if (!locationParts.includes(clientLocation)) {
262
+ locationParts.push(clientLocation);
263
+ }
158
264
  }
159
265
 
160
- const location = item.filePath ? ` at ${item.filePath}:${item.line}` : "";
266
+ const location = locationParts.length > 0 ? ` at ${locationParts.join(", ")}` : "";
161
267
 
162
268
  lines.push(`${indent}${prefix}${description}${location}`);
163
269
  });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Convert absolute file paths to relative paths for display.
3
+ *
4
+ * This ensures consistent path display across different sources:
5
+ * - React _debugSource may provide absolute paths
6
+ * - Next.js data-locatorjs attributes may have absolute paths
7
+ * - Phoenix comments use relative paths
8
+ *
9
+ * Examples:
10
+ * - "/Users/name/project/src/App.tsx" → "src/App.tsx"
11
+ * - "/workspace/apps/next-16/app/page.tsx" → "app/page.tsx"
12
+ * - "src/components/Button.tsx" → "src/components/Button.tsx" (unchanged)
13
+ */
14
+ export function normalizeFilePath(filePath: string): string {
15
+ // If it's already relative (doesn't start with /), return as-is
16
+ if (!filePath.startsWith("/")) {
17
+ return filePath;
18
+ }
19
+
20
+ // Find common project indicators to trim the path
21
+ const indicators = ["/app/", "/src/", "/pages/", "/components/", "/lib/"];
22
+
23
+ for (const indicator of indicators) {
24
+ const index = filePath.indexOf(indicator);
25
+ if (index !== -1) {
26
+ // Return from the indicator onwards (remove leading slash)
27
+ return filePath.substring(index + 1);
28
+ }
29
+ }
30
+
31
+ // If no indicator found, try to get just the last few path segments
32
+ const parts = filePath.split("/");
33
+
34
+ // Return last 3-4 segments if available (e.g., "apps/next-16/app/page.tsx")
35
+ if (parts.length > 3) {
36
+ return parts.slice(-4).join("/");
37
+ }
38
+
39
+ // Last resort: return as-is
40
+ return filePath;
41
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Represents a server-side component in the ancestry chain.
3
+ * Used for Phoenix LiveView, Rails ViewComponents, Next.js RSC, etc.
4
+ */
5
+ export interface ServerComponentInfo {
6
+ /** Component name (e.g., "AppWeb.CoreComponents.button") or "@caller" for call site */
7
+ name: string;
8
+ /** File path (e.g., "lib/app_web/core_components.ex") */
9
+ filePath: string;
10
+ /** Line number in the source file */
11
+ line: number;
12
+ /** Type of server component annotation */
13
+ type: "component" | "caller";
14
+ }
@@ -1,30 +0,0 @@
1
-
2
- > @treelocator/runtime@0.1.8 build /Users/wende/projects/locatorjs/packages/runtime
3
- > concurrently pnpm:build:*
4
-
5
- [tailwind]
6
- [tailwind] > @treelocator/runtime@0.1.8 build:tailwind /Users/wende/projects/locatorjs/packages/runtime
7
- [tailwind] > tailwindcss -i ./src/main.css -o ./dist/output.css
8
- [tailwind]
9
- [babel]
10
- [babel] > @treelocator/runtime@0.1.8 build:babel /Users/wende/projects/locatorjs/packages/runtime
11
- [babel] > babel src --out-dir dist --extensions .js,.jsx,.ts,.tsx
12
- [babel]
13
- [ts]
14
- [ts] > @treelocator/runtime@0.1.8 build:ts /Users/wende/projects/locatorjs/packages/runtime
15
- [ts] > tsc --declaration --emitDeclarationOnly --noEmit false --outDir dist
16
- [ts]
17
- [wrapImage]
18
- [wrapImage] > @treelocator/runtime@0.1.8 build:wrapImage /Users/wende/projects/locatorjs/packages/runtime
19
- [wrapImage] > node ./scripts/wrapImage.js
20
- [wrapImage]
21
- [wrapImage] Tree icon file generated
22
- [wrapImage] pnpm run build:wrapImage exited with code 0
23
- [tailwind]
24
- [tailwind] Rebuilding...
25
- [tailwind]
26
- [tailwind] Done in 164ms.
27
- [tailwind] pnpm run build:tailwind exited with code 0
28
- [babel] Successfully compiled 72 files with Babel (409ms).
29
- [babel] pnpm run build:babel exited with code 0
30
- [ts] pnpm run build:ts exited with code 0
@@ -1,19 +0,0 @@
1
-
2
- > @treelocator/runtime@0.1.5 test /Users/wende/projects/locatorjs/packages/runtime
3
- > vitest run
4
-
5
-
6
- RUN v2.1.9 /Users/wende/projects/locatorjs/packages/runtime
7
-
8
- ✓ src/functions/mergeRects.test.ts (1 test) 2ms
9
- ✓ src/functions/evalTemplate.test.ts (1 test) 2ms
10
- ✓ src/functions/transformPath.test.ts (3 tests) 3ms
11
- ✓ src/functions/getUsableFileName.test.tsx (4 tests) 3ms
12
- ✓ src/functions/formatAncestryChain.test.ts (7 tests) 2ms
13
- ✓ src/functions/cropPath.test.ts (2 tests) 2ms
14
-
15
- Test Files 6 passed (6)
16
- Tests 18 passed (18)
17
- Start at 17:17:22
18
- Duration 718ms (transform 282ms, setup 0ms, collect 336ms, tests 14ms, environment 1ms, prepare 463ms)
19
-
@@ -1,4 +0,0 @@
1
-
2
- > @locator/runtime@0.5.1 ts /Users/wende/projects/locatorjs/packages/runtime
3
- > tsc --noEmit
4
-
package/LICENSE DELETED
@@ -1,22 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Krzysztof Wende
4
- Copyright (c) 2023 Michael Musil (original LocatorJS)
5
-
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.