react-doctor 0.9.4-dev.8b97fdc → 0.9.4-dev.bafef41
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.
- package/dist/cli.js +319 -142
- package/dist/index.d.ts +1 -0
- package/dist/index.js +168 -35
- package/dist/lsp.js +208 -30
- package/dist/{run-scan-app-QbtG43NL.js → run-scan-app-C8iWVgvR.js} +10 -10
- package/package.json +5 -5
package/dist/lsp.js
CHANGED
|
@@ -7275,6 +7275,16 @@ const catchTag$2 = /* @__PURE__ */ dual((args) => isEffect$1(args[0]), (self, k,
|
|
|
7275
7275
|
return catchIf$2(self, Array.isArray(k) ? (e) => hasProperty(e, "_tag") && k.includes(e._tag) : isTagged(k), f, orElse);
|
|
7276
7276
|
});
|
|
7277
7277
|
/** @internal */
|
|
7278
|
+
const catchReasons$1 = /* @__PURE__ */ dual((args) => isEffect$1(args[0]), (self, errorTag, cases, orElse) => {
|
|
7279
|
+
let keys;
|
|
7280
|
+
return catchIf$2(self, (e) => isTagged(e, errorTag) && hasProperty(e, "reason") && hasProperty(e.reason, "_tag") && isString(e.reason._tag), (e) => {
|
|
7281
|
+
const reason = e.reason;
|
|
7282
|
+
keys ??= Object.keys(cases);
|
|
7283
|
+
if (keys.includes(reason._tag)) return internalCall(() => cases[reason._tag](reason, e));
|
|
7284
|
+
return orElse ? internalCall(() => orElse(reason, e)) : fail$7(e);
|
|
7285
|
+
});
|
|
7286
|
+
});
|
|
7287
|
+
/** @internal */
|
|
7278
7288
|
const mapError = /* @__PURE__ */ dual(2, (self, f) => catch_$2(self, (error) => failSync(() => f(error))));
|
|
7279
7289
|
const mapBoth = /* @__PURE__ */ dual(2, (self, options) => matchEffect$2(self, {
|
|
7280
7290
|
onFailure: (e) => failSync(() => options.onFailure(e)),
|
|
@@ -12184,6 +12194,42 @@ const catch_$1 = catch_$2;
|
|
|
12184
12194
|
*/
|
|
12185
12195
|
const catchTag$1 = catchTag$2;
|
|
12186
12196
|
/**
|
|
12197
|
+
* Catches multiple reasons within a tagged error using an object of handlers.
|
|
12198
|
+
*
|
|
12199
|
+
* **Example** (Handling multiple error reasons)
|
|
12200
|
+
*
|
|
12201
|
+
* ```ts
|
|
12202
|
+
* import { Data, Effect } from "effect"
|
|
12203
|
+
*
|
|
12204
|
+
* class RateLimitError extends Data.TaggedError("RateLimitError")<{
|
|
12205
|
+
* retryAfter: number
|
|
12206
|
+
* }> {}
|
|
12207
|
+
*
|
|
12208
|
+
* class QuotaExceededError extends Data.TaggedError("QuotaExceededError")<{
|
|
12209
|
+
* limit: number
|
|
12210
|
+
* }> {}
|
|
12211
|
+
*
|
|
12212
|
+
* class AiError extends Data.TaggedError("AiError")<{
|
|
12213
|
+
* reason: RateLimitError | QuotaExceededError
|
|
12214
|
+
* }> {}
|
|
12215
|
+
*
|
|
12216
|
+
* declare const program: Effect.Effect<string, AiError>
|
|
12217
|
+
*
|
|
12218
|
+
* const handled = program.pipe(
|
|
12219
|
+
* Effect.catchReasons("AiError", {
|
|
12220
|
+
* RateLimitError: (reason) =>
|
|
12221
|
+
* Effect.succeed(`Retry after ${reason.retryAfter}s`),
|
|
12222
|
+
* QuotaExceededError: (reason) =>
|
|
12223
|
+
* Effect.succeed(`Quota exceeded: ${reason.limit}`)
|
|
12224
|
+
* })
|
|
12225
|
+
* )
|
|
12226
|
+
* ```
|
|
12227
|
+
*
|
|
12228
|
+
* @category error handling
|
|
12229
|
+
* @since 4.0.0
|
|
12230
|
+
*/
|
|
12231
|
+
const catchReasons = catchReasons$1;
|
|
12232
|
+
/**
|
|
12187
12233
|
* Handles both recoverable and unrecoverable errors by providing a recovery
|
|
12188
12234
|
* effect.
|
|
12189
12235
|
*
|
|
@@ -62351,17 +62397,20 @@ const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
|
|
|
62351
62397
|
const isErrnoException = (error) => error instanceof Error && "code" in error;
|
|
62352
62398
|
const IGNORABLE_READDIR_ERROR_CODES = new Set([
|
|
62353
62399
|
"EACCES",
|
|
62400
|
+
"EBUSY",
|
|
62354
62401
|
"EPERM",
|
|
62355
62402
|
"ENOENT",
|
|
62356
62403
|
"ENOTDIR",
|
|
62357
62404
|
"EINVAL",
|
|
62358
62405
|
"ELOOP",
|
|
62359
|
-
"ENAMETOOLONG"
|
|
62406
|
+
"ENAMETOOLONG",
|
|
62407
|
+
"ETIMEDOUT",
|
|
62408
|
+
"UNKNOWN"
|
|
62360
62409
|
]);
|
|
62361
62410
|
const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
|
|
62362
62411
|
const readDirectoryEntries = (directoryPath) => {
|
|
62363
62412
|
try {
|
|
62364
|
-
return
|
|
62413
|
+
return fs.readdirSync(directoryPath, { withFileTypes: true });
|
|
62365
62414
|
} catch (error) {
|
|
62366
62415
|
if (isIgnorableReaddirError(error)) return [];
|
|
62367
62416
|
throw error;
|
|
@@ -62369,14 +62418,14 @@ const readDirectoryEntries = (directoryPath) => {
|
|
|
62369
62418
|
};
|
|
62370
62419
|
const isFile = (filePath) => {
|
|
62371
62420
|
try {
|
|
62372
|
-
return
|
|
62421
|
+
return fs.statSync(filePath).isFile();
|
|
62373
62422
|
} catch {
|
|
62374
62423
|
return false;
|
|
62375
62424
|
}
|
|
62376
62425
|
};
|
|
62377
62426
|
const isDirectory = (directoryPath) => {
|
|
62378
62427
|
try {
|
|
62379
|
-
return
|
|
62428
|
+
return fs.statSync(directoryPath).isDirectory();
|
|
62380
62429
|
} catch {
|
|
62381
62430
|
return false;
|
|
62382
62431
|
}
|
|
@@ -62806,7 +62855,12 @@ const mergeCompilerOptions = (inherited, current) => {
|
|
|
62806
62855
|
};
|
|
62807
62856
|
};
|
|
62808
62857
|
const readResolvedCompilerOptions = (tsConfigPath, extendsDepth, visitedPaths) => {
|
|
62809
|
-
|
|
62858
|
+
let realPath;
|
|
62859
|
+
try {
|
|
62860
|
+
realPath = NFS.realpathSync.native(tsConfigPath);
|
|
62861
|
+
} catch {
|
|
62862
|
+
return null;
|
|
62863
|
+
}
|
|
62810
62864
|
if (visitedPaths.has(realPath)) return null;
|
|
62811
62865
|
const tsConfig = readTsConfig(realPath);
|
|
62812
62866
|
if (!tsConfig) return null;
|
|
@@ -63334,27 +63388,30 @@ const getSelectedObjectProperty = (expression, propertyName, analysis, visitedEx
|
|
|
63334
63388
|
}
|
|
63335
63389
|
return null;
|
|
63336
63390
|
};
|
|
63337
|
-
const configExpressionMayDefineProperty = (expression, propertyName, analysis) => {
|
|
63391
|
+
const configExpressionMayDefineProperty = (expression, propertyName, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
|
|
63338
63392
|
let resolvedExpression = expression;
|
|
63339
63393
|
while (ts.isParenthesizedExpression(resolvedExpression) || ts.isAsExpression(resolvedExpression) || ts.isTypeAssertionExpression(resolvedExpression) || ts.isSatisfiesExpression(resolvedExpression) || ts.isNonNullExpression(resolvedExpression)) resolvedExpression = resolvedExpression.expression;
|
|
63394
|
+
if (visitedExpressions.has(resolvedExpression)) return true;
|
|
63395
|
+
const nextVisitedExpressions = new Set(visitedExpressions);
|
|
63396
|
+
nextVisitedExpressions.add(resolvedExpression);
|
|
63340
63397
|
if (ts.isIdentifier(resolvedExpression)) {
|
|
63341
63398
|
if (analysis.localBindings.has(resolvedExpression.text)) {
|
|
63342
63399
|
const localReference = analysis.localBindings.get(resolvedExpression.text);
|
|
63343
|
-
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis) : true;
|
|
63400
|
+
return localReference?.expression ? configExpressionMayDefineProperty(localReference.expression, propertyName, localReference.analysis, nextVisitedExpressions) : true;
|
|
63344
63401
|
}
|
|
63345
63402
|
const scopedBinding = getScopedConfigBinding(resolvedExpression);
|
|
63346
|
-
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis) : true;
|
|
63403
|
+
if (scopedBinding.wasFound) return scopedBinding.initializer ? configExpressionMayDefineProperty(scopedBinding.initializer, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63347
63404
|
const topLevelBinding = getTopLevelBinding(analysis.sourceFile, resolvedExpression.text);
|
|
63348
|
-
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis) : true;
|
|
63405
|
+
return topLevelBinding && ts.isExpression(topLevelBinding) ? configExpressionMayDefineProperty(topLevelBinding, propertyName, analysis, nextVisitedExpressions) : true;
|
|
63349
63406
|
}
|
|
63350
63407
|
if (ts.isConditionalExpression(resolvedExpression)) {
|
|
63351
|
-
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis);
|
|
63352
|
-
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63353
|
-
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis);
|
|
63408
|
+
if (isStaticallyTruthyConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions);
|
|
63409
|
+
if (isStaticallyDisabledConfigExpression(resolvedExpression.condition, analysis)) return configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63410
|
+
return configExpressionMayDefineProperty(resolvedExpression.whenTrue, propertyName, analysis, nextVisitedExpressions) || configExpressionMayDefineProperty(resolvedExpression.whenFalse, propertyName, analysis, nextVisitedExpressions);
|
|
63354
63411
|
}
|
|
63355
63412
|
if (!ts.isObjectLiteralExpression(resolvedExpression)) return true;
|
|
63356
63413
|
return resolvedExpression.properties.some((property) => {
|
|
63357
|
-
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis);
|
|
63414
|
+
if (ts.isSpreadAssignment(property)) return configExpressionMayDefineProperty(property.expression, propertyName, analysis, nextVisitedExpressions);
|
|
63358
63415
|
if (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property) || ts.isMethodDeclaration(property) || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
|
|
63359
63416
|
const staticPropertyName = getStaticPropertyName$2(property.name);
|
|
63360
63417
|
return staticPropertyName === null || staticPropertyName === propertyName;
|
|
@@ -63430,7 +63487,13 @@ const analyzeConfigModuleExport = (filePath, exportName, allowCompilerTransform,
|
|
|
63430
63487
|
if (visitedModules.has(moduleVisitKey)) return false;
|
|
63431
63488
|
const nextVisitedModules = new Set(visitedModules);
|
|
63432
63489
|
nextVisitedModules.add(moduleVisitKey);
|
|
63433
|
-
|
|
63490
|
+
let sourceText;
|
|
63491
|
+
try {
|
|
63492
|
+
sourceText = NFS.readFileSync(filePath, "utf-8");
|
|
63493
|
+
} catch {
|
|
63494
|
+
return false;
|
|
63495
|
+
}
|
|
63496
|
+
return analyzeConfigSourceFileExport(parseConfigSourceFile(filePath, sourceText), filePath, exportName, allowCompilerTransform, importDepth, nextVisitedModules, argumentsList, argumentAnalysis);
|
|
63434
63497
|
};
|
|
63435
63498
|
const analyzeConfigSourceFileExport = (sourceFile, filePath, exportName, allowCompilerTransform, importDepth, visitedModules, argumentsList = [], argumentAnalysis) => {
|
|
63436
63499
|
const analysis = {
|
|
@@ -66911,6 +66974,43 @@ const validateStringArrayField = (fieldName, value) => {
|
|
|
66911
66974
|
return false;
|
|
66912
66975
|
});
|
|
66913
66976
|
};
|
|
66977
|
+
const validateIgnoreOverride = (rawOverride, index) => {
|
|
66978
|
+
const fieldName = `ignore.overrides[${index}]`;
|
|
66979
|
+
if (!isRecord(rawOverride)) {
|
|
66980
|
+
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawOverride}); ignoring this override.`);
|
|
66981
|
+
return;
|
|
66982
|
+
}
|
|
66983
|
+
const files = validateStringArrayField(`${fieldName}.files`, rawOverride.files);
|
|
66984
|
+
if (files === void 0) return void 0;
|
|
66985
|
+
const validatedOverride = { files };
|
|
66986
|
+
if (rawOverride.rules !== void 0) {
|
|
66987
|
+
const rules = validateStringArrayField(`${fieldName}.rules`, rawOverride.rules);
|
|
66988
|
+
if (rules !== void 0) validatedOverride.rules = rules;
|
|
66989
|
+
}
|
|
66990
|
+
return validatedOverride;
|
|
66991
|
+
};
|
|
66992
|
+
const validateIgnoreField = (rawIgnore) => {
|
|
66993
|
+
if (!isRecord(rawIgnore)) {
|
|
66994
|
+
warnConfigIssue(`config field "ignore" must be an object (got ${typeof rawIgnore}); ignoring this field.`);
|
|
66995
|
+
return;
|
|
66996
|
+
}
|
|
66997
|
+
const validatedIgnore = {};
|
|
66998
|
+
for (const fieldName of [
|
|
66999
|
+
"rules",
|
|
67000
|
+
"files",
|
|
67001
|
+
"tags"
|
|
67002
|
+
]) {
|
|
67003
|
+
if (rawIgnore[fieldName] === void 0) continue;
|
|
67004
|
+
const validatedValues = validateStringArrayField(`ignore.${fieldName}`, rawIgnore[fieldName]);
|
|
67005
|
+
if (validatedValues !== void 0) validatedIgnore[fieldName] = validatedValues;
|
|
67006
|
+
}
|
|
67007
|
+
if (rawIgnore.overrides !== void 0) if (!Array.isArray(rawIgnore.overrides)) warnConfigIssue(`config field "ignore.overrides" must be an array (got ${typeof rawIgnore.overrides}); ignoring this field.`);
|
|
67008
|
+
else validatedIgnore.overrides = rawIgnore.overrides.flatMap((rawOverride, index) => {
|
|
67009
|
+
const validatedOverride = validateIgnoreOverride(rawOverride, index);
|
|
67010
|
+
return validatedOverride ? [validatedOverride] : [];
|
|
67011
|
+
});
|
|
67012
|
+
return validatedIgnore;
|
|
67013
|
+
};
|
|
66914
67014
|
const validateSurfaceControls = (surface, rawControls) => {
|
|
66915
67015
|
if (!isRecord(rawControls)) {
|
|
66916
67016
|
warnConfigIssue(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
|
|
@@ -66986,6 +67086,7 @@ const validateConfigTypes = (config) => {
|
|
|
66986
67086
|
for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
|
|
66987
67087
|
for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
|
|
66988
67088
|
for (const fieldName of STRING_ARRAY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateStringArrayField(fieldName, value));
|
|
67089
|
+
applyFieldValidator(config, validated, "ignore", validateIgnoreField);
|
|
66989
67090
|
applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
|
|
66990
67091
|
for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value, fieldName === "categories"));
|
|
66991
67092
|
applyFieldValidator(config, validated, "plugins", (value) => validateStringArrayField("plugins", value));
|
|
@@ -68602,7 +68703,7 @@ const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
|
|
|
68602
68703
|
if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
|
|
68603
68704
|
}
|
|
68604
68705
|
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
68605
|
-
const tagEvidence = ts.
|
|
68706
|
+
const tagEvidence = ts.isIdentifier(node.tagName) || ts.isPropertyAccessExpression(node.tagName) ? resolveMotionExpressionEvidence(node.tagName, typeChecker, program) : EMPTY_MOTION_EXPRESSION_EVIDENCE;
|
|
68606
68707
|
if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
|
|
68607
68708
|
if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
|
|
68608
68709
|
}
|
|
@@ -70586,7 +70687,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
70586
70687
|
changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
|
|
70587
70688
|
isCurrentChanges: false
|
|
70588
70689
|
};
|
|
70589
|
-
}).pipe(withSpan("Git.diffSelection")),
|
|
70690
|
+
}).pipe(catchReasons("ReactDoctorError", { GitInvocationFailed: () => succeed$2(null) }, (_reason, error) => fail$4(error)), withSpan("Git.diffSelection")),
|
|
70590
70691
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
70591
70692
|
"diff",
|
|
70592
70693
|
"--no-ext-diff",
|
|
@@ -70802,6 +70903,33 @@ const detectUserLintConfigPaths = (rootDirectory) => {
|
|
|
70802
70903
|
return [];
|
|
70803
70904
|
};
|
|
70804
70905
|
const DISABLE_DIRECTIVE_PATTERN = /(eslint|oxlint)-disable/;
|
|
70906
|
+
const neutralizedFileLeases = /* @__PURE__ */ new Map();
|
|
70907
|
+
const activeNeutralizationInitializations = /* @__PURE__ */ new Set();
|
|
70908
|
+
const directoriesOverlap = (left, right) => {
|
|
70909
|
+
const isWithin = (parent, candidate) => {
|
|
70910
|
+
const relativePath = Path.relative(parent, candidate);
|
|
70911
|
+
return relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath);
|
|
70912
|
+
};
|
|
70913
|
+
return isWithin(left, right) || isWithin(right, left);
|
|
70914
|
+
};
|
|
70915
|
+
const withOverlappingInitializationLock = async (rootDirectory, operation) => {
|
|
70916
|
+
const blockers = [...activeNeutralizationInitializations].filter((initialization) => directoriesOverlap(initialization.rootDirectory, rootDirectory)).map((initialization) => initialization.done);
|
|
70917
|
+
let release;
|
|
70918
|
+
const initialization = {
|
|
70919
|
+
rootDirectory,
|
|
70920
|
+
done: new Promise((resolve) => {
|
|
70921
|
+
release = resolve;
|
|
70922
|
+
})
|
|
70923
|
+
};
|
|
70924
|
+
activeNeutralizationInitializations.add(initialization);
|
|
70925
|
+
await Promise.all(blockers);
|
|
70926
|
+
try {
|
|
70927
|
+
return await operation();
|
|
70928
|
+
} finally {
|
|
70929
|
+
activeNeutralizationInitializations.delete(initialization);
|
|
70930
|
+
release();
|
|
70931
|
+
}
|
|
70932
|
+
};
|
|
70805
70933
|
const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths) => {
|
|
70806
70934
|
const program = gen(function* () {
|
|
70807
70935
|
return yield* (yield* Git).grep({
|
|
@@ -70844,34 +70972,84 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
|
|
|
70844
70972
|
};
|
|
70845
70973
|
const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
|
|
70846
70974
|
const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
|
|
70847
|
-
const
|
|
70848
|
-
const
|
|
70849
|
-
const
|
|
70975
|
+
const collectNeutralizationCandidatePaths = (rootDirectory, discoveredRelativePaths, includePaths) => {
|
|
70976
|
+
const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
|
|
70977
|
+
const requestedPaths = includePaths && includePaths.length > 0 ? new Set(includePaths.flatMap((includePath) => {
|
|
70978
|
+
try {
|
|
70979
|
+
return [NFS.realpathSync(Path.resolve(resolvedRootDirectory, includePath))];
|
|
70980
|
+
} catch {
|
|
70981
|
+
return [];
|
|
70982
|
+
}
|
|
70983
|
+
})) : null;
|
|
70984
|
+
const candidatePaths = /* @__PURE__ */ new Set();
|
|
70985
|
+
for (const relativePath of discoveredRelativePaths) try {
|
|
70986
|
+
candidatePaths.add(NFS.realpathSync(Path.resolve(resolvedRootDirectory, relativePath)));
|
|
70987
|
+
} catch {
|
|
70988
|
+
continue;
|
|
70989
|
+
}
|
|
70990
|
+
for (const leasedPath of neutralizedFileLeases.keys()) {
|
|
70991
|
+
const relativePath = Path.relative(resolvedRootDirectory, leasedPath);
|
|
70992
|
+
if (!(relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath)) || requestedPaths && !requestedPaths.has(leasedPath)) continue;
|
|
70993
|
+
candidatePaths.add(leasedPath);
|
|
70994
|
+
}
|
|
70995
|
+
return candidatePaths;
|
|
70996
|
+
};
|
|
70997
|
+
const neutralizeDisableDirectives = async (rootDirectory, includePaths, options = {}) => {
|
|
70998
|
+
const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
|
|
70999
|
+
const leasedPaths = /* @__PURE__ */ new Set();
|
|
70850
71000
|
let isRestored = false;
|
|
70851
71001
|
const restore = () => {
|
|
70852
71002
|
if (isRestored) return;
|
|
70853
71003
|
isRestored = true;
|
|
70854
|
-
for (const
|
|
70855
|
-
|
|
70856
|
-
|
|
70857
|
-
|
|
71004
|
+
for (const absolutePath of leasedPaths) {
|
|
71005
|
+
const lease = neutralizedFileLeases.get(absolutePath);
|
|
71006
|
+
if (!lease) continue;
|
|
71007
|
+
lease.referenceCount -= 1;
|
|
71008
|
+
if (lease.referenceCount > 0) continue;
|
|
71009
|
+
neutralizedFileLeases.delete(absolutePath);
|
|
71010
|
+
try {
|
|
71011
|
+
NFS.writeFileSync(absolutePath, lease.originalContent);
|
|
71012
|
+
} catch (error) {
|
|
71013
|
+
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
|
|
71014
|
+
}
|
|
70858
71015
|
}
|
|
70859
71016
|
};
|
|
70860
71017
|
const onExit = () => restore();
|
|
70861
71018
|
process.once("exit", onExit);
|
|
70862
|
-
|
|
70863
|
-
|
|
71019
|
+
const leaseCandidatePath = (absolutePath) => {
|
|
71020
|
+
if (leasedPaths.has(absolutePath)) return;
|
|
71021
|
+
const existingLease = neutralizedFileLeases.get(absolutePath);
|
|
71022
|
+
if (existingLease) {
|
|
71023
|
+
existingLease.referenceCount += 1;
|
|
71024
|
+
leasedPaths.add(absolutePath);
|
|
71025
|
+
return;
|
|
71026
|
+
}
|
|
70864
71027
|
let originalContent;
|
|
70865
71028
|
try {
|
|
70866
71029
|
originalContent = NFS.readFileSync(absolutePath, "utf-8");
|
|
70867
71030
|
} catch {
|
|
70868
|
-
|
|
71031
|
+
return;
|
|
70869
71032
|
}
|
|
70870
71033
|
const neutralizedContent = neutralizeContent(originalContent);
|
|
70871
71034
|
if (neutralizedContent !== originalContent) {
|
|
70872
|
-
originalContents.set(absolutePath, originalContent);
|
|
70873
71035
|
NFS.writeFileSync(absolutePath, neutralizedContent);
|
|
71036
|
+
neutralizedFileLeases.set(absolutePath, {
|
|
71037
|
+
originalContent,
|
|
71038
|
+
referenceCount: 1
|
|
71039
|
+
});
|
|
71040
|
+
leasedPaths.add(absolutePath);
|
|
70874
71041
|
}
|
|
71042
|
+
};
|
|
71043
|
+
try {
|
|
71044
|
+
await withOverlappingInitializationLock(resolvedRootDirectory, async () => {
|
|
71045
|
+
for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, [], includePaths)) if (neutralizedFileLeases.has(absolutePath)) leaseCandidatePath(absolutePath);
|
|
71046
|
+
const discoveredRelativePaths = await (options.findFiles ?? findFilesWithDisableDirectives)(resolvedRootDirectory, includePaths);
|
|
71047
|
+
for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, discoveredRelativePaths, includePaths)) leaseCandidatePath(absolutePath);
|
|
71048
|
+
});
|
|
71049
|
+
} catch (error) {
|
|
71050
|
+
restore();
|
|
71051
|
+
process.removeListener("exit", onExit);
|
|
71052
|
+
throw error;
|
|
70875
71053
|
}
|
|
70876
71054
|
return () => {
|
|
70877
71055
|
restore();
|
|
@@ -75206,7 +75384,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
75206
75384
|
const sourcePath = path.join(input.directory, subdirectory, configFilename);
|
|
75207
75385
|
const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
|
|
75208
75386
|
if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
|
|
75209
|
-
if (
|
|
75387
|
+
if (isFile(sourcePath) && !fs.existsSync(targetPath)) {
|
|
75210
75388
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
75211
75389
|
fs.cpSync(sourcePath, targetPath);
|
|
75212
75390
|
}
|
|
@@ -77428,5 +77606,5 @@ const startLanguageServer = () => {
|
|
|
77428
77606
|
};
|
|
77429
77607
|
//#endregion
|
|
77430
77608
|
export { startLanguageServer };
|
|
77431
|
-
!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]="
|
|
77432
|
-
//# debugId=
|
|
77609
|
+
!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]="8e8ec622-f2dc-5f52-bfe8-232b07051a7f")}catch(e){}}();
|
|
77610
|
+
//# debugId=8e8ec622-f2dc-5f52-bfe8-232b07051a7f
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
!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]="
|
|
2
|
+
!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]="ce3dfab8-7fd1-5dae-a660-054bea703cbf")}catch(e){}}();
|
|
3
3
|
import { $ as TUI_REPORT_DETAIL_WIDTH_FRACTION, A as shouldRecordOnboarding, B as buildSortedRuleGroups, C as createInvocationInspect, D as markOnboardingComplete, E as doctorFace, F as buildEmptyReportMessage, G as recordCount, H as formatLearnMoreLine, I as hasIncompleteScoreAnalysis, J as findNearestPackageDirectory, K as recordDistribution, L as buildNoScoreMessage, M as computeProjectedScore, N as formatElapsedTime, O as canAnimateOnboarding, P as buildCodeFrame, Q as TUI_REPORT_COMPACT_MAX_ROWS, R as hasLintHardFailure, S as deduplicateProjectScans, T as easeOutCubic, U as resolveBlockingLevel, V as formatFixRecipeLine, W as isReactDoctorWorkflowInstalled, X as CI_TRUST_COMPANIES, Y as isUnicodeSupported, Z as METRIC, _ as launchCliAgent, _t as succeed, a as selectProjects, at as buildRuleDocsUrl, b as formatSkippedProjectsMessage, c as resolveWorkspaceDeadCodeOwner, ct as highlighter, d as countUniqueScannedFiles, dt as remainingDeadlineBudgetMs, et as isCiEnvironment, f as setUpGitHubActions, ft as resolveScanTarget, g as copyToClipboard, gt as void_, h as CLI_AGENT_BINARIES, ht as sync, i as discoverWorkspacePackages, it as Reporter, j as filterDiagnosticsByCategories, k as isOnboardingForced, l as resolveCliInspectOptions, lt as isPathInsideDirectory, m as detectLaunchableAgents, mt as runPromise, n as registerActiveTuiRenderer, nt as GITHUB_ACTIONS_SETUP_URL, o as resolveProjectScan, ot as getCategoryImpact, p as openUrl, pt as yieldToEventLoop, q as toForwardSlashes, r as shouldFailScanGate, rt as Progress, s as retryMissingProjectScores, st as hasPublishedFixRecipe, t as exitGracefully, tt as DIAGNOSTIC_CATEGORY_BUCKETS, u as filterScansForSurface, ut as mapWithConcurrency, v as buildHandoffPayload, w as printFooter, x as collectProjectSourceFileCounts, y as isShareOptedOut, z as buildRulePriorityMap } from "./cli.js";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { performance } from "node:perf_hooks";
|
|
6
7
|
import { getSkillAgentConfig } from "agent-install";
|
|
7
|
-
import { Box, Text, render, useApp, useInput, useStdout } from "ink";
|
|
8
|
+
import { Box, Text, Transform, render, useApp, useInput, useStdout } from "ink";
|
|
8
9
|
import figures from "figures";
|
|
9
|
-
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import
|
|
11
|
+
import terminalLink from "terminal-link";
|
|
12
12
|
import Spinner from "ink-spinner";
|
|
13
13
|
//#region src/cli/utils/pluralize.ts
|
|
14
14
|
const pluralize = (count, singularNoun) => `${count} ${singularNoun}${count === 1 ? "" : "s"}`;
|
|
@@ -49,6 +49,7 @@ const useExitOnCtrlC = () => {
|
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
|
+
const { useEffect, useMemo, useRef, useState, useSyncExternalStore } = createRequire(createRequire(import.meta.url).resolve("ink"))("react");
|
|
52
53
|
//#endregion
|
|
53
54
|
//#region src/cli/ink/hooks/use-stdout-dimensions.ts
|
|
54
55
|
const readDimensions = (stdout) => ({
|
|
@@ -527,10 +528,9 @@ const AgentHandoff = ({ agents, onSelect, onBack, onQuit }) => {
|
|
|
527
528
|
};
|
|
528
529
|
//#endregion
|
|
529
530
|
//#region src/cli/ink/components/tui-link.tsx
|
|
530
|
-
const TuiLink = ({ children, url }) => /* @__PURE__ */ jsx(
|
|
531
|
-
url,
|
|
532
|
-
|
|
533
|
-
children
|
|
531
|
+
const TuiLink = ({ children, url }) => /* @__PURE__ */ jsx(Transform, {
|
|
532
|
+
transform: (text) => terminalLink(text, url, { fallback: false }),
|
|
533
|
+
children: /* @__PURE__ */ jsx(Text, { children })
|
|
534
534
|
});
|
|
535
535
|
//#endregion
|
|
536
536
|
//#region src/cli/ink/components/ci-justification.tsx
|
|
@@ -2322,5 +2322,5 @@ const runScanApp = async (input) => {
|
|
|
2322
2322
|
//#endregion
|
|
2323
2323
|
export { runScanApp };
|
|
2324
2324
|
|
|
2325
|
-
//# sourceMappingURL=run-scan-app-
|
|
2326
|
-
//# debugId=
|
|
2325
|
+
//# sourceMappingURL=run-scan-app-C8iWVgvR.js.map
|
|
2326
|
+
//# debugId=ce3dfab8-7fd1-5dae-a660-054bea703cbf
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.9.4-dev.
|
|
3
|
+
"version": "0.9.4-dev.bafef41",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
60
60
|
"figures": "^6.1.0",
|
|
61
61
|
"ink": "^7.1.0",
|
|
62
|
-
"ink-link": "^5.0.0",
|
|
63
62
|
"ink-spinner": "^5.0.0",
|
|
64
63
|
"jiti": "^2.7.0",
|
|
65
64
|
"magicast": "^0.5.3",
|
|
@@ -67,13 +66,14 @@
|
|
|
67
66
|
"oxlint": ">=1.76.0 <1.77.0",
|
|
68
67
|
"prompts": "^2.4.2",
|
|
69
68
|
"react": "19.2.5",
|
|
69
|
+
"terminal-link": "^5.0.0",
|
|
70
70
|
"typescript": ">=5.0.4 <6",
|
|
71
71
|
"vscode-languageserver": "^9.0.1",
|
|
72
72
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
73
73
|
"vscode-uri": "^3.1.0",
|
|
74
74
|
"yaml": "^2.9.0",
|
|
75
75
|
"deslop-js": "0.9.4",
|
|
76
|
-
"oxlint-plugin-react-doctor": "0.9.4-dev.
|
|
76
|
+
"oxlint-plugin-react-doctor": "0.9.4-dev.bafef41"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
"commander": "^14.0.3",
|
|
84
84
|
"ink-testing-library": "^4.0.0",
|
|
85
85
|
"ora": "^9.4.0",
|
|
86
|
+
"@react-doctor/api": "0.9.4",
|
|
86
87
|
"@react-doctor/language-server": "0.9.4",
|
|
87
|
-
"@react-doctor/core": "0.9.4"
|
|
88
|
-
"@react-doctor/api": "0.9.4"
|
|
88
|
+
"@react-doctor/core": "0.9.4"
|
|
89
89
|
},
|
|
90
90
|
"engines": {
|
|
91
91
|
"node": "^20.19.0 || >=22.13.0"
|