react-doctor 0.9.1-dev.b1b62db → 0.9.2

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 (4) hide show
  1. package/dist/cli.js +216 -74
  2. package/dist/index.js +213 -71
  3. package/dist/lsp.js +214 -72
  4. package/package.json +7 -6
package/dist/lsp.js CHANGED
@@ -10,6 +10,7 @@ import * as Crypto from "node:crypto";
10
10
  import crypto, { createHash } from "node:crypto";
11
11
  import * as NodeChildProcess from "node:child_process";
12
12
  import { execFileSync, spawn, spawnSync } from "node:child_process";
13
+ import { ResolverFactory } from "oxc-resolver";
13
14
  import ts from "typescript";
14
15
  import { parseJSON5 } from "confbox";
15
16
  import * as NodeUrl from "node:url";
@@ -61845,7 +61846,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
61845
61846
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
61846
61847
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
61847
61848
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
61848
- const CORE_PACKAGE_VERSION = "0.9.1";
61849
+ const CORE_PACKAGE_VERSION = "0.9.2";
61849
61850
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
61850
61851
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
61851
61852
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -62095,8 +62096,13 @@ const findMonorepoRoot = (startDirectory) => {
62095
62096
  * byte-equivalent copy.
62096
62097
  */
62097
62098
  const isProjectBoundary = (directory) => NFS.existsSync(Path.join(directory, ".git")) || isMonorepoRoot(directory);
62099
+ const unwrapTypescriptExpression = (expression) => {
62100
+ let currentExpression = expression;
62101
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
62102
+ return currentExpression;
62103
+ };
62098
62104
  const TSCONFIG_FILENAME = "tsconfig.json";
62099
- const isRelativeExtendsValue = (extendsValue) => extendsValue.startsWith("./") || extendsValue.startsWith("../") || Path.isAbsolute(extendsValue);
62105
+ const isLocalModuleSpecifier = (moduleSpecifier) => moduleSpecifier === "." || moduleSpecifier === ".." || moduleSpecifier.startsWith("./") || moduleSpecifier.startsWith("../") || Path.isAbsolute(moduleSpecifier);
62100
62106
  const ensureJsonExtension = (filePath) => Path.extname(filePath) === "" ? `${filePath}.json` : filePath;
62101
62107
  const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
62102
62108
  const requireFromConfig = createRequire(Path.join(fromConfigDirectory, "tsconfig.json"));
@@ -62113,7 +62119,12 @@ const resolvePackageExtendsPath = (extendsValue, fromConfigDirectory) => {
62113
62119
  return null;
62114
62120
  };
62115
62121
  const resolveExtendsPath = (extendsValue, fromConfigDirectory) => {
62116
- if (isRelativeExtendsValue(extendsValue)) return ensureJsonExtension(Path.resolve(fromConfigDirectory, extendsValue));
62122
+ if (isLocalModuleSpecifier(extendsValue)) {
62123
+ const resolvedPath = Path.resolve(fromConfigDirectory, extendsValue);
62124
+ if (isFile(resolvedPath)) return resolvedPath;
62125
+ const directoryConfigPath = Path.join(resolvedPath, TSCONFIG_FILENAME);
62126
+ return isFile(directoryConfigPath) ? directoryConfigPath : ensureJsonExtension(resolvedPath);
62127
+ }
62117
62128
  return resolvePackageExtendsPath(extendsValue, fromConfigDirectory);
62118
62129
  };
62119
62130
  const normalizeCompilerOptions = (compilerOptions) => {
@@ -62307,6 +62318,15 @@ const REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS = [
62307
62318
  ".cts",
62308
62319
  ".json"
62309
62320
  ];
62321
+ const REACT_COMPILER_CONFIG_RESOLVER = new ResolverFactory({
62322
+ conditionNames: [
62323
+ "import",
62324
+ "require",
62325
+ "node",
62326
+ "default"
62327
+ ],
62328
+ extensions: REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS
62329
+ });
62310
62330
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
62311
62331
  const hasCompilerPackage = (packageJson, compilerPackages) => {
62312
62332
  const allDependencies = {
@@ -62330,6 +62350,18 @@ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
62330
62350
  return false;
62331
62351
  };
62332
62352
  const resolveImportedConfigFile = (fromFilePath, moduleSpecifier) => {
62353
+ if (!isLocalModuleSpecifier(moduleSpecifier)) {
62354
+ try {
62355
+ const resolvedPath = REACT_COMPILER_CONFIG_RESOLVER.resolveFileSync(fromFilePath, moduleSpecifier).path;
62356
+ if (resolvedPath && isFile(resolvedPath)) return resolvedPath;
62357
+ } catch {}
62358
+ try {
62359
+ const resolvedPath = createRequire(fromFilePath).resolve(moduleSpecifier);
62360
+ return isFile(resolvedPath) ? resolvedPath : null;
62361
+ } catch {
62362
+ return null;
62363
+ }
62364
+ }
62333
62365
  const unresolvedPath = Path.resolve(Path.dirname(fromFilePath), moduleSpecifier);
62334
62366
  const extension = Path.extname(unresolvedPath);
62335
62367
  return (extension ? [unresolvedPath, ...REACT_COMPILER_CONFIG_SOURCE_EXTENSIONS.map((sourceExtension) => `${unresolvedPath.slice(0, -extension.length)}${sourceExtension}`)] : [
@@ -62355,7 +62387,7 @@ const hasTopLevelValueBinding = (sourceFile, bindingName) => sourceFile.statemen
62355
62387
  const namedBindings = importClause?.namedBindings;
62356
62388
  return namedBindings ? ts.isNamespaceImport(namedBindings) ? namedBindings.name.text === bindingName : namedBindings.elements.some((element) => element.name.text === bindingName) : false;
62357
62389
  }
62358
- if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === bindingName);
62390
+ if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContainsIdentifier(declaration.name, bindingName));
62359
62391
  return (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name?.text === bindingName;
62360
62392
  });
62361
62393
  const getImportBinding = (sourceFile, bindingName) => {
@@ -62456,6 +62488,48 @@ const getScopedConfigBinding = (identifier) => {
62456
62488
  };
62457
62489
  };
62458
62490
  const isCompilerTransformModule = (moduleSpecifier, exportName) => moduleSpecifier === "babel-plugin-react-compiler" && exportName === "default" || moduleSpecifier === "@vitejs/plugin-react" && exportName === "reactCompilerPreset";
62491
+ const NODE_MODULE_SPECIFIERS = new Set(["module", "node:module"]);
62492
+ const isConstantVariableInitializer = (node) => ts.isExpression(node) && ts.isVariableDeclaration(node.parent) && ts.isVariableDeclarationList(node.parent.parent) && Boolean(node.parent.parent.flags & ts.NodeFlags.Const);
62493
+ const isNodeCreateRequireCall = (node, analysis) => {
62494
+ if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isTypeAssertionExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isAwaitExpression(node)) return isNodeCreateRequireCall(node.expression, analysis);
62495
+ if (!ts.isCallExpression(node)) return false;
62496
+ const target = node.expression;
62497
+ if (ts.isIdentifier(target)) {
62498
+ if (analysis.localBindings.has(target.text) || getScopedConfigBinding(target).wasFound) return false;
62499
+ const importBinding = getImportBinding(analysis.sourceFile, target.text);
62500
+ return Boolean(importBinding && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier) && importBinding.exportName === "createRequire");
62501
+ }
62502
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return false;
62503
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "createRequire") return false;
62504
+ const createRequireReceiver = target.expression;
62505
+ if (ts.isCallExpression(createRequireReceiver)) {
62506
+ const requiredModuleSpecifier = getRequireModuleSpecifier$1(createRequireReceiver);
62507
+ if (requiredModuleSpecifier === null || !NODE_MODULE_SPECIFIERS.has(requiredModuleSpecifier) || !ts.isIdentifier(createRequireReceiver.expression)) return false;
62508
+ const requireIdentifier = createRequireReceiver.expression;
62509
+ return !analysis.localBindings.has(requireIdentifier.text) && !getScopedConfigBinding(requireIdentifier).wasFound && !hasTopLevelValueBinding(analysis.sourceFile, requireIdentifier.text);
62510
+ }
62511
+ if (!ts.isIdentifier(createRequireReceiver)) return false;
62512
+ if (analysis.localBindings.has(createRequireReceiver.text) || getScopedConfigBinding(createRequireReceiver).wasFound) return false;
62513
+ const importBinding = getImportBinding(analysis.sourceFile, createRequireReceiver.text);
62514
+ return Boolean(importBinding?.isNamespace && NODE_MODULE_SPECIFIERS.has(importBinding.moduleSpecifier));
62515
+ };
62516
+ const getNodeRequireResolveModuleSpecifier = (callExpression, analysis) => {
62517
+ const [moduleSpecifierNode] = callExpression.arguments;
62518
+ if (!moduleSpecifierNode || !ts.isStringLiteralLike(moduleSpecifierNode)) return null;
62519
+ const target = callExpression.expression;
62520
+ if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62521
+ if ((ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null) !== "resolve") return null;
62522
+ if (isNodeCreateRequireCall(target.expression, analysis)) return moduleSpecifierNode.text;
62523
+ if (!ts.isIdentifier(target.expression)) return null;
62524
+ const resolverIdentifier = target.expression;
62525
+ if (analysis.localBindings.has(resolverIdentifier.text)) return null;
62526
+ const scopedBinding = getScopedConfigBinding(resolverIdentifier);
62527
+ const topLevelBinding = scopedBinding.wasFound ? null : getTopLevelBinding(analysis.sourceFile, resolverIdentifier.text);
62528
+ const resolverInitializer = scopedBinding.wasFound ? scopedBinding.initializer : topLevelBinding;
62529
+ if (resolverInitializer === null && !scopedBinding.wasFound && resolverIdentifier.text === "require" && !hasTopLevelValueBinding(analysis.sourceFile, resolverIdentifier.text) && getImportBinding(analysis.sourceFile, resolverIdentifier.text) === null) return moduleSpecifierNode.text;
62530
+ if (!resolverInitializer || !isConstantVariableInitializer(resolverInitializer) || !isNodeCreateRequireCall(resolverInitializer, analysis)) return null;
62531
+ return moduleSpecifierNode.text;
62532
+ };
62459
62533
  const getAssignedPropertyInitializer = (identifier, propertyName) => {
62460
62534
  let bindingScope = null;
62461
62535
  let currentNode = identifier;
@@ -62498,9 +62572,11 @@ const getAssignedPropertyInitializer = (identifier, propertyName) => {
62498
62572
  initializer: assignedInitializer
62499
62573
  };
62500
62574
  };
