react-code-locator 0.1.9 → 0.1.13

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