react-code-locator 0.1.8 → 0.1.12

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 (52) hide show
  1. package/README.md +49 -44
  2. package/dist/babel.cjs +427 -40
  3. package/dist/babel.cjs.map +1 -1
  4. package/dist/babel.d.cts +12 -1
  5. package/dist/babel.d.ts +12 -1
  6. package/dist/babel.js +424 -29
  7. package/dist/babel.js.map +1 -1
  8. package/dist/babelInjectComponentSource.cjs +403 -38
  9. package/dist/babelInjectComponentSource.cjs.map +1 -1
  10. package/dist/babelInjectComponentSource.d.cts +3 -4
  11. package/dist/babelInjectComponentSource.d.ts +3 -4
  12. package/dist/babelInjectComponentSource.js +403 -28
  13. package/dist/babelInjectComponentSource.js.map +1 -1
  14. package/dist/client-sm5wi0uT.d.cts +15 -0
  15. package/dist/client-sm5wi0uT.d.ts +15 -0
  16. package/dist/client.cjs +166 -27
  17. package/dist/client.cjs.map +1 -1
  18. package/dist/client.d.cts +1 -14
  19. package/dist/client.d.ts +1 -14
  20. package/dist/client.js +166 -27
  21. package/dist/client.js.map +1 -1
  22. package/dist/esbuild.cjs +615 -0
  23. package/dist/esbuild.cjs.map +1 -0
  24. package/dist/esbuild.d.cts +25 -0
  25. package/dist/esbuild.d.ts +25 -0
  26. package/dist/esbuild.js +588 -0
  27. package/dist/esbuild.js.map +1 -0
  28. package/dist/index.cjs +833 -29
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +9 -1
  31. package/dist/index.d.ts +9 -1
  32. package/dist/index.js +820 -28
  33. package/dist/index.js.map +1 -1
  34. package/dist/sourceAdapter-DLWo_ABo.d.cts +15 -0
  35. package/dist/sourceAdapter-DLWo_ABo.d.ts +15 -0
  36. package/dist/swc.cjs +588 -0
  37. package/dist/swc.cjs.map +1 -0
  38. package/dist/swc.d.cts +29 -0
  39. package/dist/swc.d.ts +29 -0
  40. package/dist/swc.js +559 -0
  41. package/dist/swc.js.map +1 -0
  42. package/dist/vite.cjs +525 -84
  43. package/dist/vite.cjs.map +1 -1
  44. package/dist/vite.d.cts +20 -6
  45. package/dist/vite.d.ts +20 -6
  46. package/dist/vite.js +520 -72
  47. package/dist/vite.js.map +1 -1
  48. package/dist/webpackRuntimeEntry.cjs +166 -27
  49. package/dist/webpackRuntimeEntry.cjs.map +1 -1
  50. package/dist/webpackRuntimeEntry.js +166 -27
  51. package/dist/webpackRuntimeEntry.js.map +1 -1
  52. package/package.json +12 -1
@@ -1,5 +1,65 @@
1
1
  // src/constants.ts
2
2
  var SOURCE_PROP = "__componentSourceLoc";
3
+ var JSX_SOURCE_PROP = "$componentSourceLoc";
4
+ var JSX_SOURCE_REGISTRY_SYMBOL = "react-code-locator.jsxSourceRegistry";
5
+
6
+ // src/sourceMetadata.ts
7
+ function normalizeSlashes(value) {
8
+ return value.replace(/\\/g, "/");
9
+ }
10
+ function trimTrailingSlash(value) {
11
+ return value.replace(/\/+$/, "");
12
+ }
13
+ function splitPathSegments(value) {
14
+ return normalizeSlashes(value).split("/").filter(Boolean);
15
+ }
16
+ function computeRelativePath(fromPath, toPath) {
17
+ const fromSegments = splitPathSegments(fromPath);
18
+ const toSegments = splitPathSegments(toPath);
19
+ let sharedIndex = 0;
20
+ while (sharedIndex < fromSegments.length && sharedIndex < toSegments.length && fromSegments[sharedIndex] === toSegments[sharedIndex]) {
21
+ sharedIndex += 1;
22
+ }
23
+ const upSegments = new Array(Math.max(0, fromSegments.length - sharedIndex)).fill("..");
24
+ const downSegments = toSegments.slice(sharedIndex);
25
+ const relativeSegments = [...upSegments, ...downSegments];
26
+ return relativeSegments.length > 0 ? relativeSegments.join("/") : ".";
27
+ }
28
+ function normalizeProjectRoot(projectRoot) {
29
+ if (projectRoot) {
30
+ return trimTrailingSlash(normalizeSlashes(projectRoot));
31
+ }
32
+ if (typeof process !== "undefined" && typeof process.cwd === "function") {
33
+ return trimTrailingSlash(normalizeSlashes(process.cwd()));
34
+ }
35
+ return "";
36
+ }
37
+ function getSourceFile(source) {
38
+ if (!source) {
39
+ return null;
40
+ }
41
+ const match = source.match(/^(.*):\d+:\d+$/);
42
+ return match?.[1] ?? null;
43
+ }
44
+ function isProjectLocalFile(filename, projectRoot) {
45
+ if (!filename) {
46
+ return false;
47
+ }
48
+ const root = normalizeProjectRoot(projectRoot);
49
+ const normalizedFilename = normalizeSlashes(filename);
50
+ if (!root) {
51
+ return !normalizedFilename.startsWith("../") && !normalizedFilename.startsWith("/") && !/^[A-Za-z]:\//.test(normalizedFilename);
52
+ }
53
+ if (normalizedFilename.startsWith(`${root}/`) || normalizedFilename === root) {
54
+ return true;
55
+ }
56
+ const relativePath = computeRelativePath(root, normalizedFilename);
57
+ return !relativePath.startsWith("../");
58
+ }
59
+ function isProjectLocalSource(source, projectRoot) {
60
+ const file = getSourceFile(source);
61
+ return isProjectLocalFile(file ?? void 0, projectRoot);
62
+ }
3
63
 
4
64
  // src/runtime.ts