62501
- const getStaticConfigValueState = (expression, analysis) => {
62502
- let unwrappedExpression = expression;
62503
- while (ts.isParenthesizedExpression(unwrappedExpression) || ts.isAsExpression(unwrappedExpression) || ts.isTypeAssertionExpression(unwrappedExpression) || ts.isSatisfiesExpression(unwrappedExpression) || ts.isNonNullExpression(unwrappedExpression)) unwrappedExpression = unwrappedExpression.expression;
62575
+ const getStaticConfigValueState = (expression, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
62576
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
62577
+ if (visitedExpressions.has(unwrappedExpression)) return null;
62578
+ const nextVisitedExpressions = new Set(visitedExpressions);
62579
+ nextVisitedExpressions.add(unwrappedExpression);
62504
62580
  if (unwrappedExpression.kind === ts.SyntaxKind.NullKeyword || ts.isIdentifier(unwrappedExpression) && unwrappedExpression.text === "undefined") return {
62505
62581
  isNullish: true,
62506
62582
  isTruthy: false
@@ -62516,31 +62592,31 @@ const getStaticConfigValueState = (expression, analysis) => {
62516
62592
  if (ts.isIdentifier(unwrappedExpression)) {
62517
62593
  if (analysis.localBindings.has(unwrappedExpression.text)) {
62518
62594
  const localInitializer = analysis.localBindings.get(unwrappedExpression.text);
62519
- return localInitializer ? getStaticConfigValueState(localInitializer, analysis) : null;
62595
+ return localInitializer ? getStaticConfigValueState(localInitializer, analysis, nextVisitedExpressions) : null;
62520
62596
  }
62521
62597
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, unwrappedExpression.text);
62522
- return topLevelBinding && ts.isExpression(topLevelBinding) ? getStaticConfigValueState(topLevelBinding, analysis) : null;
62598
+ return topLevelBinding && ts.isExpression(topLevelBinding) ? getStaticConfigValueState(topLevelBinding, analysis, nextVisitedExpressions) : null;
62523
62599
  }
62524
62600
  if (ts.isConditionalExpression(unwrappedExpression)) {
62525
- const conditionState = getStaticConfigValueState(unwrappedExpression.condition, analysis);
62526
- if (conditionState !== null) return getStaticConfigValueState(conditionState.isTruthy ? unwrappedExpression.whenTrue : unwrappedExpression.whenFalse, analysis);
62527
- const whenTrueState = getStaticConfigValueState(unwrappedExpression.whenTrue, analysis);
62528
- const whenFalseState = getStaticConfigValueState(unwrappedExpression.whenFalse, analysis);
62601
+ const conditionState = getStaticConfigValueState(unwrappedExpression.condition, analysis, nextVisitedExpressions);
62602
+ if (conditionState !== null) return getStaticConfigValueState(conditionState.isTruthy ? unwrappedExpression.whenTrue : unwrappedExpression.whenFalse, analysis, nextVisitedExpressions);
62603
+ const whenTrueState = getStaticConfigValueState(unwrappedExpression.whenTrue, analysis, nextVisitedExpressions);
62604
+ const whenFalseState = getStaticConfigValueState(unwrappedExpression.whenFalse, analysis, nextVisitedExpressions);
62529
62605
  return whenTrueState !== null && whenFalseState !== null && whenTrueState.isNullish === whenFalseState.isNullish && whenTrueState.isTruthy === whenFalseState.isTruthy ? whenTrueState : null;
62530
62606
  }
62531
62607
  if (ts.isBinaryExpression(unwrappedExpression)) {
62532
- const leftState = getStaticConfigValueState(unwrappedExpression.left, analysis);
62608
+ const leftState = getStaticConfigValueState(unwrappedExpression.left, analysis, nextVisitedExpressions);
62533
62609
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
62534
62610
  if (leftState === null) return null;
62535
- return leftState.isTruthy ? getStaticConfigValueState(unwrappedExpression.right, analysis) : leftState;
62611
+ return leftState.isTruthy ? getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions) : leftState;
62536
62612
  }
62537
62613
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
62538
62614
  if (leftState === null) return null;
62539
- return leftState.isTruthy ? leftState : getStaticConfigValueState(unwrappedExpression.right, analysis);
62615
+ return leftState.isTruthy ? leftState : getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions);
62540
62616
  }
