react-doctor 0.9.4 → 0.9.5-dev.4b03b15
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/README.md +0 -2
- package/dist/chunk-q7NCDQ7-.js +28 -0
- package/dist/cli.js +7433 -92141
- package/dist/devtools-BQATi33M.js +17003 -0
- package/dist/exit-gracefully-CWpoNtfk.js +84177 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +236 -66
- package/dist/lsp.js +278 -63
- package/dist/run-scan-app-BLZb7ws3.js +28311 -0
- package/package.json +11 -10
- package/dist/run-scan-app-QbtG43NL.js +0 -2326
package/dist/lsp.js
CHANGED
|
@@ -14,8 +14,8 @@ import { ResolverFactory } from "oxc-resolver";
|
|
|
14
14
|
import ts from "typescript";
|
|
15
15
|
import * as NodeUrl from "node:url";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { parseJSON5 } from "confbox";
|
|
18
17
|
import { createJiti } from "jiti";
|
|
18
|
+
import { parseJSON5 } from "confbox";
|
|
19
19
|
import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
|
|
20
20
|
import { convertToTSX } from "@astrojs/compiler/sync";
|
|
21
21
|
import { gzipSync } from "node:zlib";
|
|
@@ -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
|
*
|
|
@@ -62338,7 +62384,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
62338
62384
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
62339
62385
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
62340
62386
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
62341
|
-
const CORE_PACKAGE_VERSION = "0.9.
|
|
62387
|
+
const CORE_PACKAGE_VERSION = "0.9.5";
|
|
62342
62388
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
62343
62389
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
62344
62390
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -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 = {
|
|
@@ -66817,6 +66880,11 @@ var DeadCodeResultCacheEnabled = class extends Reference("react-doctor/DeadCodeR
|
|
|
66817
66880
|
if (CACHE_DISABLED_VALUES.has(noDeadCodeCache)) return false;
|
|
66818
66881
|
return true;
|
|
66819
66882
|
} }) {};
|
|
66883
|
+
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
66884
|
+
const imported = await jitiInstance.import(filePath);
|
|
66885
|
+
return imported?.default ?? imported;
|
|
66886
|
+
};
|
|
66887
|
+
const readJson5File = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
|
|
66820
66888
|
const DIAGNOSTIC_SURFACES = [
|
|
66821
66889
|
"cli",
|
|
66822
66890
|
"prComment",
|
|
@@ -66911,6 +66979,43 @@ const validateStringArrayField = (fieldName, value) => {
|
|
|
66911
66979
|
return false;
|
|
66912
66980
|
});
|
|
66913
66981
|
};
|
|
66982
|
+
const validateIgnoreOverride = (rawOverride, index) => {
|
|
66983
|
+
const fieldName = `ignore.overrides[${index}]`;
|
|
66984
|
+
if (!isRecord(rawOverride)) {
|
|
66985
|
+
warnConfigIssue(`config field "${fieldName}" must be an object (got ${typeof rawOverride}); ignoring this override.`);
|
|
66986
|
+
return;
|
|
66987
|
+
}
|
|
66988
|
+
const files = validateStringArrayField(`${fieldName}.files`, rawOverride.files);
|
|
66989
|
+
if (files === void 0) return void 0;
|
|
66990
|
+
const validatedOverride = { files };
|
|
66991
|
+
if (rawOverride.rules !== void 0) {
|
|
66992
|
+
const rules = validateStringArrayField(`${fieldName}.rules`, rawOverride.rules);
|
|
66993
|
+
if (rules !== void 0) validatedOverride.rules = rules;
|
|
66994
|
+
}
|
|
66995
|
+
return validatedOverride;
|
|
66996
|
+
};
|
|
66997
|
+
const validateIgnoreField = (rawIgnore) => {
|
|
66998
|
+
if (!isRecord(rawIgnore)) {
|
|
66999
|
+
warnConfigIssue(`config field "ignore" must be an object (got ${typeof rawIgnore}); ignoring this field.`);
|
|
67000
|
+
return;
|
|
67001
|
+
}
|
|
67002
|
+
const validatedIgnore = {};
|
|
67003
|
+
for (const fieldName of [
|
|
67004
|
+
"rules",
|
|
67005
|
+
"files",
|
|
67006
|
+
"tags"
|
|
67007
|
+
]) {
|
|
67008
|
+
if (rawIgnore[fieldName] === void 0) continue;
|
|
67009
|
+
const validatedValues = validateStringArrayField(`ignore.${fieldName}`, rawIgnore[fieldName]);
|
|
67010
|
+
if (validatedValues !== void 0) validatedIgnore[fieldName] = validatedValues;
|
|
67011
|
+
}
|
|
67012
|
+
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.`);
|
|
67013
|
+
else validatedIgnore.overrides = rawIgnore.overrides.flatMap((rawOverride, index) => {
|
|
67014
|
+
const validatedOverride = validateIgnoreOverride(rawOverride, index);
|
|
67015
|
+
return validatedOverride ? [validatedOverride] : [];
|
|
67016
|
+
});
|
|
67017
|
+
return validatedIgnore;
|
|
67018
|
+
};
|
|
66914
67019
|
const validateSurfaceControls = (surface, rawControls) => {
|
|
66915
67020
|
if (!isRecord(rawControls)) {
|
|
66916
67021
|
warnConfigIssue(`config field "surfaces.${surface}" must be an object (got ${typeof rawControls}); ignoring this surface.`);
|
|
@@ -66986,6 +67091,7 @@ const validateConfigTypes = (config) => {
|
|
|
66986
67091
|
for (const fieldName of BOOLEAN_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => coerceMaybeBooleanString(fieldName, value));
|
|
66987
67092
|
for (const fieldName of STRING_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateString(fieldName, value));
|
|
66988
67093
|
for (const fieldName of STRING_ARRAY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateStringArrayField(fieldName, value));
|
|
67094
|
+
applyFieldValidator(config, validated, "ignore", validateIgnoreField);
|
|
66989
67095
|
applyFieldValidator(config, validated, "surfaces", validateSurfacesField);
|
|
66990
67096
|
for (const fieldName of SEVERITY_FIELD_NAMES) applyFieldValidator(config, validated, fieldName, (value) => validateSeverityMap(fieldName, value, fieldName === "categories"));
|
|
66991
67097
|
applyFieldValidator(config, validated, "plugins", (value) => validateStringArrayField("plugins", value));
|
|
@@ -67009,11 +67115,7 @@ const DATA_CONFIG_EXTENSIONS = new Set(["json", "jsonc"]);
|
|
|
67009
67115
|
const PACKAGE_JSON_FILENAME = "package.json";
|
|
67010
67116
|
const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
|
|
67011
67117
|
const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
|
|
67012
|
-
const jiti = createJiti(import.meta.url);
|
|
67013
|
-
const importDefaultExport = async (jitiInstance, filePath) => {
|
|
67014
|
-
const imported = await jitiInstance.import(filePath);
|
|
67015
|
-
return imported?.default ?? imported;
|
|
67016
|
-
};
|
|
67118
|
+
const jiti$1 = createJiti(import.meta.url);
|
|
67017
67119
|
const SELF_PACKAGE_IMPORT_SPECIFIER = "react-doctor/api";
|
|
67018
67120
|
const SELF_PACKAGE_RESOLVE_TARGETS = ["react-doctor/api", "@react-doctor/core"];
|
|
67019
67121
|
const MODULE_NOT_FOUND_ERROR_CODES = new Set(["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"]);
|
|
@@ -67021,7 +67123,7 @@ let selfAliasJiti;
|
|
|
67021
67123
|
const getSelfAliasJiti = () => {
|
|
67022
67124
|
if (selfAliasJiti !== void 0) return selfAliasJiti;
|
|
67023
67125
|
for (const resolveTarget of SELF_PACKAGE_RESOLVE_TARGETS) try {
|
|
67024
|
-
const aliasTargetPath = fileURLToPath(jiti.esmResolve(resolveTarget));
|
|
67126
|
+
const aliasTargetPath = fileURLToPath(jiti$1.esmResolve(resolveTarget));
|
|
67025
67127
|
selfAliasJiti = createJiti(import.meta.url, { alias: { [SELF_PACKAGE_IMPORT_SPECIFIER]: aliasTargetPath } });
|
|
67026
67128
|
return selfAliasJiti;
|
|
67027
67129
|
} catch {
|
|
@@ -67033,7 +67135,7 @@ const getSelfAliasJiti = () => {
|
|
|
67033
67135
|
const isSelfPackageResolutionError = (error) => error instanceof Error && "code" in error && typeof error.code === "string" && MODULE_NOT_FOUND_ERROR_CODES.has(error.code) && error.message.includes(SELF_PACKAGE_IMPORT_SPECIFIER);
|
|
67034
67136
|
const loadModuleConfig = async (filePath) => {
|
|
67035
67137
|
try {
|
|
67036
|
-
return await importDefaultExport(jiti, filePath);
|
|
67138
|
+
return await importDefaultExport(jiti$1, filePath);
|
|
67037
67139
|
} catch (error) {
|
|
67038
67140
|
if (!isSelfPackageResolutionError(error)) throw error;
|
|
67039
67141
|
const aliasJiti = getSelfAliasJiti();
|
|
@@ -67045,12 +67147,11 @@ const loadModuleConfig = async (filePath) => {
|
|
|
67045
67147
|
}
|
|
67046
67148
|
}
|
|
67047
67149
|
};
|
|
67048
|
-
const readDataConfig = (filePath) => parseJSON5(NFS.readFileSync(filePath, "utf-8"));
|
|
67049
67150
|
const readEmbeddedPackageJsonConfig = (directory) => {
|
|
67050
67151
|
const packageJsonPath = Path.join(directory, PACKAGE_JSON_FILENAME);
|
|
67051
67152
|
if (!isFile(packageJsonPath)) return null;
|
|
67052
67153
|
try {
|
|
67053
|
-
const packageJson =
|
|
67154
|
+
const packageJson = readJson5File(packageJsonPath);
|
|
67054
67155
|
if (isPlainObject(packageJson)) {
|
|
67055
67156
|
const embeddedConfig = packageJson[PACKAGE_JSON_CONFIG_KEY];
|
|
67056
67157
|
if (isPlainObject(embeddedConfig)) return embeddedConfig;
|
|
@@ -67075,7 +67176,7 @@ const loadLegacyConfig = (directory) => {
|
|
|
67075
67176
|
loaded: null
|
|
67076
67177
|
};
|
|
67077
67178
|
try {
|
|
67078
|
-
const parsed =
|
|
67179
|
+
const parsed = readJson5File(legacyFilePath);
|
|
67079
67180
|
if (isPlainObject(parsed)) {
|
|
67080
67181
|
warn(`${LEGACY_CONFIG_FILENAME} is deprecated — rename it to ${CONFIG_BASENAME}.json (or author a ${CONFIG_BASENAME}.ts). It is still read for now.`);
|
|
67081
67182
|
return {
|
|
@@ -67104,7 +67205,7 @@ const loadConfigFromDirectory = async (directory) => {
|
|
|
67104
67205
|
if (!isFile(filePath)) continue;
|
|
67105
67206
|
const isDataFile = DATA_CONFIG_EXTENSIONS.has(extension);
|
|
67106
67207
|
try {
|
|
67107
|
-
const parsed = isDataFile ?
|
|
67208
|
+
const parsed = isDataFile ? readJson5File(filePath) : await loadModuleConfig(filePath);
|
|
67108
67209
|
if (isPlainObject(parsed)) return {
|
|
67109
67210
|
status: "found",
|
|
67110
67211
|
loaded: {
|
|
@@ -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
|
}
|
|
@@ -69258,20 +69359,45 @@ const collectIgnorePatterns = (rootDirectory) => {
|
|
|
69258
69359
|
cachedPatternsByRoot.set(rootDirectory, patterns);
|
|
69259
69360
|
return patterns;
|
|
69260
69361
|
};
|
|
69261
|
-
const
|
|
69362
|
+
const KNIP_DATA_CONFIG_FILENAMES = new Set([
|
|
69363
|
+
"knip.json",
|
|
69364
|
+
"knip.jsonc",
|
|
69365
|
+
".knip.json",
|
|
69366
|
+
".knip.jsonc"
|
|
69367
|
+
]);
|
|
69368
|
+
const KNIP_CONFIG_FILENAMES = [
|
|
69369
|
+
...KNIP_DATA_CONFIG_FILENAMES,
|
|
69370
|
+
"knip.ts",
|
|
69371
|
+
"knip.js",
|
|
69372
|
+
"knip.config.ts",
|
|
69373
|
+
"knip.config.js"
|
|
69374
|
+
];
|
|
69375
|
+
const jiti = createJiti(import.meta.url, { moduleCache: false });
|
|
69376
|
+
const resolveKnipConfigExport = async (configExport) => {
|
|
69377
|
+
const config = typeof configExport === "function" ? await configExport() : await configExport;
|
|
69378
|
+
return isRecord(config) ? config : null;
|
|
69379
|
+
};
|
|
69380
|
+
const loadKnipConfigFile = async (configFilename, filePath) => {
|
|
69262
69381
|
try {
|
|
69263
|
-
return
|
|
69382
|
+
return await resolveKnipConfigExport(KNIP_DATA_CONFIG_FILENAMES.has(configFilename) ? readJson5File(filePath) : await importDefaultExport(jiti, filePath));
|
|
69264
69383
|
} catch {
|
|
69265
|
-
return
|
|
69384
|
+
return null;
|
|
69266
69385
|
}
|
|
69267
69386
|
};
|
|
69268
|
-
const
|
|
69269
|
-
const
|
|
69270
|
-
|
|
69271
|
-
|
|
69272
|
-
|
|
69273
|
-
|
|
69274
|
-
|
|
69387
|
+
const loadKnipConfig = async (rootDirectory) => {
|
|
69388
|
+
for (const configFilename of KNIP_CONFIG_FILENAMES) {
|
|
69389
|
+
const filePath = path.join(rootDirectory, configFilename);
|
|
69390
|
+
if (!isFile(filePath)) continue;
|
|
69391
|
+
const config = await loadKnipConfigFile(configFilename, filePath);
|
|
69392
|
+
if (config) return config;
|
|
69393
|
+
}
|
|
69394
|
+
try {
|
|
69395
|
+
const packageJson = readJson5File(path.join(rootDirectory, "package.json"));
|
|
69396
|
+
const packageKnipConfig = isRecord(packageJson) ? packageJson.knip : null;
|
|
69397
|
+
return isRecord(packageKnipConfig) ? packageKnipConfig : null;
|
|
69398
|
+
} catch {
|
|
69399
|
+
return null;
|
|
69400
|
+
}
|
|
69275
69401
|
};
|
|
69276
69402
|
const normalizePatternList = (value) => {
|
|
69277
69403
|
if (typeof value === "string" && value.length > 0) return [value];
|
|
@@ -69291,22 +69417,28 @@ const collectKnipWorkspacePatterns = (workspaces, settingName) => {
|
|
|
69291
69417
|
}
|
|
69292
69418
|
return patterns;
|
|
69293
69419
|
};
|
|
69294
|
-
const collectKnipPatterns = (
|
|
69295
|
-
const config = readKnipConfig(rootDirectory);
|
|
69420
|
+
const collectKnipPatterns = (config, settingName) => {
|
|
69296
69421
|
if (!config) return [];
|
|
69297
69422
|
return [...normalizePatternList(config[settingName]), ...collectKnipWorkspacePatterns(config.workspaces, settingName)];
|
|
69298
69423
|
};
|
|
69299
|
-
const collectDeadCodeIgnorePatterns = (rootDirectory) => {
|
|
69424
|
+
const collectDeadCodeIgnorePatterns = (rootDirectory, config) => {
|
|
69300
69425
|
const seen = /* @__PURE__ */ new Set();
|
|
69301
69426
|
const sources = [
|
|
69302
69427
|
readIgnoreFile(path.join(rootDirectory, ".gitignore")),
|
|
69303
69428
|
collectIgnorePatterns(rootDirectory),
|
|
69304
|
-
collectKnipPatterns(
|
|
69429
|
+
collectKnipPatterns(config, "ignore")
|
|
69305
69430
|
];
|
|
69306
69431
|
for (const source of sources) for (const pattern of source) seen.add(pattern);
|
|
69307
69432
|
return [...seen].filter((pattern) => pattern.length > 0);
|
|
69308
69433
|
};
|
|
69309
|
-
const collectDeadCodeEntryPatterns = (
|
|
69434
|
+
const collectDeadCodeEntryPatterns = (config) => [...new Set(collectKnipPatterns(config, "entry"))].filter((pattern) => pattern.length > 0);
|
|
69435
|
+
const collectDeadCodePatterns = async (rootDirectory) => {
|
|
69436
|
+
const config = await loadKnipConfig(rootDirectory);
|
|
69437
|
+
return {
|
|
69438
|
+
entryPatterns: collectDeadCodeEntryPatterns(config),
|
|
69439
|
+
ignorePatterns: collectDeadCodeIgnorePatterns(rootDirectory, config)
|
|
69440
|
+
};
|
|
69441
|
+
};
|
|
69310
69442
|
const atomicWriteJson = (filePath, value) => {
|
|
69311
69443
|
try {
|
|
69312
69444
|
NFS.mkdirSync(Path.dirname(filePath), { recursive: true });
|
|
@@ -69317,6 +69449,13 @@ const atomicWriteJson = (filePath, value) => {
|
|
|
69317
69449
|
return;
|
|
69318
69450
|
}
|
|
69319
69451
|
};
|
|
69452
|
+
const failOpenReadJson = (filePath, fallback) => {
|
|
69453
|
+
try {
|
|
69454
|
+
return JSON.parse(NFS.readFileSync(filePath, "utf8"));
|
|
69455
|
+
} catch {
|
|
69456
|
+
return fallback;
|
|
69457
|
+
}
|
|
69458
|
+
};
|
|
69320
69459
|
const hashFileContents = (filePath) => {
|
|
69321
69460
|
try {
|
|
69322
69461
|
return crypto.createHash("sha1").update(NFS.readFileSync(filePath)).digest("hex");
|
|
@@ -69325,7 +69464,7 @@ const hashFileContents = (filePath) => {
|
|
|
69325
69464
|
}
|
|
69326
69465
|
};
|
|
69327
69466
|
const ANALYZED_FILE_EXTENSIONS = new Set(DEFAULT_EXTENSIONS);
|
|
69328
|
-
const CORE_SIDE_MANIFEST_NAMES = [
|
|
69467
|
+
const CORE_SIDE_MANIFEST_NAMES = [...KNIP_CONFIG_FILENAMES, "deno.lock"];
|
|
69329
69468
|
const ANALYZED_MANIFEST_NAMES = new Set([...ANALYZED_MANIFEST_FILENAMES, ...CORE_SIDE_MANIFEST_NAMES]);
|
|
69330
69469
|
const isTsConfigLikeFile = (fileName) => (fileName.startsWith("tsconfig") || fileName.startsWith("jsconfig")) && fileName.endsWith(".json");
|
|
69331
69470
|
const isFingerprintedFile = (fileName) => ANALYZED_FILE_EXTENSIONS.has(Path.extname(fileName).toLowerCase()) || ANALYZED_MANIFEST_NAMES.has(fileName) || isTsConfigLikeFile(fileName);
|
|
@@ -69851,8 +69990,7 @@ const runDeadCodeWorkerWithTimeout = (handle, timeoutMs, abortSignal) => new Pro
|
|
|
69851
69990
|
const checkDeadCode = async (options) => {
|
|
69852
69991
|
const rootDirectory = toCanonicalPath(options.rootDirectory);
|
|
69853
69992
|
if (!NFS.existsSync(Path.join(rootDirectory, "package.json"))) return [];
|
|
69854
|
-
const entryPatterns =
|
|
69855
|
-
const ignorePatterns = collectDeadCodeIgnorePatterns(rootDirectory);
|
|
69993
|
+
const { entryPatterns, ignorePatterns } = await collectDeadCodePatterns(rootDirectory);
|
|
69856
69994
|
const tsConfigPath = resolveTsConfigPath(rootDirectory);
|
|
69857
69995
|
const deslopJsModuleSpecifier = options.deslopJsModuleSpecifier ?? import.meta.resolve("deslop-js");
|
|
69858
69996
|
const fileStatsSnapshot = options.cacheEnabled ? collectAnalyzedFileStats(rootDirectory) : null;
|
|
@@ -70586,7 +70724,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
70586
70724
|
changedFiles: yield* mergeUntracked(directory, splitNullSeparated(diff.stdout), includeUntracked),
|
|
70587
70725
|
isCurrentChanges: false
|
|
70588
70726
|
};
|
|
70589
|
-
}).pipe(withSpan("Git.diffSelection")),
|
|
70727
|
+
}).pipe(catchReasons("ReactDoctorError", { GitInvocationFailed: () => succeed$2(null) }, (_reason, error) => fail$4(error)), withSpan("Git.diffSelection")),
|
|
70590
70728
|
stagedFilePaths: (directory) => runGit(directory, [
|
|
70591
70729
|
"diff",
|
|
70592
70730
|
"--no-ext-diff",
|
|
@@ -70802,6 +70940,33 @@ const detectUserLintConfigPaths = (rootDirectory) => {
|
|
|
70802
70940
|
return [];
|
|
70803
70941
|
};
|
|
70804
70942
|
const DISABLE_DIRECTIVE_PATTERN = /(eslint|oxlint)-disable/;
|
|
70943
|
+
const neutralizedFileLeases = /* @__PURE__ */ new Map();
|
|
70944
|
+
const activeNeutralizationInitializations = /* @__PURE__ */ new Set();
|
|
70945
|
+
const directoriesOverlap = (left, right) => {
|
|
70946
|
+
const isWithin = (parent, candidate) => {
|
|
70947
|
+
const relativePath = Path.relative(parent, candidate);
|
|
70948
|
+
return relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath);
|
|
70949
|
+
};
|
|
70950
|
+
return isWithin(left, right) || isWithin(right, left);
|
|
70951
|
+
};
|
|
70952
|
+
const withOverlappingInitializationLock = async (rootDirectory, operation) => {
|
|
70953
|
+
const blockers = [...activeNeutralizationInitializations].filter((initialization) => directoriesOverlap(initialization.rootDirectory, rootDirectory)).map((initialization) => initialization.done);
|
|
70954
|
+
let release;
|
|
70955
|
+
const initialization = {
|
|
70956
|
+
rootDirectory,
|
|
70957
|
+
done: new Promise((resolve) => {
|
|
70958
|
+
release = resolve;
|
|
70959
|
+
})
|
|
70960
|
+
};
|
|
70961
|
+
activeNeutralizationInitializations.add(initialization);
|
|
70962
|
+
await Promise.all(blockers);
|
|
70963
|
+
try {
|
|
70964
|
+
return await operation();
|
|
70965
|
+
} finally {
|
|
70966
|
+
activeNeutralizationInitializations.delete(initialization);
|
|
70967
|
+
release();
|
|
70968
|
+
}
|
|
70969
|
+
};
|
|
70805
70970
|
const findFilesWithDisableDirectivesViaGit = async (rootDirectory, includePaths) => {
|
|
70806
70971
|
const program = gen(function* () {
|
|
70807
70972
|
return yield* (yield* Git).grep({
|
|
@@ -70844,34 +71009,84 @@ const findFilesWithDisableDirectivesViaFilesystem = (rootDirectory, includePaths
|
|
|
70844
71009
|
};
|
|
70845
71010
|
const findFilesWithDisableDirectives = async (rootDirectory, includePaths) => await findFilesWithDisableDirectivesViaGit(rootDirectory, includePaths) ?? findFilesWithDisableDirectivesViaFilesystem(rootDirectory, includePaths);
|
|
70846
71011
|
const neutralizeContent = (content) => content.replaceAll("eslint-disable", "eslint_disable").replaceAll("oxlint-disable", "oxlint_disable");
|
|
70847
|
-
const
|
|
70848
|
-
const
|
|
70849
|
-
const
|
|
71012
|
+
const collectNeutralizationCandidatePaths = (rootDirectory, discoveredRelativePaths, includePaths) => {
|
|
71013
|
+
const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
|
|
71014
|
+
const requestedPaths = includePaths && includePaths.length > 0 ? new Set(includePaths.flatMap((includePath) => {
|
|
71015
|
+
try {
|
|
71016
|
+
return [NFS.realpathSync(Path.resolve(resolvedRootDirectory, includePath))];
|
|
71017
|
+
} catch {
|
|
71018
|
+
return [];
|
|
71019
|
+
}
|
|
71020
|
+
})) : null;
|
|
71021
|
+
const candidatePaths = /* @__PURE__ */ new Set();
|
|
71022
|
+
for (const relativePath of discoveredRelativePaths) try {
|
|
71023
|
+
candidatePaths.add(NFS.realpathSync(Path.resolve(resolvedRootDirectory, relativePath)));
|
|
71024
|
+
} catch {
|
|
71025
|
+
continue;
|
|
71026
|
+
}
|
|
71027
|
+
for (const leasedPath of neutralizedFileLeases.keys()) {
|
|
71028
|
+
const relativePath = Path.relative(resolvedRootDirectory, leasedPath);
|
|
71029
|
+
if (!(relativePath.length === 0 || !relativePath.startsWith(`..${Path.sep}`) && relativePath !== ".." && !Path.isAbsolute(relativePath)) || requestedPaths && !requestedPaths.has(leasedPath)) continue;
|
|
71030
|
+
candidatePaths.add(leasedPath);
|
|
71031
|
+
}
|
|
71032
|
+
return candidatePaths;
|
|
71033
|
+
};
|
|
71034
|
+
const neutralizeDisableDirectives = async (rootDirectory, includePaths, options = {}) => {
|
|
71035
|
+
const resolvedRootDirectory = NFS.realpathSync(rootDirectory);
|
|
71036
|
+
const leasedPaths = /* @__PURE__ */ new Set();
|
|
70850
71037
|
let isRestored = false;
|
|
70851
71038
|
const restore = () => {
|
|
70852
71039
|
if (isRestored) return;
|
|
70853
71040
|
isRestored = true;
|
|
70854
|
-
for (const
|
|
70855
|
-
|
|
70856
|
-
|
|
70857
|
-
|
|
71041
|
+
for (const absolutePath of leasedPaths) {
|
|
71042
|
+
const lease = neutralizedFileLeases.get(absolutePath);
|
|
71043
|
+
if (!lease) continue;
|
|
71044
|
+
lease.referenceCount -= 1;
|
|
71045
|
+
if (lease.referenceCount > 0) continue;
|
|
71046
|
+
neutralizedFileLeases.delete(absolutePath);
|
|
71047
|
+
try {
|
|
71048
|
+
NFS.writeFileSync(absolutePath, lease.originalContent);
|
|
71049
|
+
} catch (error) {
|
|
71050
|
+
process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
|
|
71051
|
+
}
|
|
70858
71052
|
}
|
|
70859
71053
|
};
|
|
70860
71054
|
const onExit = () => restore();
|
|
70861
71055
|
process.once("exit", onExit);
|
|
70862
|
-
|
|
70863
|
-
|
|
71056
|
+
const leaseCandidatePath = (absolutePath) => {
|
|
71057
|
+
if (leasedPaths.has(absolutePath)) return;
|
|
71058
|
+
const existingLease = neutralizedFileLeases.get(absolutePath);
|
|
71059
|
+
if (existingLease) {
|
|
71060
|
+
existingLease.referenceCount += 1;
|
|
71061
|
+
leasedPaths.add(absolutePath);
|
|
71062
|
+
return;
|
|
71063
|
+
}
|
|
70864
71064
|
let originalContent;
|
|
70865
71065
|
try {
|
|
70866
71066
|
originalContent = NFS.readFileSync(absolutePath, "utf-8");
|
|
70867
71067
|
} catch {
|
|
70868
|
-
|
|
71068
|
+
return;
|
|
70869
71069
|
}
|
|
70870
71070
|
const neutralizedContent = neutralizeContent(originalContent);
|
|
70871
71071
|
if (neutralizedContent !== originalContent) {
|
|
70872
|
-
originalContents.set(absolutePath, originalContent);
|
|
70873
71072
|
NFS.writeFileSync(absolutePath, neutralizedContent);
|
|
71073
|
+
neutralizedFileLeases.set(absolutePath, {
|
|
71074
|
+
originalContent,
|
|
71075
|
+
referenceCount: 1
|
|
71076
|
+
});
|
|
71077
|
+
leasedPaths.add(absolutePath);
|
|
70874
71078
|
}
|
|
71079
|
+
};
|
|
71080
|
+
try {
|
|
71081
|
+
await withOverlappingInitializationLock(resolvedRootDirectory, async () => {
|
|
71082
|
+
for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, [], includePaths)) if (neutralizedFileLeases.has(absolutePath)) leaseCandidatePath(absolutePath);
|
|
71083
|
+
const discoveredRelativePaths = await (options.findFiles ?? findFilesWithDisableDirectives)(resolvedRootDirectory, includePaths);
|
|
71084
|
+
for (const absolutePath of collectNeutralizationCandidatePaths(resolvedRootDirectory, discoveredRelativePaths, includePaths)) leaseCandidatePath(absolutePath);
|
|
71085
|
+
});
|
|
71086
|
+
} catch (error) {
|
|
71087
|
+
restore();
|
|
71088
|
+
process.removeListener("exit", onExit);
|
|
71089
|
+
throw error;
|
|
70875
71090
|
}
|
|
70876
71091
|
return () => {
|
|
70877
71092
|
restore();
|
|
@@ -75206,7 +75421,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
75206
75421
|
const sourcePath = path.join(input.directory, subdirectory, configFilename);
|
|
75207
75422
|
const targetPath = path.resolve(resolvedTempDirectory, subdirectory, configFilename);
|
|
75208
75423
|
if (!isPathInsideDirectory(targetPath, resolvedTempDirectory)) continue;
|
|
75209
|
-
if (
|
|
75424
|
+
if (isFile(sourcePath) && !fs.existsSync(targetPath)) {
|
|
75210
75425
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
75211
75426
|
fs.cpSync(sourcePath, targetPath);
|
|
75212
75427
|
}
|
|
@@ -75386,7 +75601,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
75386
75601
|
/** Display name used in client-facing messages and progress titles. */
|
|
75387
75602
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
75388
75603
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
75389
|
-
const SERVER_VERSION = "0.9.
|
|
75604
|
+
const SERVER_VERSION = "0.9.5";
|
|
75390
75605
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
75391
75606
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
75392
75607
|
/**
|
|
@@ -77120,7 +77335,7 @@ const METRIC = {
|
|
|
77120
77335
|
tuiFindingNavigated: "tui.finding_navigated",
|
|
77121
77336
|
tuiIssueStreamShown: "tui.issue_stream_shown",
|
|
77122
77337
|
tuiProjectPathContextShown: "tui.project_path_context_shown",
|
|
77123
|
-
|
|
77338
|
+
tuiProjectSelectShown: "tui.project_select_shown",
|
|
77124
77339
|
tuiReportActionSelected: "tui.report_action_selected",
|
|
77125
77340
|
tuiCancelled: "tui.cancelled",
|
|
77126
77341
|
tuiScanInlineShown: "tui.scan_inline_shown",
|
|
@@ -77428,5 +77643,5 @@ const startLanguageServer = () => {
|
|
|
77428
77643
|
};
|
|
77429
77644
|
//#endregion
|
|
77430
77645
|
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=
|
|
77646
|
+
!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]="57ccd601-03eb-51e3-a852-2e296333f7ea")}catch(e){}}();
|
|
77647
|
+
//# debugId=57ccd601-03eb-51e3-a852-2e296333f7ea
|