5
65
  function isTriggerPressed(event, triggerKey) {
@@ -47,19 +107,17 @@ function getSourceFromType(type) {
47
107
  return typeof source === "string" ? source : null;
48
108
  }
49
109
  function getSourceFromProps(props) {
50
- const source = props?.[SOURCE_PROP];
51
- return typeof source === "string" ? source : null;
52
- }
53
- function resolveJsxSourceFromFiber(fiber) {
54
- let current = fiber;
55
- while (current) {
56
- const source = getSourceFromProps(current.pendingProps) ?? getSourceFromProps(current.memoizedProps);
57
- if (source) {
58
- return source;
110
+ if (props && typeof props === "object") {
111
+ const registry = globalThis[Symbol.for(JSX_SOURCE_REGISTRY_SYMBOL)];
112
+ if (registry instanceof WeakMap) {
113
+ const intrinsicSource = registry.get(props);
114
+ if (typeof intrinsicSource === "string") {
115
+ return intrinsicSource;
116
+ }
59
117
  }
60
- current = current.return ?? null;
61
118
  }
62
- return null;
119
+ const source = props?.[JSX_SOURCE_PROP];
120
+ return typeof source === "string" ? source : null;
63
121
  }
64
122
  function resolveComponentSourceFromFiber(fiber) {
65
123
  let current = fiber;
@@ -72,24 +130,76 @@ function resolveComponentSourceFromFiber(fiber) {
72
130
  }
73
131
  return null;
74
132
  }
75
- function getDebugSource(fiber) {
133
+ function getDirectDebugSource(fiber) {
134
+ const debugSource = fiber?._debugSource;
135
+ if (debugSource?.fileName && typeof debugSource.lineNumber === "number") {
136
+ return `${debugSource.fileName.replace(/\\/g, "/")}:${debugSource.lineNumber}:${debugSource.columnNumber ?? 1}`;
137
+ }
138
+ return null;
139
+ }
140
+ function resolveSourceCandidates(fiber) {
76
141
  let current = fiber;
142
+ const jsxCandidates = [];
143
+ const componentCandidates = [];
77
144
  while (current) {
78
- const debugSource = current._debugSource;
79
- if (debugSource?.fileName && typeof debugSource.lineNumber === "number") {
80
- return `${debugSource.fileName.replace(/\\/g, "/")}:${debugSource.lineNumber}:${debugSource.columnNumber ?? 1}`;
145
+ const jsxSource = getSourceFromProps(current.pendingProps) ?? getSourceFromProps(current.memoizedProps) ?? getDirectDebugSource(current);
146
+ if (jsxSource) {
147
+ const file = getSourceFile(jsxSource);
148
+ if (file && !jsxCandidates.some((candidate) => candidate.source === jsxSource)) {
149
+ jsxCandidates.push({ source: jsxSource, file });
150
+ }
151
+ }
152
+ const componentSource = getSourceFromType(current.type) ?? getSourceFromType(current.elementType);
153
+ if (componentSource) {
154
+ const file = getSourceFile(componentSource);
155
+ if (file && !componentCandidates.some((candidate) => candidate.source === componentSource)) {
156
+ componentCandidates.push({ source: componentSource, file });
157
+ }
81
158
  }
82
159
  current = current.return ?? null;
83
160
  }
84
- return null;
161
+ const direct = jsxCandidates[0]?.source ?? null;
162
+ const nearestProjectLocalComponentFile = componentCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.file;
163
+ let screen = null;
164
+ if (nearestProjectLocalComponentFile) {
165
+ const matchingJsxCandidate = jsxCandidates.find((candidate) => candidate.file === nearestProjectLocalComponentFile);
166
+ if (matchingJsxCandidate) {
167
+ screen = matchingJsxCandidate.source;
168
+ } else {
169
+ const matchingComponentCandidate = componentCandidates.find(
170
+ (candidate) => candidate.file === nearestProjectLocalComponentFile
171
+ );
172
+ if (matchingComponentCandidate) {
173
+ screen = matchingComponentCandidate.source;
174
+ }
175
+ }
176
+ }
177
+ const implementationComponentCandidate = componentCandidates.find((candidate) => !isProjectLocalSource(candidate.source))?.source ?? null;
178
+ const implementationJsxCandidate = jsxCandidates.find((candidate) => !isProjectLocalSource(candidate.source))?.source ?? null;
179
+ const projectLocalJsxCandidate = jsxCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.source ?? null;
180
+ const screenFallback = screen ?? projectLocalJsxCandidate ?? componentCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.source ?? null;
181
+ return {
182
+ direct: direct ?? screenFallback,
183
+ screen: screenFallback,
184
+ implementation: implementationComponentCandidate ?? implementationJsxCandidate ?? screenFallback
185
+ };
186
+ }
187
+ function getModeDescription(mode) {
188
+ if (mode === "direct") {
189
+ return "Direct JSX";
190
+ }
191
+ if (mode === "screen") {
192
+ return "Screen source";
193
+ }
194
+ return "Implementation source";
85
195
  }
86
196
  function createStatusOverlay(triggerKey) {
87
197
  if (typeof document === "undefined") {
88
198
  return null;
89
199
  }
90
200
  const element = document.createElement("div");
91
- let currentText = "";
92
201
  let copyValue = null;
202
+ let currentMode = "screen";
93
203
  let hideTimer = null;
94
204
  element.setAttribute("data-react-code-locator", "true");
95
205
  Object.assign(element.style, {
@@ -113,7 +223,6 @@ function createStatusOverlay(triggerKey) {
113
223
  transition: "opacity 120ms ease"
114
224
  });
115
225
  const show = (message, tone) => {
116
- currentText = message;
117
226
  element.textContent = message;
118
227
  element.style.background = tone === "success" ? "rgba(6, 95, 70, 0.92)" : tone === "error" ? "rgba(153, 27, 27, 0.94)" : "rgba(17, 24, 39, 0.92)";
119
228
  element.style.opacity = "1";
@@ -124,7 +233,7 @@ function createStatusOverlay(triggerKey) {
124
233
  hideTimer = setTimeout(() => {
125
234
  element.style.opacity = "0";
126
235
  element.style.pointerEvents = "none";
127
- }, 1500);
236
+ }, 2e3);
128
237
  };
129
238
  element.addEventListener("click", async () => {
130
239
  if (!copyValue) {
@@ -137,7 +246,7 @@ function createStatusOverlay(triggerKey) {
137
246
  show(`[react-code-locator] copy failed`, "error");
138
247
  }
139
248
  });
140
- show(`[react-code-locator] enabled (${triggerKey}+click)`, "idle");
249
+ show(`[react-code-locator] enabled (${triggerKey}+click, alt+1/2/3 to switch mode)`, "idle");
141
250
  const mount = () => {
142
251
  if (!element.isConnected && document.body) {
143
252
  document.body.appendChild(element);
@@ -155,6 +264,10 @@ function createStatusOverlay(triggerKey) {
155
264
  setCopyValue(value) {
156
265
  copyValue = value;
157
266
  },
267
+ setMode(mode) {
268
+ currentMode = mode;
269
+ show(`[react-code-locator] ${getModeDescription(mode)}`, "idle");
270
+ },
158
271
  remove() {
159
272
  if (hideTimer) {
160
273
  clearTimeout(hideTimer);
@@ -163,17 +276,18 @@ function createStatusOverlay(triggerKey) {
163
276
  }
164
277
  };
165
278
  }
166
- function locateComponentSource(target) {
279
+ function locateComponentSource(target, mode = "screen") {
167
280
  const elementTarget = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
168
281
  const fiber = getClosestReactFiber(elementTarget);
169
282
  if (!fiber) {
170
283
  return null;
171
284
  }
172
- const jsxSource = resolveJsxSourceFromFiber(fiber) ?? getDebugSource(fiber);
173
- if (jsxSource) {
285
+ const candidates = resolveSourceCandidates(fiber);
286
+ const source = candidates[mode] ?? candidates.screen ?? candidates.direct ?? candidates.implementation;
287
+ if (source) {
174
288
  return {
175
- source: jsxSource,
176
- mode: "jsx"
289
+ source,
290
+ mode
177
291
  };
178
292
  }
179
293
  const componentSource = resolveComponentSourceFromFiber(fiber);
@@ -182,11 +296,12 @@ function locateComponentSource(target) {
182
296
  }
183
297
  return {
184
298
  source: componentSource,
185
- mode: "component"
299
+ mode
186
300
  };
187
301
  }
188
302
  function enableReactComponentJump(options = {}) {
189
303
  const overlay = createStatusOverlay(options.triggerKey ?? "shift");
304
+ let currentMode = "screen";
190
305
  const {
191
306
  triggerKey = "shift",
192
307
  onLocate = (result) => {
@@ -202,6 +317,28 @@ function enableReactComponentJump(options = {}) {
202
317
  }
203
318
  } = options;
204
319
  console.log("[react-code-locator] enabled", { triggerKey });
320
+ const keyHandler = (event) => {
321
+ if (!event.altKey) {
322
+ return;
323
+ }
324
+ if (event.code === "Digit1") {
325
+ currentMode = "direct";
326
+ overlay?.setMode(currentMode);
327
+ event.preventDefault();
328
+ return;
329
+ }
330
+ if (event.code === "Digit2") {
331
+ currentMode = "screen";
332
+ overlay?.setMode(currentMode);
333
+ event.preventDefault();
334
+ return;
335
+ }
336
+ if (event.code === "Digit3") {
337
+ currentMode = "implementation";
338
+ overlay?.setMode(currentMode);
339
+ event.preventDefault();
340
+ }
341
+ };
205
342
  const handler = (event) => {
206
343
  console.log("[react-code-locator] click", {
207
344
  triggerKey,
@@ -214,7 +351,7 @@ function enableReactComponentJump(options = {}) {
214
351
  if (!isTriggerPressed(event, triggerKey)) {
215
352
  return;
216
353
  }
217
- const result = locateComponentSource(event.target);
354
+ const result = locateComponentSource(event.target, currentMode);
218
355
  if (!result) {
219
356
  onError(new Error("No React component source metadata found for clicked element."));
220
357
  return;
@@ -224,8 +361,10 @@ function enableReactComponentJump(options = {}) {
224
361
  onLocate(result);
225
362
  };
226
363
  document.addEventListener("click", handler, true);
364
+ document.addEventListener("keydown", keyHandler, true);
227
365
  return () => {
228
366
  document.removeEventListener("click", handler, true);
367
+ document.removeEventListener("keydown", keyHandler, true);
229
368
  overlay?.remove();
230
369
  };
231
370
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/runtime.ts","../src/webpackRuntimeEntry.ts"],"sourcesContent":["export const SOURCE_PROP = \"__componentSourceLoc\";\n\n","import { SOURCE_PROP } from \"./constants\";\n\nexport type TriggerKey = \"alt\" | \"meta\" | \"ctrl\" | \"shift\" | \"none\";\n\ntype ReactFiber = {\n return?: ReactFiber | null;\n type?: unknown;\n elementType?: unknown;\n pendingProps?: Record<string, unknown> | null;\n memoizedProps?: Record<string, unknown> | null;\n _debugSource?: {\n fileName?: string;\n lineNumber?: number;\n columnNumber?: number;\n } | null;\n};\n\nexport type LocatorResult = {\n source: string;\n mode: \"jsx\" | \"component\";\n};\n\nexport type LocatorOptions = {\n triggerKey?: TriggerKey;\n onLocate?: (result: LocatorResult) => void;\n onError?: (error: unknown) => void;\n};\n\ntype StatusOverlay = {\n setStatus: (message: string, tone?: \"idle\" | \"success\" | \"error\") => void;\n setCopyValue: (value: string | null) => void;\n remove: () => void;\n};\n\nfunction isTriggerPressed(event: MouseEvent, triggerKey: TriggerKey) {\n if (triggerKey === \"none\") {\n return true;\n }\n\n if (triggerKey === \"alt\") {\n return event.altKey;\n }\n\n if (triggerKey === \"meta\") {\n return event.metaKey;\n }\n\n if (triggerKey === \"ctrl\") {\n return event.ctrlKey;\n }\n\n return event.shiftKey;\n}\n\nfunction getReactFiberKey(element: Element) {\n return Object.keys(element).find((key) => key.startsWith(\"__reactFiber$\") || key.startsWith(\"__reactInternalInstance$\"));\n}\n\nfunction getClosestReactFiber(target: Element | null) {\n let current = target;\n\n while (current) {\n const fiberKey = getReactFiberKey(current);\n if (fiberKey) {\n return (current as unknown as Record<string, unknown>)[fiberKey] as ReactFiber;\n }\n\n current = current.parentElement;\n }\n\n return null;\n}\n\nfunction getSourceFromType(type: unknown) {\n if (!type) {\n return null;\n }\n\n if (typeof type === \"function\") {\n const source = (type as unknown as Record<string, unknown>)[SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n }\n\n if (typeof type !== \"object\") {\n return null;\n }\n\n const record = type as {\n type?: Record<string, unknown>;\n render?: Record<string, unknown>;\n [SOURCE_PROP]?: unknown;\n };\n\n const source = record[SOURCE_PROP] ?? record.type?.[SOURCE_PROP] ?? record.render?.[SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n}\n\nfunction getSourceFromProps(props: Record<string, unknown> | null | undefined) {\n const source = props?.[SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n}\n\nfunction resolveJsxSourceFromFiber(fiber: ReactFiber | null) {\n let current = fiber;\n\n while (current) {\n const source = getSourceFromProps(current.pendingProps) ?? getSourceFromProps(current.memoizedProps);\n if (source) {\n return source;\n }\n\n current = current.return ?? null;\n }\n\n return null;\n}\n\nfunction resolveComponentSourceFromFiber(fiber: ReactFiber | null) {\n let current = fiber;\n\n while (current) {\n const source = getSourceFromType(current.type) ?? getSourceFromType(current.elementType);\n if (source) {\n return source;\n }\n\n current = current.return ?? null;\n }\n\n return null;\n}\n\nfunction getDebugSource(fiber: ReactFiber | null) {\n let current = fiber;\n\n while (current) {\n const debugSource = current._debugSource;\n if (debugSource?.fileName && typeof debugSource.lineNumber === \"number\") {\n return `${debugSource.fileName.replace(/\\\\/g, \"/\")}:${debugSource.lineNumber}:${debugSource.columnNumber ?? 1}`;\n }\n\n current = current.return ?? null;\n }\n\n return null;\n}\n\nfunction createStatusOverlay(triggerKey: TriggerKey): StatusOverlay | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const element = document.createElement(\"div\");\n let currentText = \"\";\n let copyValue: string | null = null;\n let hideTimer: ReturnType<typeof setTimeout> | null = null;\n element.setAttribute(\"data-react-code-locator\", \"true\");\n Object.assign(element.style, {\n position: \"fixed\",\n right: \"12px\",\n bottom: \"12px\",\n zIndex: \"2147483647\",\n padding: \"8px 10px\",\n borderRadius: \"8px\",\n background: \"rgba(17, 24, 39, 0.92)\",\n color: \"#fff\",\n fontSize: \"12px\",\n lineHeight: \"1.4\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n boxShadow: \"0 8px 30px rgba(0, 0, 0, 0.25)\",\n pointerEvents: \"auto\",\n cursor: \"pointer\",\n maxWidth: \"min(70vw, 720px)\",\n wordBreak: \"break-all\",\n opacity: \"0\",\n transition: \"opacity 120ms ease\",\n });\n\n const show = (message: string, tone: \"idle\" | \"success\" | \"error\") => {\n currentText = message;\n element.textContent = message;\n element.style.background =\n tone === \"success\"\n ? \"rgba(6, 95, 70, 0.92)\"\n : tone === \"error\"\n ? \"rgba(153, 27, 27, 0.94)\"\n : \"rgba(17, 24, 39, 0.92)\";\n element.style.opacity = \"1\";\n element.style.pointerEvents = \"auto\";\n\n if (hideTimer) {\n clearTimeout(hideTimer);\n }\n\n hideTimer = setTimeout(() => {\n element.style.opacity = \"0\";\n element.style.pointerEvents = \"none\";\n }, 1500);\n };\n\n element.addEventListener(\"click\", async () => {\n if (!copyValue) {\n return;\n }\n\n try {\n await navigator.clipboard.writeText(copyValue);\n show(`[react-code-locator] copied`, \"success\");\n } catch {\n show(`[react-code-locator] copy failed`, \"error\");\n }\n });\n\n show(`[react-code-locator] enabled (${triggerKey}+click)`, \"idle\");\n\n const mount = () => {\n if (!element.isConnected && document.body) {\n document.body.appendChild(element);\n }\n };\n\n if (document.body) {\n mount();\n } else {\n document.addEventListener(\"DOMContentLoaded\", mount, { once: true });\n }\n\n return {\n setStatus(message, tone = \"idle\") {\n show(message, tone);\n },\n setCopyValue(value) {\n copyValue = value;\n },\n remove() {\n if (hideTimer) {\n clearTimeout(hideTimer);\n }\n element.remove();\n },\n };\n}\n\nexport function locateComponentSource(target: EventTarget | null): LocatorResult | null {\n const elementTarget =\n target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n const fiber = getClosestReactFiber(elementTarget);\n if (!fiber) {\n return null;\n }\n\n const jsxSource = resolveJsxSourceFromFiber(fiber) ?? getDebugSource(fiber);\n if (jsxSource) {\n return {\n source: jsxSource,\n mode: \"jsx\",\n };\n }\n\n const componentSource = resolveComponentSourceFromFiber(fiber);\n if (!componentSource) {\n return null;\n }\n\n return {\n source: componentSource,\n mode: \"component\",\n };\n}\n\nexport function enableReactComponentJump(options: LocatorOptions = {}) {\n const overlay = createStatusOverlay(options.triggerKey ?? \"shift\");\n const {\n triggerKey = \"shift\",\n onLocate = (result) => {\n console.log(`[react-code-locator] ${result.source}`);\n overlay?.setCopyValue(result.source);\n overlay?.setStatus(`[react-code-locator] ${result.source}`, \"success\");\n },\n onError = (error) => {\n console.error(\"[react-code-locator]\", error);\n const message = error instanceof Error ? error.message : String(error);\n overlay?.setCopyValue(null);\n overlay?.setStatus(`[react-code-locator] ${message}`, \"error\");\n },\n } = options;\n\n console.log(\"[react-code-locator] enabled\", { triggerKey });\n\n const handler = (event: MouseEvent) => {\n console.log(\"[react-code-locator] click\", {\n triggerKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n target: event.target,\n });\n\n if (!isTriggerPressed(event, triggerKey)) {\n return;\n }\n\n const result = locateComponentSource(event.target);\n if (!result) {\n onError(new Error(\"No React component source metadata found for clicked element.\"));\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n onLocate(result);\n };\n\n document.addEventListener(\"click\", handler, true);\n\n return () => {\n document.removeEventListener(\"click\", handler, true);\n overlay?.remove();\n };\n}\n","import { enableReactComponentJump } from \"./runtime\";\n\nif (typeof document !== \"undefined\") {\n enableReactComponentJump();\n}\n\n"],"mappings":"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","names":["source"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/sourceMetadata.ts","../src/runtime.ts","../src/webpackRuntimeEntry.ts"],"sourcesContent":["export const SOURCE_PROP = \"__componentSourceLoc\";\nexport const JSX_SOURCE_PROP = \"$componentSourceLoc\";\nexport const JSX_SOURCE_REGISTRY_SYMBOL = \"react-code-locator.jsxSourceRegistry\";\n","export type SourceLocation = {\n line: number;\n column: number;\n};\n\nfunction normalizeSlashes(value: string) {\n return value.replace(/\\\\/g, \"/\");\n}\n\nfunction trimTrailingSlash(value: string) {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction splitPathSegments(value: string) {\n return normalizeSlashes(value).split(\"/\").filter(Boolean);\n}\n\nfunction computeRelativePath(fromPath: string, toPath: string) {\n const fromSegments = splitPathSegments(fromPath);\n const toSegments = splitPathSegments(toPath);\n\n let sharedIndex = 0;\n while (\n sharedIndex < fromSegments.length &&\n sharedIndex < toSegments.length &&\n fromSegments[sharedIndex] === toSegments[sharedIndex]\n ) {\n sharedIndex += 1;\n }\n\n const upSegments = new Array(Math.max(0, fromSegments.length - sharedIndex)).fill(\"..\");\n const downSegments = toSegments.slice(sharedIndex);\n const relativeSegments = [...upSegments, ...downSegments];\n return relativeSegments.length > 0 ? relativeSegments.join(\"/\") : \".\";\n}\n\nexport function normalizeProjectRoot(projectRoot?: string) {\n if (projectRoot) {\n return trimTrailingSlash(normalizeSlashes(projectRoot));\n }\n\n if (typeof process !== \"undefined\" && typeof process.cwd === \"function\") {\n return trimTrailingSlash(normalizeSlashes(process.cwd()));\n }\n\n return \"\";\n}\n\nexport function toRelativeSource(\n filename: string | undefined,\n loc: SourceLocation | null | undefined,\n projectRoot?: string,\n) {\n if (!filename || !loc) {\n return null;\n }\n\n const root = normalizeProjectRoot(projectRoot);\n const normalizedFilename = normalizeSlashes(filename);\n const relPath =\n root && normalizedFilename.startsWith(`${root}/`)\n ? normalizedFilename.slice(root.length + 1)\n : root\n ? computeRelativePath(root, normalizedFilename)\n : normalizedFilename;\n return `${relPath}:${loc.line}:${loc.column + 1}`;\n}\n\nexport function getSourceFile(source: string | null) {\n if (!source) {\n return null;\n }\n\n const match = source.match(/^(.*):\\d+:\\d+$/);\n return match?.[1] ?? null;\n}\n\nexport function isProjectLocalFile(filename: string | undefined, projectRoot?: string) {\n if (!filename) {\n return false;\n }\n\n const root = normalizeProjectRoot(projectRoot);\n const normalizedFilename = normalizeSlashes(filename);\n\n if (!root) {\n return (\n !normalizedFilename.startsWith(\"../\") &&\n !normalizedFilename.startsWith(\"/\") &&\n !/^[A-Za-z]:\\//.test(normalizedFilename)\n );\n }\n\n if (normalizedFilename.startsWith(`${root}/`) || normalizedFilename === root) {\n return true;\n }\n\n const relativePath = computeRelativePath(root, normalizedFilename);\n return !relativePath.startsWith(\"../\");\n}\n\nexport function isExternalToProjectRoot(filename: string | undefined, projectRoot?: string) {\n return !isProjectLocalFile(filename, projectRoot);\n}\n\nexport function isProjectLocalSource(source: string, projectRoot?: string) {\n const file = getSourceFile(source);\n return isProjectLocalFile(file ?? undefined, projectRoot);\n}\n","import {\n JSX_SOURCE_PROP,\n JSX_SOURCE_REGISTRY_SYMBOL,\n SOURCE_PROP,\n} from \"./constants\";\nimport { getSourceFile, isProjectLocalSource } from \"./sourceMetadata\";\n\nexport type TriggerKey = \"alt\" | \"meta\" | \"ctrl\" | \"shift\" | \"none\";\nexport type LocatorMode = \"direct\" | \"screen\" | \"implementation\";\n\ntype ReactFiber = {\n return?: ReactFiber | null;\n type?: unknown;\n elementType?: unknown;\n pendingProps?: Record<string, unknown> | null;\n memoizedProps?: Record<string, unknown> | null;\n _debugOwner?: ReactFiber | null;\n _debugSource?: {\n fileName?: string;\n lineNumber?: number;\n columnNumber?: number;\n } | null;\n};\n\nexport type LocatorResult = {\n source: string;\n mode: LocatorMode;\n};\n\nexport type LocatorOptions = {\n triggerKey?: TriggerKey;\n onLocate?: (result: LocatorResult) => void;\n onError?: (error: unknown) => void;\n};\n\ntype StatusOverlay = {\n setStatus: (message: string, tone?: \"idle\" | \"success\" | \"error\") => void;\n setCopyValue: (value: string | null) => void;\n setMode: (mode: LocatorMode) => void;\n remove: () => void;\n};\n\nfunction isTriggerPressed(event: MouseEvent, triggerKey: TriggerKey) {\n if (triggerKey === \"none\") {\n return true;\n }\n\n if (triggerKey === \"alt\") {\n return event.altKey;\n }\n\n if (triggerKey === \"meta\") {\n return event.metaKey;\n }\n\n if (triggerKey === \"ctrl\") {\n return event.ctrlKey;\n }\n\n return event.shiftKey;\n}\n\nfunction getReactFiberKey(element: Element) {\n return Object.keys(element).find((key) => key.startsWith(\"__reactFiber$\") || key.startsWith(\"__reactInternalInstance$\"));\n}\n\nfunction getClosestReactFiber(target: Element | null) {\n let current = target;\n\n while (current) {\n const fiberKey = getReactFiberKey(current);\n if (fiberKey) {\n return (current as unknown as Record<string, unknown>)[fiberKey] as ReactFiber;\n }\n\n current = current.parentElement;\n }\n\n return null;\n}\n\nfunction getSourceFromType(type: unknown) {\n if (!type) {\n return null;\n }\n\n if (typeof type === \"function\") {\n const source = (type as unknown as Record<string, unknown>)[SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n }\n\n if (typeof type !== \"object\") {\n return null;\n }\n\n const record = type as {\n type?: Record<string, unknown>;\n render?: Record<string, unknown>;\n [SOURCE_PROP]?: unknown;\n };\n\n const source = record[SOURCE_PROP] ?? record.type?.[SOURCE_PROP] ?? record.render?.[SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n}\n\nfunction getSourceFromProps(props: Record<string, unknown> | null | undefined) {\n if (props && typeof props === \"object\") {\n const registry = (globalThis as Record<symbol, unknown>)[\n Symbol.for(JSX_SOURCE_REGISTRY_SYMBOL)\n ];\n if (registry instanceof WeakMap) {\n const intrinsicSource = registry.get(props as object);\n if (typeof intrinsicSource === \"string\") {\n return intrinsicSource;\n }\n }\n }\n\n const source = props?.[JSX_SOURCE_PROP];\n return typeof source === \"string\" ? source : null;\n}\n\nfunction resolveComponentSourceFromFiber(fiber: ReactFiber | null) {\n let current = fiber;\n\n while (current) {\n const source = getSourceFromType(current.type) ?? getSourceFromType(current.elementType);\n if (source) {\n return source;\n }\n\n current = current.return ?? null;\n }\n\n return null;\n}\n\nfunction getDirectDebugSource(fiber: ReactFiber | null) {\n const debugSource = fiber?._debugSource;\n if (debugSource?.fileName && typeof debugSource.lineNumber === \"number\") {\n return `${debugSource.fileName.replace(/\\\\/g, \"/\")}:${debugSource.lineNumber}:${debugSource.columnNumber ?? 1}`;\n }\n\n return null;\n}\n\ntype SourceCandidate = {\n source: string;\n file: string;\n};\n\ntype ResolvedCandidates = {\n direct: string | null;\n screen: string | null;\n implementation: string | null;\n};\n\nfunction resolveSourceCandidates(fiber: ReactFiber | null): ResolvedCandidates {\n let current = fiber;\n const jsxCandidates: SourceCandidate[] = [];\n const componentCandidates: SourceCandidate[] = [];\n\n while (current) {\n const jsxSource =\n getSourceFromProps(current.pendingProps) ?? getSourceFromProps(current.memoizedProps) ?? getDirectDebugSource(current);\n if (jsxSource) {\n const file = getSourceFile(jsxSource);\n if (file && !jsxCandidates.some((candidate) => candidate.source === jsxSource)) {\n jsxCandidates.push({ source: jsxSource, file });\n }\n }\n\n const componentSource = getSourceFromType(current.type) ?? getSourceFromType(current.elementType);\n if (componentSource) {\n const file = getSourceFile(componentSource);\n if (file && !componentCandidates.some((candidate) => candidate.source === componentSource)) {\n componentCandidates.push({ source: componentSource, file });\n }\n }\n\n current = current.return ?? null;\n }\n\n const direct = jsxCandidates[0]?.source ?? null;\n const nearestProjectLocalComponentFile = componentCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.file;\n let screen: string | null = null;\n if (nearestProjectLocalComponentFile) {\n const matchingJsxCandidate = jsxCandidates.find((candidate) => candidate.file === nearestProjectLocalComponentFile);\n if (matchingJsxCandidate) {\n screen = matchingJsxCandidate.source;\n } else {\n const matchingComponentCandidate = componentCandidates.find(\n (candidate) => candidate.file === nearestProjectLocalComponentFile,\n );\n if (matchingComponentCandidate) {\n screen = matchingComponentCandidate.source;\n }\n }\n }\n\n const implementationComponentCandidate =\n componentCandidates.find((candidate) => !isProjectLocalSource(candidate.source))?.source ?? null;\n const implementationJsxCandidate =\n jsxCandidates.find((candidate) => !isProjectLocalSource(candidate.source))?.source ?? null;\n\n const projectLocalJsxCandidate = jsxCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.source ?? null;\n const screenFallback = screen ?? projectLocalJsxCandidate ?? componentCandidates.find((candidate) => isProjectLocalSource(candidate.source))?.source ?? null;\n\n return {\n direct: direct ?? screenFallback,\n screen: screenFallback,\n implementation: implementationComponentCandidate ?? implementationJsxCandidate ?? screenFallback,\n };\n}\n\nfunction getModeDescription(mode: LocatorMode) {\n if (mode === \"direct\") {\n return \"Direct JSX\";\n }\n\n if (mode === \"screen\") {\n return \"Screen source\";\n }\n\n return \"Implementation source\";\n}\n\nfunction createStatusOverlay(triggerKey: TriggerKey): StatusOverlay | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const element = document.createElement(\"div\");\n let copyValue: string | null = null;\n let currentMode: LocatorMode = \"screen\";\n let hideTimer: ReturnType<typeof setTimeout> | null = null;\n element.setAttribute(\"data-react-code-locator\", \"true\");\n Object.assign(element.style, {\n position: \"fixed\",\n right: \"12px\",\n bottom: \"12px\",\n zIndex: \"2147483647\",\n padding: \"8px 10px\",\n borderRadius: \"8px\",\n background: \"rgba(17, 24, 39, 0.92)\",\n color: \"#fff\",\n fontSize: \"12px\",\n lineHeight: \"1.4\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n boxShadow: \"0 8px 30px rgba(0, 0, 0, 0.25)\",\n pointerEvents: \"auto\",\n cursor: \"pointer\",\n maxWidth: \"min(70vw, 720px)\",\n wordBreak: \"break-all\",\n opacity: \"0\",\n transition: \"opacity 120ms ease\",\n });\n\n const show = (message: string, tone: \"idle\" | \"success\" | \"error\") => {\n element.textContent = message;\n element.style.background =\n tone === \"success\"\n ? \"rgba(6, 95, 70, 0.92)\"\n : tone === \"error\"\n ? \"rgba(153, 27, 27, 0.94)\"\n : \"rgba(17, 24, 39, 0.92)\";\n element.style.opacity = \"1\";\n element.style.pointerEvents = \"auto\";\n\n if (hideTimer) {\n clearTimeout(hideTimer);\n }\n\n hideTimer = setTimeout(() => {\n element.style.opacity = \"0\";\n element.style.pointerEvents = \"none\";\n }, 2000);\n };\n\n element.addEventListener(\"click\", async () => {\n if (!copyValue) {\n return;\n }\n\n try {\n await navigator.clipboard.writeText(copyValue);\n show(`[react-code-locator] copied`, \"success\");\n } catch {\n show(`[react-code-locator] copy failed`, \"error\");\n }\n });\n\n show(`[react-code-locator] enabled (${triggerKey}+click, alt+1/2/3 to switch mode)`, \"idle\");\n\n const mount = () => {\n if (!element.isConnected && document.body) {\n document.body.appendChild(element);\n }\n };\n\n if (document.body) {\n mount();\n } else {\n document.addEventListener(\"DOMContentLoaded\", mount, { once: true });\n }\n\n return {\n setStatus(message, tone = \"idle\") {\n show(message, tone);\n },\n setCopyValue(value) {\n copyValue = value;\n },\n setMode(mode) {\n currentMode = mode;\n show(`[react-code-locator] ${getModeDescription(mode)}`, \"idle\");\n },\n remove() {\n if (hideTimer) {\n clearTimeout(hideTimer);\n }\n element.remove();\n },\n };\n}\n\nexport function locateComponentSource(target: EventTarget | null, mode: LocatorMode = \"screen\"): LocatorResult | null {\n const elementTarget =\n target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n const fiber = getClosestReactFiber(elementTarget);\n if (!fiber) {\n return null;\n }\n\n const candidates = resolveSourceCandidates(fiber);\n const source = candidates[mode] ?? candidates.screen ?? candidates.direct ?? candidates.implementation;\n if (source) {\n return {\n source,\n mode,\n };\n }\n\n const componentSource = resolveComponentSourceFromFiber(fiber);\n if (!componentSource) {\n return null;\n }\n\n return {\n source: componentSource,\n mode,\n };\n}\n\nexport function enableReactComponentJump(options: LocatorOptions = {}) {\n const overlay = createStatusOverlay(options.triggerKey ?? \"shift\");\n let currentMode: LocatorMode = \"screen\";\n const {\n triggerKey = \"shift\",\n onLocate = (result) => {\n console.log(`[react-code-locator] ${result.source}`);\n overlay?.setCopyValue(result.source);\n overlay?.setStatus(`[react-code-locator] ${result.source}`, \"success\");\n },\n onError = (error) => {\n console.error(\"[react-code-locator]\", error);\n const message = error instanceof Error ? error.message : String(error);\n overlay?.setCopyValue(null);\n overlay?.setStatus(`[react-code-locator] ${message}`, \"error\");\n },\n } = options;\n\n console.log(\"[react-code-locator] enabled\", { triggerKey });\n\n const keyHandler = (event: KeyboardEvent) => {\n if (!event.altKey) {\n return;\n }\n\n if (event.code === \"Digit1\") {\n currentMode = \"direct\";\n overlay?.setMode(currentMode);\n event.preventDefault();\n return;\n }\n\n if (event.code === \"Digit2\") {\n currentMode = \"screen\";\n overlay?.setMode(currentMode);\n event.preventDefault();\n return;\n }\n\n if (event.code === \"Digit3\") {\n currentMode = \"implementation\";\n overlay?.setMode(currentMode);\n event.preventDefault();\n }\n };\n\n const handler = (event: MouseEvent) => {\n console.log(\"[react-code-locator] click\", {\n triggerKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n target: event.target,\n });\n\n if (!isTriggerPressed(event, triggerKey)) {\n return;\n }\n\n const result = locateComponentSource(event.target, currentMode);\n if (!result) {\n onError(new Error(\"No React component source metadata found for clicked element.\"));\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n onLocate(result);\n };\n\n document.addEventListener(\"click\", handler, true);\n document.addEventListener(\"keydown\", keyHandler, true);\n\n return () => {\n document.removeEventListener(\"click\", handler, true);\n document.removeEventListener(\"keydown\", keyHandler, true);\n overlay?.remove();\n };\n}\n","import { enableReactComponentJump } from \"./runtime\";\n\nif (typeof document !== \"undefined\") {\n enableReactComponentJump();\n}\n\n"],"mappings":";AAAO,IAAM,cAAc;AACpB,IAAM,kBAAkB;AACxB,IAAM,6BAA6B;;;ACG1C,SAAS,iBAAiB,OAAe;AACvC,SAAO,MAAM,QAAQ,OAAO,GAAG;AACjC;AAEA,SAAS,kBAAkB,OAAe;AACxC,SAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;AAEA,SAAS,kBAAkB,OAAe;AACxC,SAAO,iBAAiB,KAAK,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D;AAEA,SAAS,oBAAoB,UAAkB,QAAgB;AAC7D,QAAM,eAAe,kBAAkB,QAAQ;AAC/C,QAAM,aAAa,kBAAkB,MAAM;AAE3C,MAAI,cAAc;AAClB,SACE,cAAc,aAAa,UAC3B,cAAc,WAAW,UACzB,aAAa,WAAW,MAAM,WAAW,WAAW,GACpD;AACA,mBAAe;AAAA,EACjB;AAEA,QAAM,aAAa,IAAI,MAAM,KAAK,IAAI,GAAG,aAAa,SAAS,WAAW,CAAC,EAAE,KAAK,IAAI;AACtF,QAAM,eAAe,WAAW,MAAM,WAAW;AACjD,QAAM,mBAAmB,CAAC,GAAG,YAAY,GAAG,YAAY;AACxD,SAAO,iBAAiB,SAAS,IAAI,iBAAiB,KAAK,GAAG,IAAI;AACpE;AAEO,SAAS,qBAAqB,aAAsB;AACzD,MAAI,aAAa;AACf,WAAO,kBAAkB,iBAAiB,WAAW,CAAC;AAAA,EACxD;AAEA,MAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,QAAQ,YAAY;AACvE,WAAO,kBAAkB,iBAAiB,QAAQ,IAAI,CAAC,CAAC;AAAA,EAC1D;AAEA,SAAO;AACT;AAsBO,SAAS,cAAc,QAAuB;AACnD,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,MAAM,gBAAgB;AAC3C,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEO,SAAS,mBAAmB,UAA8B,aAAsB;AACrF,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,qBAAqB,WAAW;AAC7C,QAAM,qBAAqB,iBAAiB,QAAQ;AAEpD,MAAI,CAAC,MAAM;AACT,WACE,CAAC,mBAAmB,WAAW,KAAK,KACpC,CAAC,mBAAmB,WAAW,GAAG,KAClC,CAAC,eAAe,KAAK,kBAAkB;AAAA,EAE3C;AAEA,MAAI,mBAAmB,WAAW,GAAG,IAAI,GAAG,KAAK,uBAAuB,MAAM;AAC5E,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,oBAAoB,MAAM,kBAAkB;AACjE,SAAO,CAAC,aAAa,WAAW,KAAK;AACvC;AAMO,SAAS,qBAAqB,QAAgB,aAAsB;AACzE,QAAM,OAAO,cAAc,MAAM;AACjC,SAAO,mBAAmB,QAAQ,QAAW,WAAW;AAC1D;;;AClEA,SAAS,iBAAiB,OAAmB,YAAwB;AACnE,MAAI,eAAe,QAAQ;AACzB,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,OAAO;AACxB,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,eAAe,QAAQ;AACzB,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,eAAe,QAAQ;AACzB,WAAO,MAAM;AAAA,EACf;AAEA,SAAO,MAAM;AACf;AAEA,SAAS,iBAAiB,SAAkB;AAC1C,SAAO,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,WAAW,eAAe,KAAK,IAAI,WAAW,0BAA0B,CAAC;AACzH;AAEA,SAAS,qBAAqB,QAAwB;AACpD,MAAI,UAAU;AAEd,SAAO,SAAS;AACd,UAAM,WAAW,iBAAiB,OAAO;AACzC,QAAI,UAAU;AACZ,aAAQ,QAA+C,QAAQ;AAAA,IACjE;AAEA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAe;AACxC,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAMA,UAAU,KAA4C,WAAW;AACvE,WAAO,OAAOA,YAAW,WAAWA,UAAS;AAAA,EAC/C;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS;AAMf,QAAM,SAAS,OAAO,WAAW,KAAK,OAAO,OAAO,WAAW,KAAK,OAAO,SAAS,WAAW;AAC/F,SAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAEA,SAAS,mBAAmB,OAAmD;AAC7E,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,WAAY,WAChB,OAAO,IAAI,0BAA0B,CACvC;AACA,QAAI,oBAAoB,SAAS;AAC/B,YAAM,kBAAkB,SAAS,IAAI,KAAe;AACpD,UAAI,OAAO,oBAAoB,UAAU;AACvC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,QAAQ,eAAe;AACtC,SAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAEA,SAAS,gCAAgC,OAA0B;AACjE,MAAI,UAAU;AAEd,SAAO,SAAS;AACd,UAAM,SAAS,kBAAkB,QAAQ,IAAI,KAAK,kBAAkB,QAAQ,WAAW;AACvF,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,cAAU,QAAQ,UAAU;AAAA,EAC9B;AAEA,SAAO;AACT;AAEA,SAAS,qBAAqB,OAA0B;AACtD,QAAM,cAAc,OAAO;AAC3B,MAAI,aAAa,YAAY,OAAO,YAAY,eAAe,UAAU;AACvE,WAAO,GAAG,YAAY,SAAS,QAAQ,OAAO,GAAG,CAAC,IAAI,YAAY,UAAU,IAAI,YAAY,gBAAgB,CAAC;AAAA,EAC/G;AAEA,SAAO;AACT;AAaA,SAAS,wBAAwB,OAA8C;AAC7E,MAAI,UAAU;AACd,QAAM,gBAAmC,CAAC;AAC1C,QAAM,sBAAyC,CAAC;AAEhD,SAAO,SAAS;AACd,UAAM,YACJ,mBAAmB,QAAQ,YAAY,KAAK,mBAAmB,QAAQ,aAAa,KAAK,qBAAqB,OAAO;AACvH,QAAI,WAAW;AACb,YAAM,OAAO,cAAc,SAAS;AACpC,UAAI,QAAQ,CAAC,cAAc,KAAK,CAAC,cAAc,UAAU,WAAW,SAAS,GAAG;AAC9E,sBAAc,KAAK,EAAE,QAAQ,WAAW,KAAK,CAAC;AAAA,MAChD;AAAA,IACF;AAEA,UAAM,kBAAkB,kBAAkB,QAAQ,IAAI,KAAK,kBAAkB,QAAQ,WAAW;AAChG,QAAI,iBAAiB;AACnB,YAAM,OAAO,cAAc,eAAe;AAC1C,UAAI,QAAQ,CAAC,oBAAoB,KAAK,CAAC,cAAc,UAAU,WAAW,eAAe,GAAG;AAC1F,4BAAoB,KAAK,EAAE,QAAQ,iBAAiB,KAAK,CAAC;AAAA,MAC5D;AAAA,IACF;AAEA,cAAU,QAAQ,UAAU;AAAA,EAC9B;AAEA,QAAM,SAAS,cAAc,CAAC,GAAG,UAAU;AAC3C,QAAM,mCAAmC,oBAAoB,KAAK,CAAC,cAAc,qBAAqB,UAAU,MAAM,CAAC,GAAG;AAC1H,MAAI,SAAwB;AAC5B,MAAI,kCAAkC;AACpC,UAAM,uBAAuB,cAAc,KAAK,CAAC,cAAc,UAAU,SAAS,gCAAgC;AAClH,QAAI,sBAAsB;AACxB,eAAS,qBAAqB;AAAA,IAChC,OAAO;AACL,YAAM,6BAA6B,oBAAoB;AAAA,QACrD,CAAC,cAAc,UAAU,SAAS;AAAA,MACpC;AACA,UAAI,4BAA4B;AAC9B,iBAAS,2BAA2B;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,mCACJ,oBAAoB,KAAK,CAAC,cAAc,CAAC,qBAAqB,UAAU,MAAM,CAAC,GAAG,UAAU;AAC9F,QAAM,6BACJ,cAAc,KAAK,CAAC,cAAc,CAAC,qBAAqB,UAAU,MAAM,CAAC,GAAG,UAAU;AAExF,QAAM,2BAA2B,cAAc,KAAK,CAAC,cAAc,qBAAqB,UAAU,MAAM,CAAC,GAAG,UAAU;AACtH,QAAM,iBAAiB,UAAU,4BAA4B,oBAAoB,KAAK,CAAC,cAAc,qBAAqB,UAAU,MAAM,CAAC,GAAG,UAAU;AAExJ,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB,QAAQ;AAAA,IACR,gBAAgB,oCAAoC,8BAA8B;AAAA,EACpF;AACF;AAEA,SAAS,mBAAmB,MAAmB;AAC7C,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,YAA8C;AACzE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,MAAI,YAA2B;AAC/B,MAAI,cAA2B;AAC/B,MAAI,YAAkD;AACtD,UAAQ,aAAa,2BAA2B,MAAM;AACtD,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,EACd,CAAC;AAED,QAAM,OAAO,CAAC,SAAiB,SAAuC;AACpE,YAAQ,cAAc;AACtB,YAAQ,MAAM,aACZ,SAAS,YACL,0BACA,SAAS,UACP,4BACA;AACR,YAAQ,MAAM,UAAU;AACxB,YAAQ,MAAM,gBAAgB;AAE9B,QAAI,WAAW;AACb,mBAAa,SAAS;AAAA,IACxB;AAEA,gBAAY,WAAW,MAAM;AAC3B,cAAQ,MAAM,UAAU;AACxB,cAAQ,MAAM,gBAAgB;AAAA,IAChC,GAAG,GAAI;AAAA,EACT;AAEA,UAAQ,iBAAiB,SAAS,YAAY;AAC5C,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,UAAU,UAAU,SAAS;AAC7C,WAAK,+BAA+B,SAAS;AAAA,IAC/C,QAAQ;AACN,WAAK,oCAAoC,OAAO;AAAA,IAClD;AAAA,EACF,CAAC;AAED,OAAK,iCAAiC,UAAU,qCAAqC,MAAM;AAE3F,QAAM,QAAQ,MAAM;AAClB,QAAI,CAAC,QAAQ,eAAe,SAAS,MAAM;AACzC,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AAAA,EACF;AAEA,MAAI,SAAS,MAAM;AACjB,UAAM;AAAA,EACR,OAAO;AACL,aAAS,iBAAiB,oBAAoB,OAAO,EAAE,MAAM,KAAK,CAAC;AAAA,EACrE;AAEA,SAAO;AAAA,IACL,UAAU,SAAS,OAAO,QAAQ;AAChC,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA,IACA,aAAa,OAAO;AAClB,kBAAY;AAAA,IACd;AAAA,IACA,QAAQ,MAAM;AACZ,oBAAc;AACd,WAAK,wBAAwB,mBAAmB,IAAI,CAAC,IAAI,MAAM;AAAA,IACjE;AAAA,IACA,SAAS;AACP,UAAI,WAAW;AACb,qBAAa,SAAS;AAAA,MACxB;AACA,cAAQ,OAAO;AAAA,IACjB;AAAA,EACF;AACF;AAEO,SAAS,sBAAsB,QAA4B,OAAoB,UAAgC;AACpH,QAAM,gBACJ,kBAAkB,UAAU,SAAS,kBAAkB,OAAO,OAAO,gBAAgB;AACvF,QAAM,QAAQ,qBAAqB,aAAa;AAChD,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,wBAAwB,KAAK;AAChD,QAAM,SAAS,WAAW,IAAI,KAAK,WAAW,UAAU,WAAW,UAAU,WAAW;AACxF,MAAI,QAAQ;AACV,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB,gCAAgC,KAAK;AAC7D,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,yBAAyB,UAA0B,CAAC,GAAG;AACrE,QAAM,UAAU,oBAAoB,QAAQ,cAAc,OAAO;AACjE,MAAI,cAA2B;AAC/B,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,WAAW,CAAC,WAAW;AACrB,cAAQ,IAAI,wBAAwB,OAAO,MAAM,EAAE;AACnD,eAAS,aAAa,OAAO,MAAM;AACnC,eAAS,UAAU,wBAAwB,OAAO,MAAM,IAAI,SAAS;AAAA,IACvE;AAAA,IACA,UAAU,CAAC,UAAU;AACnB,cAAQ,MAAM,wBAAwB,KAAK;AAC3C,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,eAAS,aAAa,IAAI;AAC1B,eAAS,UAAU,wBAAwB,OAAO,IAAI,OAAO;AAAA,IAC/D;AAAA,EACF,IAAI;AAEJ,UAAQ,IAAI,gCAAgC,EAAE,WAAW,CAAC;AAE1D,QAAM,aAAa,CAAC,UAAyB;AAC3C,QAAI,CAAC,MAAM,QAAQ;AACjB;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,UAAU;AAC3B,oBAAc;AACd,eAAS,QAAQ,WAAW;AAC5B,YAAM,eAAe;AACrB;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,UAAU;AAC3B,oBAAc;AACd,eAAS,QAAQ,WAAW;AAC5B,YAAM,eAAe;AACrB;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,UAAU;AAC3B,oBAAc;AACd,eAAS,QAAQ,WAAW;AAC5B,YAAM,eAAe;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,UAAsB;AACrC,YAAQ,IAAI,8BAA8B;AAAA,MACxC;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,iBAAiB,OAAO,UAAU,GAAG;AACxC;AAAA,IACF;AAEA,UAAM,SAAS,sBAAsB,MAAM,QAAQ,WAAW;AAC9D,QAAI,CAAC,QAAQ;AACX,cAAQ,IAAI,MAAM,+DAA+D,CAAC;AAClF;AAAA,IACF;AAEA,UAAM,eAAe;AACrB,UAAM,gBAAgB;AACtB,aAAS,MAAM;AAAA,EACjB;AAEA,WAAS,iBAAiB,SAAS,SAAS,IAAI;AAChD,WAAS,iBAAiB,WAAW,YAAY,IAAI;AAErD,SAAO,MAAM;AACX,aAAS,oBAAoB,SAAS,SAAS,IAAI;AACnD,aAAS,oBAAoB,WAAW,YAAY,IAAI;AACxD,aAAS,OAAO;AAAA,EAClB;AACF;;;AC/aA,IAAI,OAAO,aAAa,aAAa;AACnC,2BAAyB;AAC3B;","names":["source"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-code-locator",
3
- "version": "0.1.8",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -26,6 +26,16 @@
26
26
  "import": "./dist/vite.js",
27
27
  "require": "./dist/vite.cjs"
28
28
  },
29
+ "./esbuild": {
30
+ "types": "./dist/esbuild.d.ts",
31
+ "import": "./dist/esbuild.js",
32
+ "require": "./dist/esbuild.cjs"
33
+ },
34
+ "./swc": {
35
+ "types": "./dist/swc.d.ts",
36
+ "import": "./dist/swc.js",
37
+ "require": "./dist/swc.cjs"
38
+ },
29
39
  "./webpack": {
30
40
  "types": "./dist/webpack.d.cts",
31
41
  "require": "./dist/webpack.cjs"
@@ -51,6 +61,7 @@
51
61
  },
52
62
  "devDependencies": {
53
63
  "@babel/core": "^7.26.0",
64
+ "@types/babel__core": "^7.20.5",
54
65
  "@types/node": "^22.13.10",
55
66
  "tsup": "^8.5.1",
56
67
  "typescript": "^5.8.2",