62541
62617
  if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
62542
62618
  if (leftState === null) return null;
62543
- return leftState.isNullish ? getStaticConfigValueState(unwrappedExpression.right, analysis) : leftState;
62619
+ return leftState.isNullish ? getStaticConfigValueState(unwrappedExpression.right, analysis, nextVisitedExpressions) : leftState;
62544
62620
  }
62545
62621
  }
62546
62622
  return null;
@@ -62549,25 +62625,27 @@ const isStaticallyDisabledConfigExpression = (expression, analysis) => getStatic
62549
62625
  const isStaticallyTruthyConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isTruthy === true;
62550
62626
  const isStaticallyNullishConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isNullish === true;
62551
62627
  const isStaticallyNonNullishConfigExpression = (expression, analysis) => getStaticConfigValueState(expression, analysis)?.isNullish === false;
62552
- const getReactCompilerFlagState = (expression, analysis) => {
62553
- let unwrappedExpression = expression;
62554
- while (ts.isParenthesizedExpression(unwrappedExpression) || ts.isAsExpression(unwrappedExpression) || ts.isTypeAssertionExpression(unwrappedExpression) || ts.isSatisfiesExpression(unwrappedExpression) || ts.isNonNullExpression(unwrappedExpression)) unwrappedExpression = unwrappedExpression.expression;
62628
+ const getReactCompilerFlagState = (expression, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
62629
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
62630
+ if (visitedExpressions.has(unwrappedExpression)) return null;
62631
+ const nextVisitedExpressions = new Set(visitedExpressions);
62632
+ nextVisitedExpressions.add(unwrappedExpression);
62555
62633
  if (ts.isIdentifier(unwrappedExpression)) {
62556
62634
  const assignedBinding = getAssignedPropertyInitializer(unwrappedExpression, "reactCompiler");
62557
62635
  if (assignedBinding.wasFound && assignedBinding.initializer) return { isEnabled: !isStaticallyDisabledConfigExpression(assignedBinding.initializer, analysis) };
62558
62636
  if (analysis.localBindings.has(unwrappedExpression.text)) {
62559
62637
  const localInitializer = analysis.localBindings.get(unwrappedExpression.text);
62560
- return localInitializer ? getReactCompilerFlagState(localInitializer, analysis) : null;
62638
+ return localInitializer ? getReactCompilerFlagState(localInitializer, analysis, nextVisitedExpressions) : null;
62561
62639
  }
62562
62640
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, unwrappedExpression.text);
62563
- return topLevelBinding && ts.isExpression(topLevelBinding) ? getReactCompilerFlagState(topLevelBinding, analysis) : null;
62641
+ return topLevelBinding && ts.isExpression(topLevelBinding) ? getReactCompilerFlagState(topLevelBinding, analysis, nextVisitedExpressions) : null;
62564
62642
  }
62565
62643
  if (!ts.isObjectLiteralExpression(unwrappedExpression)) return null;
62566
62644
  for (const property of [...unwrappedExpression.properties].reverse()) {
62567
62645
  if (ts.isPropertyAssignment(property) && getStaticPropertyName$2(property.name) === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.initializer, analysis) };
62568
62646
  if (ts.isShorthandPropertyAssignment(property) && property.name.text === "reactCompiler") return { isEnabled: !isStaticallyDisabledConfigExpression(property.name, analysis) };
62569
62647
  if (ts.isSpreadAssignment(property)) {
62570
- const spreadState = getReactCompilerFlagState(property.expression, analysis);
62648
+ const spreadState = getReactCompilerFlagState(property.expression, analysis, nextVisitedExpressions);
62571
62649
  if (spreadState) return spreadState;
62572
62650
  }
62573
62651
  }
