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
package/dist/vite.js CHANGED
@@ -1,58 +1,129 @@
1
- // src/elementLocatorReact.ts
2
- var VIRTUAL_CLIENT_MODULE_ID = "virtual:react-code-locator/client";
3
- var RESOLVED_VIRTUAL_CLIENT_MODULE_ID = `\0${VIRTUAL_CLIENT_MODULE_ID}`;
4
- function createClientInjector(locatorOptions = {}) {
5
- const serialized = JSON.stringify(locatorOptions);
6
- return {
7
- name: "element-locator-client-injector",
8
- apply: "serve",
9
- resolveId(id) {
10
- if (id === VIRTUAL_CLIENT_MODULE_ID) {
11
- return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;
12
- }
13
- return null;
14
- },
15
- load(id) {
16
- if (id !== RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {
17
- return null;
18
- }
19
- return `
20
- import { enableReactComponentJump } from "react-code-locator/client";
21
-
22
- enableReactComponentJump(${serialized});
23
- `;
24
- },
25
- transformIndexHtml() {
26
- return [
27
- {
28
- tag: "script",
29
- attrs: {
30
- type: "module",
31
- src: `/@id/__x00__${VIRTUAL_CLIENT_MODULE_ID}`
32
- },
33
- injectTo: "head"
34
- }
35
- ];
36
- }
37
- };
38
- }
39
- function elementLocatorReact(options = {}) {
40
- const { command = "serve", locator = {}, injectClient = true } = options;
41
- const isServe = command === "serve";
42
- return [isServe && injectClient ? createClientInjector(locator) : null].filter(Boolean);
1
+ // src/sourceAdapter.ts
2
+ function defineSourceAdapter(descriptor) {
3
+ return descriptor;
43
4
  }
44
5
 
6
+ // src/sourceTransform.ts
7
+ import { transformAsync } from "@babel/core";
8
+
45
9
  // src/babelInjectComponentSource.ts
46
- import path from "path";
47
10
  import { types as t } from "@babel/core";
48
11
 
49
12
  // src/constants.ts
50
13
  var SOURCE_PROP = "__componentSourceLoc";
14
+ var JSX_SOURCE_PROP = "$componentSourceLoc";
15
+ var JSX_SOURCE_REGISTRY_SYMBOL = "react-code-locator.jsxSourceRegistry";
16
+
17
+ // src/sourceMetadata.ts
18
+ function normalizeSlashes(value) {
19
+ return value.replace(/\\/g, "/");
20
+ }
21
+ function trimTrailingSlash(value) {
22
+ return value.replace(/\/+$/, "");
23
+ }
24
+ function splitPathSegments(value) {
25
+ return normalizeSlashes(value).split("/").filter(Boolean);
26
+ }
27
+ function computeRelativePath(fromPath, toPath) {
28
+ const fromSegments = splitPathSegments(fromPath);
29
+ const toSegments = splitPathSegments(toPath);
30
+ let sharedIndex = 0;
31
+ while (sharedIndex < fromSegments.length && sharedIndex < toSegments.length && fromSegments[sharedIndex] === toSegments[sharedIndex]) {
32
+ sharedIndex += 1;
33
+ }
34
+ const upSegments = new Array(Math.max(0, fromSegments.length - sharedIndex)).fill("..");
35
+ const downSegments = toSegments.slice(sharedIndex);
36
+ const relativeSegments = [...upSegments, ...downSegments];
37
+ return relativeSegments.length > 0 ? relativeSegments.join("/") : ".";
38
+ }
39
+ function normalizeProjectRoot(projectRoot) {
40
+ if (projectRoot) {
41
+ return trimTrailingSlash(normalizeSlashes(projectRoot));
42
+ }
43
+ if (typeof process !== "undefined" && typeof process.cwd === "function") {
44
+ return trimTrailingSlash(normalizeSlashes(process.cwd()));
45
+ }
46
+ return "";
47
+ }
48
+ function toRelativeSource(filename, loc, projectRoot) {
49
+ if (!filename || !loc) {
50
+ return null;
51
+ }
52
+ const root = normalizeProjectRoot(projectRoot);
53
+ const normalizedFilename = normalizeSlashes(filename);
54
+ const relPath = root && normalizedFilename.startsWith(`${root}/`) ? normalizedFilename.slice(root.length + 1) : root ? computeRelativePath(root, normalizedFilename) : normalizedFilename;
55
+ return `${relPath}:${loc.line}:${loc.column + 1}`;
56
+ }
57
+ function isProjectLocalFile(filename, projectRoot) {
58
+ if (!filename) {
59
+ return false;
60
+ }
61
+ const root = normalizeProjectRoot(projectRoot);
62
+ const normalizedFilename = normalizeSlashes(filename);
63
+ if (!root) {
64
+ return !normalizedFilename.startsWith("../") && !normalizedFilename.startsWith("/") && !/^[A-Za-z]:\//.test(normalizedFilename);
65
+ }
66
+ if (normalizedFilename.startsWith(`${root}/`) || normalizedFilename === root) {
67
+ return true;
68
+ }
69
+ const relativePath = computeRelativePath(root, normalizedFilename);
70
+ return !relativePath.startsWith("../");
71
+ }
72
+ function isExternalToProjectRoot(filename, projectRoot) {
73
+ return !isProjectLocalFile(filename, projectRoot);
74
+ }
51
75
 
52
76
  // src/babelInjectComponentSource.ts
77
+ var SOURCE_PROP_LOCAL = "_componentSourceLoc";
78
+ var SOURCE_PROPS_REST = "__reactCodeLocatorProps";
53
79
  function isComponentName(name) {
54
80
  return /^[A-Z]/.test(name);
55
81
  }
82
+ function isCustomComponentTag(name) {
83
+ if (t.isJSXIdentifier(name)) {
84
+ return isComponentName(name.name);
85
+ }
86
+ if (t.isJSXMemberExpression(name)) {
87
+ return true;
88
+ }
89
+ return false;
90
+ }
91
+ function isIntrinsicElementTag(name) {
92
+ return t.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
93
+ }
94
+ function isElementFactoryIdentifier(name) {
95
+ return name === "jsx" || name === "jsxs" || name === "jsxDEV" || name === "_jsx" || name === "_jsxs" || name === "_jsxDEV" || name === "createElement";
96
+ }
97
+ function isReactElementFactoryCall(pathNode) {
98
+ const callee = pathNode.node.callee;
99
+ if (t.isIdentifier(callee)) {
100
+ return isElementFactoryIdentifier(callee.name);
101
+ }
102
+ return t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: "React" }) && t.isIdentifier(callee.property, { name: "createElement" });
103
+ }
104
+ function getRootJsxIdentifierName(name) {
105
+ if (t.isJSXIdentifier(name)) {
106
+ return name.name;
107
+ }
108
+ if (t.isJSXMemberExpression(name)) {
109
+ return getRootJsxIdentifierName(name.object);
110
+ }
111
+ return null;
112
+ }
113
+ function isStyledModuleImport(binding) {
114
+ if (!binding) {
115
+ return false;
116
+ }
117
+ if (!binding.path.isImportSpecifier() && !binding.path.isImportDefaultSpecifier() && !binding.path.isImportNamespaceSpecifier()) {
118
+ return false;
119
+ }
120
+ const source = binding.path.parentPath.isImportDeclaration() ? binding.path.parentPath.node.source.value : null;
121
+ if (typeof source !== "string") {
122
+ return false;
123
+ }
124
+ const normalized = source.replace(/\\/g, "/");
125
+ return normalized === "./styled" || normalized === "../styled" || normalized.endsWith("/styled");
126
+ }
56
127
  function isSupportedComponentInit(node) {
57
128
  if (!node) {
58
129
  return false;
@@ -68,13 +139,104 @@ function isSupportedComponentInit(node) {
68
139
  }
69
140
  return t.isMemberExpression(node.callee) && t.isIdentifier(node.callee.object, { name: "React" }) && t.isIdentifier(node.callee.property) && (node.callee.property.name === "memo" || node.callee.property.name === "forwardRef");
70
141
  }
71
- function getSourceValue(state, loc) {
142
+ function hasSourcePropBinding(pattern) {
143
+ return pattern.properties.some((property) => {
144
+ if (!t.isObjectProperty(property)) {
145
+ return false;
146
+ }
147
+ return t.isIdentifier(property.key) && property.key.name === JSX_SOURCE_PROP;
148
+ });
149
+ }
150
+ function injectSourcePropBinding(pattern) {
151
+ if (hasSourcePropBinding(pattern)) {
152
+ return;
153
+ }
154
+ const sourceBinding = t.objectProperty(
155
+ t.identifier(JSX_SOURCE_PROP),
156
+ t.identifier(SOURCE_PROP_LOCAL),
157
+ false,
158
+ false
159
+ );
160
+ const restIndex = pattern.properties.findIndex(
161
+ (property) => t.isRestElement(property)
162
+ );
163
+ if (restIndex === -1) {
164
+ pattern.properties.push(sourceBinding);
165
+ return;
166
+ }
167
+ pattern.properties.splice(restIndex, 0, sourceBinding);
168
+ }
169
+ function injectSourcePropIntoIdentifierParam(node, param) {
170
+ if (!t.isBlockStatement(node.body)) {
171
+ node.body = t.blockStatement([t.returnStatement(node.body)]);
172
+ }
173
+ const alreadyInjected = node.body.body.some(
174
+ (statement) => t.isVariableDeclaration(statement) && statement.declarations.some(
175
+ (declaration) => t.isIdentifier(declaration.id) && declaration.id.name === SOURCE_PROPS_REST
176
+ )
177
+ );
178
+ if (alreadyInjected) {
179
+ return;
180
+ }
181
+ node.body.body.unshift(
182
+ t.variableDeclaration("const", [
183
+ t.variableDeclarator(
184
+ t.objectPattern([
185
+ t.objectProperty(
186
+ t.identifier(JSX_SOURCE_PROP),
187
+ t.identifier(SOURCE_PROP_LOCAL),
188
+ false,
189
+ false
190
+ ),
191
+ t.restElement(t.identifier(SOURCE_PROPS_REST))
192
+ ]),
193
+ param
194
+ )
195
+ ]),
196
+ t.expressionStatement(
197
+ t.assignmentExpression(
198
+ "=",
199
+ t.identifier(param.name),
200
+ t.identifier(SOURCE_PROPS_REST)
201
+ )
202
+ )
203
+ );
204
+ }
205
+ function injectSourcePropIntoFunctionParams(node) {
206
+ const firstParam = node.params[0];
207
+ if (!firstParam) {
208
+ return;
209
+ }
210
+ if (t.isObjectPattern(firstParam)) {
211
+ injectSourcePropBinding(firstParam);
212
+ return;
213
+ }
214
+ if (t.isIdentifier(firstParam)) {
215
+ injectSourcePropIntoIdentifierParam(node, firstParam);
216
+ }
217
+ }
218
+ function injectSourcePropIntoExpression(node) {
219
+ if (!node) {
220
+ return;
221
+ }
222
+ if (t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) {
223
+ injectSourcePropIntoFunctionParams(node);
224
+ return;
225
+ }
226
+ if (!t.isCallExpression(node)) {
227
+ return;
228
+ }
229
+ const firstArg = node.arguments[0];
230
+ if (firstArg && !t.isSpreadElement(firstArg) && (t.isFunctionExpression(firstArg) || t.isArrowFunctionExpression(firstArg))) {
231
+ injectSourcePropIntoFunctionParams(firstArg);
232
+ }
233
+ }
234
+ function getSourceValue(state, loc, projectRoot) {
72
235
  const filename = state.file?.opts?.filename;
73
236
  if (!filename || !loc) {
74
237
  return null;
75
238
  }
76
- const relPath = path.relative(process.cwd(), filename).replace(/\\/g, "/");
77
- return `${relPath}:${loc.line}:${loc.column + 1}`;
239
+ return toRelativeSource(filename, loc, projectRoot);
78
240
  }
79
241
  function buildAssignment(name, sourceValue) {
80
242
  return t.expressionStatement(
@@ -85,13 +247,98 @@ function buildAssignment(name, sourceValue) {
85
247
  )
86
248
  );
87
249
  }
88
- function visitDeclaration(declarationPath, insertAfterPath, state, seen) {
250
+ function buildIntrinsicSourceHelper() {
251
+ return t.functionDeclaration(
252
+ t.identifier("_markIntrinsicElementSource"),
253
+ [t.identifier("element"), t.identifier("source")],
254
+ t.blockStatement([
255
+ t.variableDeclaration("const", [
256
+ t.variableDeclarator(
257
+ t.identifier("registryKey"),
258
+ t.callExpression(
259
+ t.memberExpression(t.identifier("Symbol"), t.identifier("for")),
260
+ [t.stringLiteral(JSX_SOURCE_REGISTRY_SYMBOL)]
261
+ )
262
+ )
263
+ ]),
264
+ t.variableDeclaration("let", [
265
+ t.variableDeclarator(
266
+ t.identifier("registry"),
267
+ t.memberExpression(t.identifier("globalThis"), t.identifier("registryKey"), true)
268
+ )
269
+ ]),
270
+ t.ifStatement(
271
+ t.unaryExpression(
272
+ "!",
273
+ t.binaryExpression("instanceof", t.identifier("registry"), t.identifier("WeakMap"))
274
+ ),
275
+ t.blockStatement([
276
+ t.expressionStatement(
277
+ t.assignmentExpression(
278
+ "=",
279
+ t.identifier("registry"),
280
+ t.assignmentExpression(
281
+ "=",
282
+ t.memberExpression(t.identifier("globalThis"), t.identifier("registryKey"), true),
283
+ t.newExpression(t.identifier("WeakMap"), [])
284
+ )
285
+ )
286
+ )
287
+ ])
288
+ ),
289
+ t.ifStatement(
290
+ t.logicalExpression(
291
+ "&&",
292
+ t.identifier("element"),
293
+ t.logicalExpression(
294
+ "&&",
295
+ t.binaryExpression("===", t.unaryExpression("typeof", t.identifier("element")), t.stringLiteral("object")),
296
+ t.binaryExpression(
297
+ "===",
298
+ t.unaryExpression("typeof", t.memberExpression(t.identifier("element"), t.identifier("props"))),
299
+ t.stringLiteral("object")
300
+ )
301
+ )
302
+ ),
303
+ t.blockStatement([
304
+ t.expressionStatement(
305
+ t.callExpression(
306
+ t.memberExpression(t.identifier("registry"), t.identifier("set")),
307
+ [t.memberExpression(t.identifier("element"), t.identifier("props")), t.identifier("source")]
308
+ )
309
+ )
310
+ ])
311
+ ),
312
+ t.returnStatement(t.identifier("element"))
313
+ ])
314
+ );
315
+ }
316
+ function ensureIntrinsicSourceHelper(programPath, state) {
317
+ if (state.injectedIntrinsicHelper) {
318
+ return;
319
+ }
320
+ const alreadyExists = programPath.node.body.some(
321
+ (node) => t.isFunctionDeclaration(node) && t.isIdentifier(node.id, { name: "_markIntrinsicElementSource" })
322
+ );
323
+ if (!alreadyExists) {
324
+ programPath.unshiftContainer("body", buildIntrinsicSourceHelper());
325
+ }
326
+ state.injectedIntrinsicHelper = true;
327
+ }
328
+ function visitDeclaration(declarationPath, insertAfterPath, state, seen, projectRoot) {
89
329
  if (declarationPath.isFunctionDeclaration() || declarationPath.isClassDeclaration()) {
90
330
  const name = declarationPath.node.id?.name;
91
331
  if (!name || !isComponentName(name) || seen.has(name)) {
92
332
  return;
93
333
  }
94
- const sourceValue = getSourceValue(state, declarationPath.node.loc?.start);
334
+ if (declarationPath.isFunctionDeclaration()) {
335
+ injectSourcePropIntoFunctionParams(declarationPath.node);
336
+ }
337
+ const sourceValue = getSourceValue(
338
+ state,
339
+ declarationPath.node.loc?.start,
340
+ projectRoot
341
+ );
95
342
  if (!sourceValue) {
96
343
  return;
97
344
  }
@@ -102,38 +349,128 @@ function visitDeclaration(declarationPath, insertAfterPath, state, seen) {
102
349
  if (!declarationPath.isVariableDeclaration()) {
103
350
  return;
104
351
  }
105
- const assignments = declarationPath.node.declarations.flatMap((declarator) => {
106
- if (!t.isIdentifier(declarator.id) || !isComponentName(declarator.id.name) || seen.has(declarator.id.name)) {
107
- return [];
108
- }
109
- if (!declarator.init) {
110
- return [];
111
- }
112
- if (!isSupportedComponentInit(declarator.init)) {
113
- return [];
114
- }
115
- const sourceValue = getSourceValue(state, declarator.loc?.start ?? declarator.init.loc?.start);
116
- if (!sourceValue) {
117
- return [];
352
+ const assignments = declarationPath.node.declarations.flatMap(
353
+ (declarator) => {
354
+ if (!t.isIdentifier(declarator.id) || !isComponentName(declarator.id.name) || seen.has(declarator.id.name)) {
355
+ return [];
356
+ }
357
+ if (!declarator.init) {
358
+ return [];
359
+ }
360
+ if (!isSupportedComponentInit(declarator.init)) {
361
+ return [];
362
+ }
363
+ injectSourcePropIntoExpression(declarator.init);
364
+ const sourceValue = getSourceValue(
365
+ state,
366
+ declarator.loc?.start ?? declarator.init.loc?.start,
367
+ projectRoot
368
+ );
369
+ if (!sourceValue) {
370
+ return [];
371
+ }
372
+ seen.add(declarator.id.name);
373
+ return [buildAssignment(declarator.id.name, sourceValue)];
118
374
  }
119
- seen.add(declarator.id.name);
120
- return [buildAssignment(declarator.id.name, sourceValue)];
121
- });
375
+ );
122
376
  if (assignments.length > 0) {
123
377
  insertAfterPath.insertAfter(assignments);
124
378
  }
125
379
  }
126
380
  function babelInjectComponentSource(options = {}) {
127
- const { injectJsxSource = false, injectComponentSource = true } = options;
381
+ const {
382
+ injectJsxSource = true,
383
+ injectComponentSource = true,
384
+ projectRoot
385
+ } = options;
128
386
  return {
129
387
  name: "babel-inject-component-source",
130
388
  visitor: {
389
+ CallExpression(pathNode, state) {
390
+ if (!injectJsxSource) {
391
+ return;
392
+ }
393
+ if (!isReactElementFactoryCall(pathNode)) {
394
+ return;
395
+ }
396
+ if (pathNode.parentPath.isCallExpression() && t.isIdentifier(pathNode.parentPath.node.callee, {
397
+ name: "_markIntrinsicElementSource"
398
+ })) {
399
+ return;
400
+ }
401
+ const sourceValue = getSourceValue(
402
+ state,
403
+ pathNode.node.loc?.start,
404
+ projectRoot
405
+ );
406
+ if (!sourceValue) {
407
+ return;
408
+ }
409
+ const programPath = pathNode.findParent((parent) => parent.isProgram());
410
+ if (!programPath || !programPath.isProgram()) {
411
+ return;
412
+ }
413
+ ensureIntrinsicSourceHelper(programPath, state);
414
+ pathNode.replaceWith(
415
+ t.callExpression(t.identifier("_markIntrinsicElementSource"), [
416
+ pathNode.node,
417
+ t.stringLiteral(sourceValue)
418
+ ])
419
+ );
420
+ pathNode.skip();
421
+ },
422
+ JSXElement: {
423
+ exit(pathNode, state) {
424
+ if (!injectJsxSource) {
425
+ return;
426
+ }
427
+ if (!isIntrinsicElementTag(pathNode.node.openingElement.name)) {
428
+ return;
429
+ }
430
+ if (pathNode.parentPath.isCallExpression() && t.isIdentifier(pathNode.parentPath.node.callee, { name: "_markIntrinsicElementSource" })) {
431
+ return;
432
+ }
433
+ const sourceValue = getSourceValue(
434
+ state,
435
+ pathNode.node.openingElement.loc?.start,
436
+ projectRoot
437
+ );
438
+ if (!sourceValue) {
439
+ return;
440
+ }
441
+ const programPath = pathNode.findParent((parent) => parent.isProgram());
442
+ if (!programPath || !programPath.isProgram()) {
443
+ return;
444
+ }
445
+ ensureIntrinsicSourceHelper(programPath, state);
446
+ const wrappedNode = t.callExpression(t.identifier("_markIntrinsicElementSource"), [
447
+ pathNode.node,
448
+ t.stringLiteral(sourceValue)
449
+ ]);
450
+ if (pathNode.parentPath.isJSXElement() || pathNode.parentPath.isJSXFragment()) {
451
+ pathNode.replaceWith(t.jsxExpressionContainer(wrappedNode));
452
+ return;
453
+ }
454
+ if (pathNode.parentPath.isJSXExpressionContainer()) {
455
+ pathNode.parentPath.replaceWith(t.jsxExpressionContainer(wrappedNode));
456
+ return;
457
+ }
458
+ pathNode.replaceWith(wrappedNode);
459
+ }
460
+ },
131
461
  JSXOpeningElement(pathNode, state) {
132
462
  if (!injectJsxSource) {
133
463
  return;
134
464
  }
465
+ if (!isCustomComponentTag(pathNode.node.name)) {
466
+ return;
467
+ }
468
+ const rootIdentifierName = getRootJsxIdentifierName(pathNode.node.name);
469
+ if (rootIdentifierName && isExternalToProjectRoot(state.file?.opts?.filename, projectRoot) && isStyledModuleImport(pathNode.scope.getBinding(rootIdentifierName))) {
470
+ return;
471
+ }
135
472
  const hasSourceProp = pathNode.node.attributes.some(
136
- (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === SOURCE_PROP
473
+ (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === JSX_SOURCE_PROP
137
474
  );
138
475
  if (hasSourceProp) {
139
476
  return;
@@ -145,8 +482,10 @@ function babelInjectComponentSource(options = {}) {
145
482
  }
146
483
  pathNode.node.attributes.push(
147
484
  t.jsxAttribute(
148
- t.jsxIdentifier(SOURCE_PROP),
149
- t.stringLiteral(getSourceValue(state, loc) ?? `${filename.replace(/\\/g, "/")}:${loc.line}:${loc.column + 1}`)
485
+ t.jsxIdentifier(JSX_SOURCE_PROP),
486
+ t.stringLiteral(
487
+ getSourceValue(state, loc, projectRoot) ?? `${filename.replace(/\\/g, "/")}:${loc.line}:${loc.column + 1}`
488
+ )
150
489
  )
151
490
  );
152
491
  },
@@ -159,19 +498,128 @@ function babelInjectComponentSource(options = {}) {
159
498
  if (childPath.isExportNamedDeclaration() || childPath.isExportDefaultDeclaration()) {
160
499
  const declarationPath = childPath.get("declaration");
161
500
  if (!Array.isArray(declarationPath) && declarationPath.node) {
162
- visitDeclaration(declarationPath, childPath, state, seen);
501
+ visitDeclaration(declarationPath, childPath, state, seen, projectRoot);
163
502
  }
164
503
  continue;
165
504
  }
166
- visitDeclaration(childPath, childPath, state, seen);
505
+ visitDeclaration(childPath, childPath, state, seen, projectRoot);
506
+ }
507
+ }
508
+ }
509
+ };
510
+ }
511
+
512
+ // src/sourceTransform.ts
513
+ async function transformSourceWithLocator(code, options) {
514
+ const { filename, sourceMaps = true, ...pluginOptions } = options;
515
+ const result = await transformAsync(code, {
516
+ filename,
517
+ babelrc: false,
518
+ configFile: false,
519
+ sourceMaps,
520
+ parserOpts: {
521
+ sourceType: "module",
522
+ plugins: ["jsx", "typescript"]
523
+ },
524
+ generatorOpts: {
525
+ retainLines: true
526
+ },
527
+ plugins: [[babelInjectComponentSource, pluginOptions]]
528
+ });
529
+ return {
530
+ code: result?.code ?? code,
531
+ map: result?.map ?? null
532
+ };
533
+ }
534
+
535
+ // src/viteClientInjector.ts
536
+ var VIRTUAL_CLIENT_MODULE_ID = "virtual:react-code-locator/client";
537
+ var RESOLVED_VIRTUAL_CLIENT_MODULE_ID = `\0${VIRTUAL_CLIENT_MODULE_ID}`;
538
+ function createClientInjector(locatorOptions = {}) {
539
+ const serialized = JSON.stringify(locatorOptions);
540
+ return {
541
+ name: "react-code-locator-client-injector",
542
+ apply: "serve",
543
+ resolveId(id) {
544
+ if (id === VIRTUAL_CLIENT_MODULE_ID) {
545
+ return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;
546
+ }
547
+ return null;
548
+ },
549
+ load(id) {
550
+ if (id !== RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {
551
+ return null;
552
+ }
553
+ return `
554
+ import { enableReactComponentJump } from "react-code-locator/client";
555
+
556
+ enableReactComponentJump(${serialized});
557
+ `;
558
+ },
559
+ transformIndexHtml() {
560
+ return [
561
+ {
562
+ tag: "script",
563
+ attrs: {
564
+ type: "module",
565
+ src: `/@id/__x00__${VIRTUAL_CLIENT_MODULE_ID}`
566
+ },
567
+ injectTo: "head"
167
568
  }
569
+ ];
570
+ }
571
+ };
572
+ }
573
+ function createViteClientInjector(options = {}) {
574
+ const { command = "serve", locator = {}, injectClient = true } = options;
575
+ const isServe = command === "serve";
576
+ return [isServe && injectClient ? createClientInjector(locator) : null].filter(Boolean);
577
+ }
578
+
579
+ // src/vite.ts
580
+ function shouldTransformSource(id) {
581
+ if (id.includes("/node_modules/") || id.startsWith("\0")) {
582
+ return false;
583
+ }
584
+ return /\.[mc]?[jt]sx?$/.test(id);
585
+ }
586
+ function viteSourceTransformPlugin(options = {}) {
587
+ return {
588
+ name: "react-code-locator-source-transform",
589
+ enforce: "pre",
590
+ async transform(code, id) {
591
+ if (!shouldTransformSource(id)) {
592
+ return null;
168
593
  }
594
+ return transformSourceWithLocator(code, {
595
+ filename: id,
596
+ ...options
597
+ });
169
598
  }
170
599
  };
171
600
  }
601
+ function createViteSourceAdapter(options = {}) {
602
+ const { babel = {}, ...viteOptions } = options;
603
+ const plugins = [
604
+ viteSourceTransformPlugin(babel),
605
+ ...createViteClientInjector(viteOptions)
606
+ ].filter(Boolean);
607
+ return defineSourceAdapter({
608
+ kind: "vite",
609
+ name: "react-code-locator/vite",
610
+ options,
611
+ config: {
612
+ plugins
613
+ }
614
+ });
615
+ }
616
+ var viteSourceAdapter = createViteSourceAdapter();
172
617
  export {
173
618
  babelInjectComponentSource,
174
- elementLocatorReact,
175
- elementLocatorReact as reactComponentJump
619
+ createViteClientInjector,
620
+ createViteSourceAdapter,
621
+ createViteClientInjector as reactComponentJump,
622
+ viteSourceAdapter,
623
+ viteSourceTransformPlugin
176
624
  };
177
625
  //# sourceMappingURL=vite.js.map