@@ -62739,6 +62817,11 @@ const analyzeConfigFunction = (functionNode, analysis, allowCompilerTransform, a
62739
62817
  visitReturns(functionNode.body);
62740
62818
  return hasCompiler;
62741
62819
  };
62820
+ const analyzeImportedConfig = ({ analysis, moduleSpecifier, exportName, allowCompilerTransform, argumentsList }) => {
62821
+ const importedFilePath = resolveImportedConfigFile(analysis.filePath, moduleSpecifier);
62822
+ if (!importedFilePath) return null;
62823
+ return analyzeConfigModuleExport(importedFilePath, exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, argumentsList);
62824
+ };
62742
62825
  const analyzeConfigIdentifier = (identifier, analysis, allowCompilerTransform, isCompilerTransformCollection, excludedPropertyNames) => {
62743
62826
  const assignedReactCompiler = getAssignedPropertyInitializer(identifier, "reactCompiler");
62744
62827
  if (assignedReactCompiler.initializer && !isStaticallyDisabledConfigExpression(assignedReactCompiler.initializer, analysis)) return true;
@@ -62759,30 +62842,62 @@ const analyzeConfigIdentifier = (identifier, analysis, allowCompilerTransform, i
62759
62842
  const importBinding = getImportBinding(analysis.sourceFile, identifier.text);
62760
62843
  if (importBinding) {
62761
62844
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, importBinding.exportName)) return true;
62762
- if (!importBinding.moduleSpecifier.startsWith(".")) return false;
62763
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
62764
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, importBinding.exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
62845
+ return Boolean(analyzeImportedConfig({
62846
+ analysis,
62847
+ moduleSpecifier: importBinding.moduleSpecifier,
62848
+ exportName: importBinding.exportName,
62849
+ allowCompilerTransform
62850
+ }));
62765
62851
  }
62766
62852
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, identifier.text);
62767
62853
  return Boolean(topLevelBinding && analyzeConfigNode(topLevelBinding, analysis, allowCompilerTransform, isCompilerTransformCollection, overriddenPropertyNames));
62768
62854
  };
62769
62855
  const analyzeConfigCallTarget = (callExpression, analysis, allowCompilerTransform) => {
62770
62856
  const target = callExpression.expression;
62857
+ const callableRequiredModuleSpecifier = getRequireModuleSpecifier$1(target);
62858
+ if (callableRequiredModuleSpecifier !== null) {
62859
+ if (ts.isCallExpression(target) && ts.isIdentifier(target.expression) && (analysis.localBindings.has(target.expression.text) || getScopedConfigBinding(target.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62860
+ if (allowCompilerTransform && isCompilerTransformModule(callableRequiredModuleSpecifier, "default")) return true;
62861
+ const hasCompilerTransform = analyzeImportedConfig({
62862
+ analysis,
62863
+ moduleSpecifier: callableRequiredModuleSpecifier,
62864
+ exportName: "default",
62865
+ allowCompilerTransform,
62866
+ argumentsList: callExpression.arguments
62867
+ });
62868
+ if (isLocalModuleSpecifier(callableRequiredModuleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
62869
+ return null;
62870
+ }
62771
62871
  if (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) return null;
62772
62872
  const propertyName = ts.isPropertyAccessExpression(target) ? target.name.text : target.argumentExpression && ts.isStringLiteralLike(target.argumentExpression) ? target.argumentExpression.text : null;
62773
62873
  if (propertyName === null) return null;
62774
62874
  const requiredModuleSpecifier = getRequireModuleSpecifier$1(target.expression);
62775
62875
  if (requiredModuleSpecifier !== null) {
62776
- if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62777
- if (!requiredModuleSpecifier.startsWith(".")) return null;
62778
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, requiredModuleSpecifier);
62779
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, propertyName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, callExpression.arguments));
62876
+ if (ts.isCallExpression(target.expression) && ts.isIdentifier(target.expression.expression) && (analysis.localBindings.has(target.expression.expression.text) || getScopedConfigBinding(target.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62877
+ if (allowCompilerTransform && isCompilerTransformModule(requiredModuleSpecifier, propertyName)) return true;
62878
+ const hasCompilerTransform = analyzeImportedConfig({
62879
+ analysis,
62880
+ moduleSpecifier: requiredModuleSpecifier,
62881
+ exportName: propertyName,
62882
+ allowCompilerTransform,
62883
+ argumentsList: callExpression.arguments
62884
+ });
62885
+ if (isLocalModuleSpecifier(requiredModuleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
62886
+ return null;
62780
62887
  }
62781
62888
  if (!ts.isIdentifier(target.expression)) return null;
62782
- const importBinding = getImportBinding(analysis.sourceFile, target.expression.text);
62783
- if (importBinding?.isNamespace && importBinding.moduleSpecifier.startsWith(".")) {
62784
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
62785
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, propertyName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, callExpression.arguments));
62889
+ const importBinding = analysis.localBindings.has(target.expression.text) || getScopedConfigBinding(target.expression).wasFound ? null : getImportBinding(analysis.sourceFile, target.expression.text);
62890
+ if (importBinding?.isNamespace) {
62891
+ if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, propertyName)) return true;
62892
+ const hasCompilerTransform = analyzeImportedConfig({
62893
+ analysis,
62894
+ moduleSpecifier: importBinding.moduleSpecifier,
62895
+ exportName: propertyName,
62896
+ allowCompilerTransform,
62897
+ argumentsList: callExpression.arguments
62898
+ });
62899
+ if (isLocalModuleSpecifier(importBinding.moduleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
62900
+ return null;
62786
62901
  }
62787
62902
  const selectedProperty = getSelectedObjectProperty(target.expression, propertyName, analysis);
62788
62903
  if (selectedProperty === null) return null;
@@ -62805,9 +62920,13 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62805
62920
  if (propertyName === "reactCompiler") continue;
62806
62921
  if ((propertyName === "plugins" || propertyName === "presets") && node.properties.slice(propertyIndex + 1).some((laterProperty) => ts.isSpreadAssignment(laterProperty) && configExpressionMayDefineProperty(laterProperty.expression, propertyName, analysis) || (ts.isPropertyAssignment(laterProperty) || ts.isShorthandPropertyAssignment(laterProperty)) && getStaticPropertyName$2(laterProperty.name) === propertyName)) continue;
62807
62922
  const propertyAllowsCompilerTransform = propertyName === "plugins" || propertyName === "presets";
62808
- if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer) && property.initializer.text.startsWith(".")) {
62809
- const extendedFilePath = resolveImportedConfigFile(analysis.filePath, property.initializer.text);
62810
- if (extendedFilePath && analyzeConfigModuleExport(extendedFilePath, "default", false, analysis.importDepth + 1, analysis.visitedModules)) return true;
62923
+ if (propertyName === "extends" && ts.isStringLiteralLike(property.initializer)) {
62924
+ if (analyzeImportedConfig({
62925
+ analysis,
62926
+ moduleSpecifier: property.initializer.text,
62927
+ exportName: "default",
62928
+ allowCompilerTransform: false
62929
+ })) return true;
62811
62930
  }
62812
62931
  if (analyzeConfigNode(property.initializer, analysis, propertyAllowsCompilerTransform, propertyAllowsCompilerTransform)) return true;
62813
62932
  } else if (ts.isShorthandPropertyAssignment(property)) {
@@ -62831,6 +62950,8 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62831
62950
  });
62832
62951
  }
62833
62952
  if (ts.isCallExpression(node)) {
62953
+ const resolvedModuleSpecifier = getNodeRequireResolveModuleSpecifier(node, analysis);
62954
+ if (resolvedModuleSpecifier !== null) return allowCompilerTransform && isCompilerTransformModule(resolvedModuleSpecifier, "default");
62834
62955
  const callTargetResult = analyzeConfigCallTarget(node, analysis, allowCompilerTransform);
62835
62956
  if (callTargetResult !== null) return callTargetResult;
62836
62957
  const directModuleSpecifier = getRequireModuleSpecifier$1(node);
@@ -62838,16 +62959,27 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62838
62959
  if (directModuleSpecifier && isRequireShadowed) return analyzeConfigNode(node.expression, analysis, allowCompilerTransform);
62839
62960
  if (directModuleSpecifier && !isRequireShadowed) {
62840
62961
  if (allowCompilerTransform && isCompilerTransformModule(directModuleSpecifier, "default")) return true;
62841
- if (directModuleSpecifier.startsWith(".")) {
62842
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, directModuleSpecifier);
62843
- if (importedFilePath && analyzeConfigModuleExport(importedFilePath, "default", allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules)) return true;
62844
- }
62962
+ if (analyzeImportedConfig({
62963
+ analysis,
62964
+ moduleSpecifier: directModuleSpecifier,
62965
+ exportName: "default",
62966
+ allowCompilerTransform
62967
+ })) return true;
62845
62968
  }
62846
62969
  if (ts.isIdentifier(node.expression)) {
62847
- const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
62848
- if (importBinding?.moduleSpecifier.startsWith(".")) {
62849
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
62850
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, importBinding.exportName, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules, node.arguments));
62970
+ if (!analysis.localBindings.has(node.expression.text) && !getScopedConfigBinding(node.expression).wasFound) {
62971
+ const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
62972
+ if (importBinding) {
62973
+ if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, importBinding.exportName)) return true;
62974
+ const hasCompilerTransform = analyzeImportedConfig({
62975
+ analysis,
62976
+ moduleSpecifier: importBinding.moduleSpecifier,
62977
+ exportName: importBinding.exportName,
62978
+ allowCompilerTransform,
62979
+ argumentsList: node.arguments
62980
+ });
62981
+ if (isLocalModuleSpecifier(importBinding.moduleSpecifier) || hasCompilerTransform !== null) return Boolean(hasCompilerTransform);
62982
+ }
62851
62983
  }
62852
62984
  const topLevelBinding = getTopLevelBinding(analysis.sourceFile, node.expression.text);
62853
62985
  if (topLevelBinding && ts.isFunctionLike(topLevelBinding) && analyzeConfigFunction(topLevelBinding, analysis, allowCompilerTransform, node.arguments)) return true;
@@ -62857,25 +62989,29 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62857
62989
  if (ts.isPropertyAccessExpression(node)) {
62858
62990
  const requiredModuleSpecifier = getRequireModuleSpecifier$1(node.expression);
62859
62991
  if (requiredModuleSpecifier) {
62860
- if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62861
- if (requiredModuleSpecifier.startsWith(".")) {
62862
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, requiredModuleSpecifier);
62863
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, node.name.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
62864
- }
62992
+ if (ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && (analysis.localBindings.has(node.expression.expression.text) || getScopedConfigBinding(node.expression.expression).wasFound || hasTopLevelValueBinding(analysis.sourceFile, "require"))) return false;
62993
+ if (analyzeImportedConfig({
62994
+ analysis,
62995
+ moduleSpecifier: requiredModuleSpecifier,
62996
+ exportName: node.name.text,
62997
+ allowCompilerTransform
62998
+ })) return true;
62865
62999
  return allowCompilerTransform && isCompilerTransformModule(requiredModuleSpecifier, node.name.text);
62866
63000
  }
62867
63001
  if (ts.isIdentifier(node.expression)) {
62868
- if (analysis.localBindings.has(node.expression.text)) {
62869
- const localInitializer = analysis.localBindings.get(node.expression.text);
62870
- return Boolean(localInitializer && analyzeConfigNode(localInitializer, analysis, allowCompilerTransform));
63002
+ if (analysis.localBindings.has(node.expression.text) || getScopedConfigBinding(node.expression).wasFound) {
63003
+ const selectedProperty = getSelectedObjectProperty(node.expression, node.name.text, analysis);
63004
+ return Boolean(selectedProperty && analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform));
62871
63005
  }
62872
63006
  const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
62873
63007
  if (importBinding?.isNamespace) {
62874
63008
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, node.name.text)) return true;
62875
- if (importBinding.moduleSpecifier.startsWith(".")) {
62876
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
62877
- if (importedFilePath && analyzeConfigModuleExport(importedFilePath, node.name.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules)) return true;
62878
- }
63009
+ if (analyzeImportedConfig({
63010
+ analysis,
63011
+ moduleSpecifier: importBinding.moduleSpecifier,
63012
+ exportName: node.name.text,
63013
+ allowCompilerTransform
63014
+ })) return true;
62879
63015
  return false;
62880
63016
  }
62881
63017
  const selectedProperty = getSelectedObjectProperty(node.expression, node.name.text, analysis);
@@ -62886,13 +63022,19 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62886
63022
  }
62887
63023
  if (ts.isElementAccessExpression(node) && node.argumentExpression && ts.isStringLiteralLike(node.argumentExpression)) {
62888
63024
  if (ts.isIdentifier(node.expression)) {
63025
+ if (analysis.localBindings.has(node.expression.text) || getScopedConfigBinding(node.expression).wasFound) {
63026
+ const selectedProperty = getSelectedObjectProperty(node.expression, node.argumentExpression.text, analysis);
63027
+ return Boolean(selectedProperty && analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform));
63028
+ }
62889
63029
  const importBinding = getImportBinding(analysis.sourceFile, node.expression.text);
62890
63030
  if (importBinding?.isNamespace) {
62891
63031
  if (allowCompilerTransform && isCompilerTransformModule(importBinding.moduleSpecifier, node.argumentExpression.text)) return true;
62892
- if (importBinding.moduleSpecifier.startsWith(".")) {
62893
- const importedFilePath = resolveImportedConfigFile(analysis.filePath, importBinding.moduleSpecifier);
62894
- return Boolean(importedFilePath && analyzeConfigModuleExport(importedFilePath, node.argumentExpression.text, allowCompilerTransform, analysis.importDepth + 1, analysis.visitedModules));
62895
- }
63032
+ return Boolean(analyzeImportedConfig({
63033
+ analysis,
63034
+ moduleSpecifier: importBinding.moduleSpecifier,
63035
+ exportName: node.argumentExpression.text,
63036
+ allowCompilerTransform
63037
+ }));
62896
63038
  }
62897
63039
  const selectedProperty = getSelectedObjectProperty(node.expression, node.argumentExpression.text, analysis);
62898
63040
  if (selectedProperty) return analyzeConfigNode(selectedProperty, analysis, allowCompilerTransform);
@@ -62930,14 +63072,19 @@ const analyzeConfigNode = (node, analysis, allowCompilerTransform, isCompilerTra
62930
63072
  };
62931
63073
  const hasCompilerInConfigFile = (filePath) => analyzeConfigModuleExport(filePath, "default", false, 0, /* @__PURE__ */ new Set());
62932
63074
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
62933
- const hasCompilerInPackageJsonConfig = (packageJson) => isPlainObject(packageJson.babel) && analyzeConfigSourceFileExport(ts.parseJsonText("package.json", JSON.stringify(packageJson.babel)), "package.json#babel", "default", false, 0, /* @__PURE__ */ new Set());
62934
- const hasCompilerConfiguration = (directory, packageJson) => hasCompilerInPackageJsonConfig(packageJson) || hasCompilerInConfigFiles(directory, REACT_COMPILER_CONFIG_FILENAMES);
63075
+ const hasCompilerInPackageJsonConfig = (directory, packageJson) => {
63076
+ if (!isPlainObject(packageJson.babel)) return false;
63077
+ const packageJsonPath = Path.join(directory, "package.json");
63078
+ return analyzeConfigSourceFileExport(ts.parseJsonText(packageJsonPath, JSON.stringify(packageJson.babel)), packageJsonPath, "default", false, 0, /* @__PURE__ */ new Set());
63079
+ };
63080
+ const hasCompilerConfiguration = (directory, packageJson) => hasCompilerInPackageJsonConfig(directory, packageJson) || hasCompilerInConfigFiles(directory, REACT_COMPILER_CONFIG_FILENAMES);
62935
63081
  const hasCompilerConfigurationInAncestors = (directory) => {
62936
63082
  if (isProjectBoundary(directory)) return false;
62937
63083
  let ancestorDirectory = Path.dirname(directory);
62938
63084
  while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
62939
63085
  const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
62940
- if (hasCompilerInPackageJsonConfig(isFile(ancestorPackagePath) ? readPackageJson(ancestorPackagePath) : {}) || hasCompilerInConfigFiles(ancestorDirectory, BABEL_CONFIG_FILENAMES)) return true;
63086
+ const ancestorPackageJson = isFile(ancestorPackagePath) ? readPackageJson(ancestorPackagePath) : {};
63087
+ if (hasCompilerInPackageJsonConfig(ancestorDirectory, ancestorPackageJson) || hasCompilerInConfigFiles(ancestorDirectory, BABEL_CONFIG_FILENAMES)) return true;
62941
63088
  if (isProjectBoundary(ancestorDirectory)) return false;
62942
63089
  ancestorDirectory = Path.dirname(ancestorDirectory);
62943
63090
  }
@@ -67121,11 +67268,6 @@ const getTypescriptScriptKind = (fileName) => {
67121
67268
  if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
67122
67269
  return ts.ScriptKind.JS;
67123
67270
  };
67124
- const unwrapTypescriptExpression = (expression) => {
67125
- let currentExpression = expression;
67126
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
67127
- return currentExpression;
67128
- };
67129
67271
  const BABEL_CONFIG_FILE_NAMES$1 = [
67130
67272
  "babel.config.js",
67131
67273
  "babel.config.cjs",
@@ -74341,7 +74483,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
74341
74483
  /** Display name used in client-facing messages and progress titles. */
74342
74484
  const SERVER_DISPLAY_NAME = "React Doctor";
74343
74485
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
74344
- const SERVER_VERSION = "0.9.1";
74486
+ const SERVER_VERSION = "0.9.2";
74345
74487
  /** `Diagnostic.source` shown next to every published diagnostic. */
74346
74488
  const DIAGNOSTIC_SOURCE = "react-doctor";
74347
74489
  /**
@@ -76372,5 +76514,5 @@ const startLanguageServer = () => {
76372
76514
  };
76373
76515
  //#endregion
76374
76516
  export { startLanguageServer };
76375
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="60b26f08-3459-56b1-938b-6a9bcdea7253")}catch(e){}}();
76376
- //# debugId=60b26f08-3459-56b1-938b-6a9bcdea7253
76517
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c691162a-94f2-58c6-9397-fab6dbaa4d44")}catch(e){}}();
76518
+ //# debugId=c691162a-94f2-58c6-9397-fab6dbaa4d44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.9.1-dev.b1b62db",
3
+ "version": "0.9.2",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -61,6 +61,7 @@
61
61
  "ink-spinner": "^5.0.0",
62
62
  "jiti": "^2.7.0",
63
63
  "magicast": "^0.5.3",
64
+ "oxc-resolver": "^11.24.2",
64
65
  "oxlint": ">=1.74.0 <1.75.0",
65
66
  "prompts": "^2.4.2",
66
67
  "react": "19.2.5",
@@ -69,8 +70,8 @@
69
70
  "vscode-languageserver-textdocument": "^1.0.12",
70
71
  "vscode-uri": "^3.1.0",
71
72
  "yaml": "^2.9.0",
72
- "deslop-js": "0.9.1",
73
- "oxlint-plugin-react-doctor": "0.9.1-dev.b1b62db"
73
+ "deslop-js": "0.9.2",
74
+ "oxlint-plugin-react-doctor": "0.9.2"
74
75
  },
75
76
  "devDependencies": {
76
77
  "@types/babel__code-frame": "^7.27.0",
@@ -80,9 +81,9 @@
80
81
  "commander": "^14.0.3",
81
82
  "ink-testing-library": "^4.0.0",
82
83
  "ora": "^9.4.0",
83
- "@react-doctor/api": "0.9.1",
84
- "@react-doctor/language-server": "0.9.1",
85
- "@react-doctor/core": "0.9.1"
84
+ "@react-doctor/api": "0.9.2",
85
+ "@react-doctor/core": "0.9.2",
86
+ "@react-doctor/language-server": "0.9.2"
86
87
  },
87
88
  "engines": {
88
89
  "node": "^20.19.0 || >=22.13.0"