react-doctor 0.8.3 → 0.9.0-dev.30369b6
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 +277 -181
- package/dist/index.js +35 -18
- package/dist/lsp.js +38 -21
- package/dist/run-scan-app-DZ5jGWFf.js +1661 -0
- package/package.json +13 -7
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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]="b50e5764-57f0-54b7-81f8-530e6656066f")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -64656,6 +64656,13 @@ const IGNORED_DIRECTORIES = new Set([
|
|
|
64656
64656
|
"storybook-static"
|
|
64657
64657
|
]);
|
|
64658
64658
|
const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
|
|
64659
|
+
const TYPESCRIPT_DECLARATION_FILE_PATTERN = /\.d\.(?:ts|mts|cts)$/;
|
|
64660
|
+
const OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES = new Set([
|
|
64661
|
+
"TS(1036)",
|
|
64662
|
+
"TS(1038)",
|
|
64663
|
+
"TS(1183)",
|
|
64664
|
+
"TS(1319)"
|
|
64665
|
+
]);
|
|
64659
64666
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
64660
64667
|
const REACT_ROUTER_CAPABILITY_THRESHOLDS = [
|
|
64661
64668
|
{
|
|
@@ -64957,6 +64964,14 @@ const DIAGNOSTIC_CATEGORY_BUCKETS = [
|
|
|
64957
64964
|
"Maintainability"
|
|
64958
64965
|
];
|
|
64959
64966
|
const OCCURRENCE_MATCHED_CATEGORIES = new Set(["Accessibility"]);
|
|
64967
|
+
const CATEGORY_IMPACT_BY_NAME = new Map(Object.entries({
|
|
64968
|
+
Security: "An attacker can read user data, act as your users, or run code you never shipped.",
|
|
64969
|
+
Bugs: "Real users hit crashes, wrong output, or state that silently corrupts.",
|
|
64970
|
+
Performance: "Users feel extra latency and wasted renders on every interaction.",
|
|
64971
|
+
Accessibility: "Users on screen readers, keyboards, or assistive tech get locked out.",
|
|
64972
|
+
Maintainability: "Every future change gets slower and riskier to make."
|
|
64973
|
+
}));
|
|
64974
|
+
const getCategoryImpact = (category) => CATEGORY_IMPACT_BY_NAME.get(category);
|
|
64960
64975
|
const APP_ONLY_RULE_KEYS = new Set([
|
|
64961
64976
|
"react-hooks-js/static-components",
|
|
64962
64977
|
"react-doctor/no-render-prop-children",
|
|
@@ -64979,7 +64994,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
64979
64994
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
64980
64995
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
64981
64996
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
64982
|
-
const CORE_PACKAGE_VERSION = "0.
|
|
64997
|
+
const CORE_PACKAGE_VERSION = "0.9.0";
|
|
64983
64998
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
64984
64999
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
64985
65000
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -65364,6 +65379,7 @@ const frameworkMergeRank = (framework) => {
|
|
|
65364
65379
|
return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
|
|
65365
65380
|
};
|
|
65366
65381
|
const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
|
|
65382
|
+
const REACT_COMPILER_RUNTIME_PACKAGES = new Set(["react-compiler-runtime"]);
|
|
65367
65383
|
const NEXT_CONFIG_FILENAMES = [
|
|
65368
65384
|
"next.config.js",
|
|
65369
65385
|
"next.config.mjs",
|
|
@@ -65700,18 +65716,20 @@ const getReactCompilerFlagState = (expression, analysis) => {
|
|
|
65700
65716
|
}
|
|
65701
65717
|
return null;
|
|
65702
65718
|
};
|
|
65703
|
-
const getSelectedObjectProperty = (expression, propertyName, analysis) => {
|
|
65719
|
+
const getSelectedObjectProperty = (expression, propertyName, analysis, visitedExpressions = /* @__PURE__ */ new Set()) => {
|
|
65704
65720
|
let resolvedExpression = expression;
|
|
65705
65721
|
while (ts.isParenthesizedExpression(resolvedExpression) || ts.isAsExpression(resolvedExpression) || ts.isTypeAssertionExpression(resolvedExpression) || ts.isSatisfiesExpression(resolvedExpression) || ts.isNonNullExpression(resolvedExpression)) resolvedExpression = resolvedExpression.expression;
|
|
65722
|
+
if (visitedExpressions.has(resolvedExpression)) return null;
|
|
65723
|
+
visitedExpressions.add(resolvedExpression);
|
|
65706
65724
|
if (ts.isIdentifier(resolvedExpression)) {
|
|
65707
65725
|
if (analysis.localBindings.has(resolvedExpression.text)) {
|
|
65708
65726
|
const localInitializer = analysis.localBindings.get(resolvedExpression.text);
|
|
65709
|
-
return localInitializer ? getSelectedObjectProperty(localInitializer, propertyName, analysis) : null;
|
|
65727
|
+
return localInitializer ? getSelectedObjectProperty(localInitializer, propertyName, analysis, visitedExpressions) : null;
|
|
65710
65728
|
}
|
|
65711
65729
|
const scopedBinding = getScopedConfigBinding(resolvedExpression);
|
|
65712
|
-
if (scopedBinding.wasFound) return scopedBinding.initializer ? getSelectedObjectProperty(scopedBinding.initializer, propertyName, analysis) : null;
|
|
65730
|
+
if (scopedBinding.wasFound) return scopedBinding.initializer ? getSelectedObjectProperty(scopedBinding.initializer, propertyName, analysis, visitedExpressions) : null;
|
|
65713
65731
|
const topLevelBinding = getTopLevelBinding(analysis.sourceFile, resolvedExpression.text);
|
|
65714
|
-
return topLevelBinding && ts.isExpression(topLevelBinding) ? getSelectedObjectProperty(topLevelBinding, propertyName, analysis) : null;
|
|
65732
|
+
return topLevelBinding && ts.isExpression(topLevelBinding) ? getSelectedObjectProperty(topLevelBinding, propertyName, analysis, visitedExpressions) : null;
|
|
65715
65733
|
}
|
|
65716
65734
|
if (!ts.isObjectLiteralExpression(resolvedExpression)) return null;
|
|
65717
65735
|
for (const property of [...resolvedExpression.properties].reverse()) {
|
|
@@ -65719,7 +65737,7 @@ const getSelectedObjectProperty = (expression, propertyName, analysis) => {
|
|
|
65719
65737
|
if (ts.isMethodDeclaration(property) && getStaticPropertyName$1(property.name) === propertyName) return property;
|
|
65720
65738
|
if (ts.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property.name;
|
|
65721
65739
|
if (ts.isSpreadAssignment(property)) {
|
|
65722
|
-
const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis);
|
|
65740
|
+
const spreadProperty = getSelectedObjectProperty(property.expression, propertyName, analysis, visitedExpressions);
|
|
65723
65741
|
if (spreadProperty) return spreadProperty;
|
|
65724
65742
|
}
|
|
65725
65743
|
}
|
|
@@ -66068,7 +66086,7 @@ const hasCompilerConfigurationInAncestors = (directory) => {
|
|
|
66068
66086
|
}
|
|
66069
66087
|
return false;
|
|
66070
66088
|
};
|
|
66071
|
-
const detectReactCompiler = (directory, packageJson) => hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
|
|
66089
|
+
const detectReactCompiler = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_RUNTIME_PACKAGES) || hasCompilerConfiguration(directory, packageJson) || hasCompilerConfigurationInAncestors(directory);
|
|
66072
66090
|
const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
|
|
66073
66091
|
const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
|
|
66074
66092
|
const filePath = Path.join(directory, filename);
|
|
@@ -73188,13 +73206,13 @@ const decodeFileDiagnostics = (raw) => {
|
|
|
73188
73206
|
}
|
|
73189
73207
|
};
|
|
73190
73208
|
const emptyCache$1 = () => ({
|
|
73191
|
-
version:
|
|
73209
|
+
version: 2,
|
|
73192
73210
|
rulesets: {}
|
|
73193
73211
|
});
|
|
73194
73212
|
const loadRulesetEntries$1 = (cacheFilePath, rulesetHash) => {
|
|
73195
73213
|
const entries = /* @__PURE__ */ new Map();
|
|
73196
73214
|
const persisted = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
73197
|
-
if (persisted.version !==
|
|
73215
|
+
if (persisted.version !== 2 || !isRecord$1(persisted.rulesets)) return entries;
|
|
73198
73216
|
const bucket = persisted.rulesets[rulesetHash];
|
|
73199
73217
|
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
73200
73218
|
for (const [fileKey, rawDiagnostics] of Object.entries(bucket.files)) {
|
|
@@ -73214,7 +73232,7 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
73214
73232
|
},
|
|
73215
73233
|
persist: () => {
|
|
73216
73234
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache$1());
|
|
73217
|
-
const rulesets = onDisk.version ===
|
|
73235
|
+
const rulesets = onDisk.version === 2 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
73218
73236
|
const existingBucket = rulesets[rulesetHash];
|
|
73219
73237
|
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
73220
73238
|
const ourFiles = {};
|
|
@@ -73228,7 +73246,7 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
73228
73246
|
files: Object.fromEntries(cappedEntries)
|
|
73229
73247
|
};
|
|
73230
73248
|
atomicWriteJson(cacheFilePath, {
|
|
73231
|
-
version:
|
|
73249
|
+
version: 2,
|
|
73232
73250
|
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord$1(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
73233
73251
|
});
|
|
73234
73252
|
}
|
|
@@ -73317,13 +73335,13 @@ const encodeSidecarFileEntry = (entry) => ({
|
|
|
73317
73335
|
diagnostics: entry.diagnostics
|
|
73318
73336
|
});
|
|
73319
73337
|
const emptyCache = () => ({
|
|
73320
|
-
version:
|
|
73338
|
+
version: 3,
|
|
73321
73339
|
rulesets: {}
|
|
73322
73340
|
});
|
|
73323
73341
|
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
73324
73342
|
const entries = /* @__PURE__ */ new Map();
|
|
73325
73343
|
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
73326
|
-
if (persisted.version !==
|
|
73344
|
+
if (persisted.version !== 3 || !isRecord$1(persisted.rulesets)) return entries;
|
|
73327
73345
|
const bucket = persisted.rulesets[rulesetHash];
|
|
73328
73346
|
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
73329
73347
|
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
@@ -73343,7 +73361,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
73343
73361
|
},
|
|
73344
73362
|
persist: () => {
|
|
73345
73363
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
73346
|
-
const rulesets = onDisk.version ===
|
|
73364
|
+
const rulesets = onDisk.version === 3 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
73347
73365
|
const existingBucket = rulesets[rulesetHash];
|
|
73348
73366
|
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
73349
73367
|
const ourFiles = {};
|
|
@@ -73357,7 +73375,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
73357
73375
|
files: Object.fromEntries(cappedEntries)
|
|
73358
73376
|
};
|
|
73359
73377
|
atomicWriteJson(cacheFilePath, {
|
|
73360
|
-
version:
|
|
73378
|
+
version: 3,
|
|
73361
73379
|
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord$1(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
73362
73380
|
});
|
|
73363
73381
|
}
|
|
@@ -74290,7 +74308,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
74290
74308
|
minifiedFileCache.set(absolutePath, minified);
|
|
74291
74309
|
return minified;
|
|
74292
74310
|
};
|
|
74293
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
74311
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => isMappableOxlintDiagnostic(diagnostic) && isLintableSourceFile(diagnostic.filename) && !(TYPESCRIPT_DECLARATION_FILE_PATTERN.test(diagnostic.filename) && OXLINT_IGNORED_DECLARATION_DIAGNOSTIC_CODES.has(diagnostic.code)) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
74294
74312
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
74295
74313
|
const primaryLabel = diagnostic.labels[0];
|
|
74296
74314
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
@@ -77300,6 +77318,7 @@ const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
|
|
|
77300
77318
|
const SCAN_RESULT_CACHE_FILENAME = "scan-cache.json";
|
|
77301
77319
|
const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
77302
77320
|
const GH_DEFAULT_BRANCH_PROBE_TIMEOUT_MS = 5e3;
|
|
77321
|
+
const TUI_REPORT_DETAIL_WIDTH_FRACTION = .6;
|
|
77303
77322
|
const CI_TRUST_COMPANIES = "PayPal, Rippling, and Alibaba";
|
|
77304
77323
|
const WELCOME_EXPLANATION_HOLD_MS = 1e3;
|
|
77305
77324
|
const CATEGORY_COUNTUP_SETTLE_HOLD_MS = 1e3;
|
|
@@ -77391,7 +77410,7 @@ const makeNoopConsole = () => ({
|
|
|
77391
77410
|
});
|
|
77392
77411
|
//#endregion
|
|
77393
77412
|
//#region src/cli/utils/version.ts
|
|
77394
|
-
const VERSION = "0.
|
|
77413
|
+
const VERSION = "0.9.0-dev.30369b6";
|
|
77395
77414
|
//#endregion
|
|
77396
77415
|
//#region src/cli/utils/json-mode.ts
|
|
77397
77416
|
let context = null;
|
|
@@ -77749,13 +77768,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
77749
77768
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
77750
77769
|
* standard `SENTRY_RELEASE` override.
|
|
77751
77770
|
*/
|
|
77752
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.
|
|
77771
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.9.0-dev.30369b6`;
|
|
77753
77772
|
/**
|
|
77754
77773
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
77755
77774
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
77756
77775
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
77757
77776
|
*/
|
|
77758
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.
|
|
77777
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.9.0-dev.30369b6") ? "development" : "production");
|
|
77759
77778
|
/**
|
|
77760
77779
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
77761
77780
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -89602,12 +89621,13 @@ const buildRuntimeLayers = (input) => {
|
|
|
89602
89621
|
const scoreLayer = input.shouldComputeScore ? Score.layerHttp : Score.layerOf(null);
|
|
89603
89622
|
const supplyChainLayer = input.shouldRunSupplyChain ? SupplyChain.layerNode : SupplyChain.layerOf([]);
|
|
89604
89623
|
const projectLayer = input.projectInfoOverride === void 0 ? Project.layerNode : Project.layerOf(input.projectInfoOverride);
|
|
89605
|
-
const progressLayer = input.shouldShowProgressSpinners ? Progress.layerOra(buildSpinnerProgressHandle) : Progress.layerNoop;
|
|
89624
|
+
const progressLayer = input.progressLayer ?? (input.shouldShowProgressSpinners ? Progress.layerOra(buildSpinnerProgressHandle) : Progress.layerNoop);
|
|
89625
|
+
const reporterLayer = input.reporterLayer ?? Reporter.layerNoop;
|
|
89606
89626
|
const baseLayers = mergeAll$1(projectLayer, input.hasConfigOverride ? Config.layerOf({
|
|
89607
89627
|
config: input.userConfig,
|
|
89608
89628
|
resolvedDirectory: input.directory,
|
|
89609
89629
|
configSourceDirectory: input.configSourceDirectory
|
|
89610
|
-
}) : Config.layerNode, Files.layerNode, Git.layerNode, linterLayer, LintPartialFailures.layerLive, deadCodeLayer, progressLayer,
|
|
89630
|
+
}) : Config.layerNode, Files.layerNode, Git.layerNode, linterLayer, LintPartialFailures.layerLive, deadCodeLayer, progressLayer, reporterLayer, scoreLayer, supplyChainLayer);
|
|
89611
89631
|
return input.oxlintConcurrency === void 0 ? baseLayers : mergeAll$1(baseLayers, succeed$3(OxlintConcurrency, input.oxlintConcurrency));
|
|
89612
89632
|
};
|
|
89613
89633
|
//#endregion
|
|
@@ -89977,12 +89997,12 @@ const resolveCacheFilePath = (projectDirectory) => path.join(resolveReactDoctorC
|
|
|
89977
89997
|
const readPersistedCache = (cacheFilePath) => {
|
|
89978
89998
|
try {
|
|
89979
89999
|
const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
|
|
89980
|
-
if (!isRecord(parsed) || parsed.version !==
|
|
89981
|
-
version:
|
|
90000
|
+
if (!isRecord(parsed) || parsed.version !== 6) return {
|
|
90001
|
+
version: 6,
|
|
89982
90002
|
entries: []
|
|
89983
90003
|
};
|
|
89984
90004
|
if (!Array.isArray(parsed.entries)) return {
|
|
89985
|
-
version:
|
|
90005
|
+
version: 6,
|
|
89986
90006
|
entries: []
|
|
89987
90007
|
};
|
|
89988
90008
|
const entries = [];
|
|
@@ -89992,12 +90012,12 @@ const readPersistedCache = (cacheFilePath) => {
|
|
|
89992
90012
|
entries.push(entry);
|
|
89993
90013
|
}
|
|
89994
90014
|
return {
|
|
89995
|
-
version:
|
|
90015
|
+
version: 6,
|
|
89996
90016
|
entries
|
|
89997
90017
|
};
|
|
89998
90018
|
} catch {
|
|
89999
90019
|
return {
|
|
90000
|
-
version:
|
|
90020
|
+
version: 6,
|
|
90001
90021
|
entries: []
|
|
90002
90022
|
};
|
|
90003
90023
|
}
|
|
@@ -90059,7 +90079,7 @@ const buildScanResultCacheKey = (input) => {
|
|
|
90059
90079
|
if (headSha === null) return null;
|
|
90060
90080
|
if (stringifyStableJson(input.userConfig) === null) return null;
|
|
90061
90081
|
const cacheKeyJson = stringifyStableJson({
|
|
90062
|
-
schemaVersion:
|
|
90082
|
+
schemaVersion: 6,
|
|
90063
90083
|
projectIdentity: resolveProjectIdentity(input.projectDirectory),
|
|
90064
90084
|
headSha,
|
|
90065
90085
|
worktreeFingerprint,
|
|
@@ -90102,7 +90122,7 @@ const createScanResultCache = (projectDirectory) => {
|
|
|
90102
90122
|
for (const entry of persistedCache.entries) entries.set(entry.key, entry);
|
|
90103
90123
|
const persist = () => {
|
|
90104
90124
|
writePersistedCache(cacheFilePath, {
|
|
90105
|
-
version:
|
|
90125
|
+
version: 6,
|
|
90106
90126
|
entries: [...entries.values()].sort((firstEntry, secondEntry) => secondEntry.createdAtMs - firstEntry.createdAtMs).slice(0, 20)
|
|
90107
90127
|
});
|
|
90108
90128
|
};
|
|
@@ -91442,6 +91462,9 @@ const supportsHyperlinks = (stream = process.stdout, env = process.env) => {
|
|
|
91442
91462
|
* would choke on the escape sequences).
|
|
91443
91463
|
*/
|
|
91444
91464
|
const shouldRenderHyperlinks = (stream = process.stdout) => supportsHyperlinks(stream) && !isCodingAgentEnvironment();
|
|
91465
|
+
//#endregion
|
|
91466
|
+
//#region src/cli/utils/should-show-share-link.ts
|
|
91467
|
+
const shouldShowShareLink = ({ noScore, share, isCi }) => !noScore && share && !isCi;
|
|
91445
91468
|
const FORCE_ONBOARDING_ENV_VAR = "REACT_DOCTOR_FORCE_ONBOARDING";
|
|
91446
91469
|
const FALSY_FLAG_VALUES = new Set([
|
|
91447
91470
|
"",
|
|
@@ -91660,6 +91683,13 @@ const colorizeByScore = (text, score) => {
|
|
|
91660
91683
|
return highlighter.error(text);
|
|
91661
91684
|
};
|
|
91662
91685
|
//#endregion
|
|
91686
|
+
//#region src/cli/utils/doctor-face.ts
|
|
91687
|
+
const doctorFace = (score) => {
|
|
91688
|
+
if (score >= 75) return ["◠ ◠", " ▽ "];
|
|
91689
|
+
if (score >= 50) return ["• •", " ─ "];
|
|
91690
|
+
return ["x x", " ▽ "];
|
|
91691
|
+
};
|
|
91692
|
+
//#endregion
|
|
91663
91693
|
//#region src/cli/utils/ease-out-cubic.ts
|
|
91664
91694
|
const easeOutCubic = (progress) => 1 - (1 - progress) ** 3;
|
|
91665
91695
|
//#endregion
|
|
@@ -91725,15 +91755,10 @@ const buildProjectedScoreBar = (currentScore, potentialScore) => {
|
|
|
91725
91755
|
const emptyCount = Math.max(0, barWidth - currentFill - gainCount);
|
|
91726
91756
|
return colorizeByScore("█".repeat(currentFill), currentScore) + highlighter.dim(colorizeByScore("▓".repeat(gainCount), currentScore)) + highlighter.dim("░".repeat(emptyCount));
|
|
91727
91757
|
};
|
|
91728
|
-
const getDoctorFace = (score) => {
|
|
91729
|
-
if (score >= 75) return ["◠ ◠", " ▽ "];
|
|
91730
|
-
if (score >= 50) return ["• •", " ─ "];
|
|
91731
|
-
return ["x x", " ▽ "];
|
|
91732
|
-
};
|
|
91733
91758
|
const BRANDING_LINE = `React Doctor ${highlighter.dim("(https://react.doctor)")}`;
|
|
91734
91759
|
const RAW_BRANDING_LINE = "React Doctor (https://react.doctor)";
|
|
91735
91760
|
const buildRawFaceLines = (score) => {
|
|
91736
|
-
const [eyes, mouth] =
|
|
91761
|
+
const [eyes, mouth] = doctorFace(score);
|
|
91737
91762
|
return [
|
|
91738
91763
|
FACE_BOX_TOP_BORDER,
|
|
91739
91764
|
`│ ${eyes} │`,
|
|
@@ -92067,7 +92092,8 @@ const mergeInspectOptions = (inputOptions, userConfig) => {
|
|
|
92067
92092
|
includeTagDefaults: inputOptions.includeTagDefaults ?? false,
|
|
92068
92093
|
scoreDisabledMessage: inputOptions.scoreDisabledMessage,
|
|
92069
92094
|
outputSurface: inputOptions.outputSurface ?? "cli",
|
|
92070
|
-
suppressRendering: inputOptions.suppressRendering ?? false,
|
|
92095
|
+
suppressRendering: (inputOptions.suppressRendering ?? false) || inputOptions.uiLayers != null,
|
|
92096
|
+
uiLayers: inputOptions.uiLayers ?? null,
|
|
92071
92097
|
concurrentScan: inputOptions.concurrentScan ?? false,
|
|
92072
92098
|
concurrency: inputOptions.concurrency,
|
|
92073
92099
|
maxDurationMs: inputOptions.maxDurationMs ?? null,
|
|
@@ -92291,7 +92317,9 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
92291
92317
|
shouldRunSupplyChain: options.supplyChain,
|
|
92292
92318
|
shouldComputeScore: !options.noScore,
|
|
92293
92319
|
shouldShowProgressSpinners,
|
|
92294
|
-
oxlintConcurrency: options.concurrency
|
|
92320
|
+
oxlintConcurrency: options.concurrency,
|
|
92321
|
+
reporterLayer: options.uiLayers?.reporter,
|
|
92322
|
+
progressLayer: options.uiLayers?.progress
|
|
92295
92323
|
});
|
|
92296
92324
|
const program = runInspect({
|
|
92297
92325
|
directory,
|
|
@@ -92329,7 +92357,7 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
|
|
|
92329
92357
|
const output = await runPromise(restoreLegacyThrow(applyObservability(options.silent ? program.pipe(provide(layers), provideService$2(Console, silentConsole)) : program.pipe(provide(layers)), rootSentrySpan)));
|
|
92330
92358
|
const didLintFail = lintBindingMissing || output.didLintFail;
|
|
92331
92359
|
const lintFailureReason = lintBindingMissing ? `oxlint native binding not found for Node ${process.version}; expected one matching ${OXLINT_NODE_REQUIREMENT}` : output.lintFailureReason;
|
|
92332
|
-
if (!options.scoreOnly && !lintBindingMissing && output.didLintFail && lintFailureReason !== null) if (output.lintFailureReasonKind === "native-binding-missing") runConsole(log(highlighter.gray(` Upgrade to Node ${OXLINT_NODE_REQUIREMENT} or run: npx -p oxlint@latest react-doctor@latest`)));
|
|
92360
|
+
if (!options.scoreOnly && !options.uiLayers && !lintBindingMissing && output.didLintFail && lintFailureReason !== null) if (output.lintFailureReasonKind === "native-binding-missing") runConsole(log(highlighter.gray(` Upgrade to Node ${OXLINT_NODE_REQUIREMENT} or run: npx -p oxlint@latest react-doctor@latest`)));
|
|
92333
92361
|
else runConsole(error$1(highlighter.error(lintFailureReason)));
|
|
92334
92362
|
let inspectDiagnostics = output.diagnostics;
|
|
92335
92363
|
let baselineDelta;
|
|
@@ -92564,7 +92592,7 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
92564
92592
|
const scoreDiagnostics = filterDiagnosticsForSurface([...diagnostics], "score", userConfig);
|
|
92565
92593
|
const displayedScoreDiagnostics = filterDiagnosticsForSurface([...printedDiagnostics], "score", userConfig);
|
|
92566
92594
|
const potentialScore = score ? yield* promise(() => computeProjectedScore(displayedScoreDiagnostics, scoreDiagnostics, score)) : null;
|
|
92567
|
-
const
|
|
92595
|
+
const showShareLink = shouldShowShareLink(options);
|
|
92568
92596
|
yield* pause;
|
|
92569
92597
|
yield* printSummary({
|
|
92570
92598
|
diagnostics: [...printedDiagnostics],
|
|
@@ -92587,7 +92615,7 @@ const finalizeAndRender = (input) => gen(function* () {
|
|
|
92587
92615
|
diagnostics: [...printedDiagnostics],
|
|
92588
92616
|
scoreResult: score,
|
|
92589
92617
|
projectName: project.projectName,
|
|
92590
|
-
isOffline: !
|
|
92618
|
+
isOffline: !showShareLink
|
|
92591
92619
|
});
|
|
92592
92620
|
return buildResult();
|
|
92593
92621
|
});
|
|
@@ -92697,6 +92725,127 @@ const computeDefaultSelectedAgents = (detectedAgents, rememberedAgents) => {
|
|
|
92697
92725
|
return detectedAgents.length === 1 ? [...detectedAgents] : [];
|
|
92698
92726
|
};
|
|
92699
92727
|
//#endregion
|
|
92728
|
+
//#region src/cli/utils/launch-agent.ts
|
|
92729
|
+
const isWindows = process.platform === "win32";
|
|
92730
|
+
const CLI_AGENT_IDS = [
|
|
92731
|
+
"claude-code",
|
|
92732
|
+
"codex",
|
|
92733
|
+
"cursor"
|
|
92734
|
+
];
|
|
92735
|
+
const CLI_AGENT_BINARIES = {
|
|
92736
|
+
"claude-code": "claude",
|
|
92737
|
+
codex: "codex",
|
|
92738
|
+
cursor: "cursor-agent"
|
|
92739
|
+
};
|
|
92740
|
+
const CLI_AGENT_AUTO_FLAGS = {
|
|
92741
|
+
"claude-code": ["--dangerously-skip-permissions"],
|
|
92742
|
+
codex: ["--yolo"],
|
|
92743
|
+
cursor: ["--force"]
|
|
92744
|
+
};
|
|
92745
|
+
const resolveCursorBundledNode = () => {
|
|
92746
|
+
if (!isWindows) return null;
|
|
92747
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
92748
|
+
if (!localAppData) return null;
|
|
92749
|
+
const cursorAgentRoot = Path.join(localAppData, "cursor-agent", "versions");
|
|
92750
|
+
try {
|
|
92751
|
+
const versions = NFS.readdirSync(cursorAgentRoot);
|
|
92752
|
+
if (versions.length === 0) return null;
|
|
92753
|
+
const sortedVersions = versions.sort((a, b) => b.localeCompare(a, void 0, { numeric: true }));
|
|
92754
|
+
for (const version of sortedVersions) try {
|
|
92755
|
+
const bundledNodePath = Path.join(cursorAgentRoot, version, "node.exe");
|
|
92756
|
+
const entryScriptPath = Path.join(cursorAgentRoot, version, "index.js");
|
|
92757
|
+
if (NFS.statSync(bundledNodePath).isFile() && NFS.statSync(entryScriptPath).isFile()) return {
|
|
92758
|
+
command: bundledNodePath,
|
|
92759
|
+
args: [entryScriptPath]
|
|
92760
|
+
};
|
|
92761
|
+
} catch {}
|
|
92762
|
+
} catch {}
|
|
92763
|
+
return null;
|
|
92764
|
+
};
|
|
92765
|
+
const resolveWindowsCmdEntryScript = (command) => {
|
|
92766
|
+
if (!isWindows) return null;
|
|
92767
|
+
const pathDirectories = (process.env.PATH ?? "").split(Path.delimiter).filter(Boolean);
|
|
92768
|
+
for (const directory of pathDirectories) {
|
|
92769
|
+
const cmdFilePath = Path.join(directory, `${command}.cmd`);
|
|
92770
|
+
try {
|
|
92771
|
+
if (!NFS.statSync(cmdFilePath).isFile()) continue;
|
|
92772
|
+
} catch {
|
|
92773
|
+
continue;
|
|
92774
|
+
}
|
|
92775
|
+
try {
|
|
92776
|
+
const entryScriptMatch = NFS.readFileSync(cmdFilePath, "utf8").match(/"%(?:~dp0|dp0%)\\([^"]+\.(?:m?js|cjs))"/);
|
|
92777
|
+
if (!entryScriptMatch) continue;
|
|
92778
|
+
const resolvedScriptPath = Path.resolve(directory, entryScriptMatch[1]);
|
|
92779
|
+
if (NFS.statSync(resolvedScriptPath).isFile()) return resolvedScriptPath;
|
|
92780
|
+
} catch {}
|
|
92781
|
+
}
|
|
92782
|
+
return null;
|
|
92783
|
+
};
|
|
92784
|
+
const spawnAgent = (command, args, cwd) => new Promise((resolve, reject) => {
|
|
92785
|
+
const child = spawn(command, [...args], {
|
|
92786
|
+
cwd,
|
|
92787
|
+
stdio: "inherit"
|
|
92788
|
+
});
|
|
92789
|
+
child.on("error", reject);
|
|
92790
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
92791
|
+
});
|
|
92792
|
+
const launchCliAgent = async (agentId, prompt, cwd) => {
|
|
92793
|
+
const binary = CLI_AGENT_BINARIES[agentId];
|
|
92794
|
+
const agentArgs = [...CLI_AGENT_AUTO_FLAGS[agentId], prompt];
|
|
92795
|
+
if (isWindows) {
|
|
92796
|
+
if (agentId === "cursor") {
|
|
92797
|
+
const cursorResolution = resolveCursorBundledNode();
|
|
92798
|
+
if (cursorResolution) return spawnAgent(cursorResolution.command, [...cursorResolution.args, ...agentArgs], cwd);
|
|
92799
|
+
}
|
|
92800
|
+
const entryScript = resolveWindowsCmdEntryScript(binary);
|
|
92801
|
+
if (entryScript) return spawnAgent(process.execPath, [entryScript, ...agentArgs], cwd);
|
|
92802
|
+
}
|
|
92803
|
+
try {
|
|
92804
|
+
return await spawnAgent(binary, agentArgs, cwd);
|
|
92805
|
+
} catch {
|
|
92806
|
+
throw new Error(`Failed to launch ${binary}`);
|
|
92807
|
+
}
|
|
92808
|
+
};
|
|
92809
|
+
const CLIPBOARD_COMMANDS = [
|
|
92810
|
+
{
|
|
92811
|
+
binary: "pbcopy",
|
|
92812
|
+
args: []
|
|
92813
|
+
},
|
|
92814
|
+
{
|
|
92815
|
+
binary: "wl-copy",
|
|
92816
|
+
args: []
|
|
92817
|
+
},
|
|
92818
|
+
{
|
|
92819
|
+
binary: "xclip",
|
|
92820
|
+
args: ["-selection", "clipboard"]
|
|
92821
|
+
},
|
|
92822
|
+
{
|
|
92823
|
+
binary: "xsel",
|
|
92824
|
+
args: ["--clipboard", "--input"]
|
|
92825
|
+
},
|
|
92826
|
+
{
|
|
92827
|
+
binary: "clip",
|
|
92828
|
+
args: []
|
|
92829
|
+
}
|
|
92830
|
+
];
|
|
92831
|
+
const copyToClipboard = (text) => {
|
|
92832
|
+
const command = CLIPBOARD_COMMANDS.find((candidate) => isCommandAvailable(candidate.binary));
|
|
92833
|
+
if (!command) return Promise.resolve(false);
|
|
92834
|
+
return new Promise((resolve) => {
|
|
92835
|
+
const child = spawn(command.binary, command.args);
|
|
92836
|
+
child.on("error", () => resolve(false));
|
|
92837
|
+
child.on("close", (code) => resolve(code === 0));
|
|
92838
|
+
child.stdin.on("error", () => resolve(false));
|
|
92839
|
+
child.stdin.end(text);
|
|
92840
|
+
});
|
|
92841
|
+
};
|
|
92842
|
+
//#endregion
|
|
92843
|
+
//#region src/cli/utils/detect-launchable-agents.ts
|
|
92844
|
+
const detectLaunchableAgents = async () => {
|
|
92845
|
+
const detected = new Set(await detectAvailableAgents());
|
|
92846
|
+
return CLI_AGENT_IDS.filter((agentId) => detected.has(agentId) && isCommandAvailable(CLI_AGENT_BINARIES[agentId]));
|
|
92847
|
+
};
|
|
92848
|
+
//#endregion
|
|
92700
92849
|
//#region src/cli/utils/action-upgrade-prompt.ts
|
|
92701
92850
|
const ACTION_UPGRADE_GATE = {
|
|
92702
92851
|
id: ACTION_UPGRADE_EVENT,
|
|
@@ -93939,116 +94088,6 @@ const installReactDoctorSkillForAgent = async (agent, projectRoot) => {
|
|
|
93939
94088
|
return result.skills.length > 0 && result.failed.length === 0;
|
|
93940
94089
|
};
|
|
93941
94090
|
//#endregion
|
|
93942
|
-
//#region src/cli/utils/launch-agent.ts
|
|
93943
|
-
const isWindows = process.platform === "win32";
|
|
93944
|
-
const CLI_AGENT_BINARIES = {
|
|
93945
|
-
"claude-code": "claude",
|
|
93946
|
-
codex: "codex",
|
|
93947
|
-
cursor: "cursor-agent"
|
|
93948
|
-
};
|
|
93949
|
-
const CLI_AGENT_AUTO_FLAGS = {
|
|
93950
|
-
"claude-code": ["--dangerously-skip-permissions"],
|
|
93951
|
-
codex: ["--yolo"],
|
|
93952
|
-
cursor: ["--force"]
|
|
93953
|
-
};
|
|
93954
|
-
const resolveCursorBundledNode = () => {
|
|
93955
|
-
if (!isWindows) return null;
|
|
93956
|
-
const localAppData = process.env.LOCALAPPDATA;
|
|
93957
|
-
if (!localAppData) return null;
|
|
93958
|
-
const cursorAgentRoot = Path.join(localAppData, "cursor-agent", "versions");
|
|
93959
|
-
try {
|
|
93960
|
-
const versions = NFS.readdirSync(cursorAgentRoot);
|
|
93961
|
-
if (versions.length === 0) return null;
|
|
93962
|
-
const sortedVersions = versions.sort((a, b) => b.localeCompare(a, void 0, { numeric: true }));
|
|
93963
|
-
for (const version of sortedVersions) try {
|
|
93964
|
-
const bundledNodePath = Path.join(cursorAgentRoot, version, "node.exe");
|
|
93965
|
-
const entryScriptPath = Path.join(cursorAgentRoot, version, "index.js");
|
|
93966
|
-
if (NFS.statSync(bundledNodePath).isFile() && NFS.statSync(entryScriptPath).isFile()) return {
|
|
93967
|
-
command: bundledNodePath,
|
|
93968
|
-
args: [entryScriptPath]
|
|
93969
|
-
};
|
|
93970
|
-
} catch {}
|
|
93971
|
-
} catch {}
|
|
93972
|
-
return null;
|
|
93973
|
-
};
|
|
93974
|
-
const resolveWindowsCmdEntryScript = (command) => {
|
|
93975
|
-
if (!isWindows) return null;
|
|
93976
|
-
const pathDirectories = (process.env.PATH ?? "").split(Path.delimiter).filter(Boolean);
|
|
93977
|
-
for (const directory of pathDirectories) {
|
|
93978
|
-
const cmdFilePath = Path.join(directory, `${command}.cmd`);
|
|
93979
|
-
try {
|
|
93980
|
-
if (!NFS.statSync(cmdFilePath).isFile()) continue;
|
|
93981
|
-
} catch {
|
|
93982
|
-
continue;
|
|
93983
|
-
}
|
|
93984
|
-
try {
|
|
93985
|
-
const entryScriptMatch = NFS.readFileSync(cmdFilePath, "utf8").match(/"%(?:~dp0|dp0%)\\([^"]+\.(?:m?js|cjs))"/);
|
|
93986
|
-
if (!entryScriptMatch) continue;
|
|
93987
|
-
const resolvedScriptPath = Path.resolve(directory, entryScriptMatch[1]);
|
|
93988
|
-
if (NFS.statSync(resolvedScriptPath).isFile()) return resolvedScriptPath;
|
|
93989
|
-
} catch {}
|
|
93990
|
-
}
|
|
93991
|
-
return null;
|
|
93992
|
-
};
|
|
93993
|
-
const spawnAgent = (command, args, cwd) => new Promise((resolve, reject) => {
|
|
93994
|
-
const child = spawn(command, [...args], {
|
|
93995
|
-
cwd,
|
|
93996
|
-
stdio: "inherit"
|
|
93997
|
-
});
|
|
93998
|
-
child.on("error", reject);
|
|
93999
|
-
child.on("close", (code) => resolve(code ?? 0));
|
|
94000
|
-
});
|
|
94001
|
-
const launchCliAgent = async (agentId, prompt, cwd) => {
|
|
94002
|
-
const binary = CLI_AGENT_BINARIES[agentId];
|
|
94003
|
-
const agentArgs = [...CLI_AGENT_AUTO_FLAGS[agentId], prompt];
|
|
94004
|
-
if (isWindows) {
|
|
94005
|
-
if (agentId === "cursor") {
|
|
94006
|
-
const cursorResolution = resolveCursorBundledNode();
|
|
94007
|
-
if (cursorResolution) return spawnAgent(cursorResolution.command, [...cursorResolution.args, ...agentArgs], cwd);
|
|
94008
|
-
}
|
|
94009
|
-
const entryScript = resolveWindowsCmdEntryScript(binary);
|
|
94010
|
-
if (entryScript) return spawnAgent(process.execPath, [entryScript, ...agentArgs], cwd);
|
|
94011
|
-
}
|
|
94012
|
-
try {
|
|
94013
|
-
return await spawnAgent(binary, agentArgs, cwd);
|
|
94014
|
-
} catch {
|
|
94015
|
-
throw new Error(`Failed to launch ${binary}`);
|
|
94016
|
-
}
|
|
94017
|
-
};
|
|
94018
|
-
const CLIPBOARD_COMMANDS = [
|
|
94019
|
-
{
|
|
94020
|
-
binary: "pbcopy",
|
|
94021
|
-
args: []
|
|
94022
|
-
},
|
|
94023
|
-
{
|
|
94024
|
-
binary: "wl-copy",
|
|
94025
|
-
args: []
|
|
94026
|
-
},
|
|
94027
|
-
{
|
|
94028
|
-
binary: "xclip",
|
|
94029
|
-
args: ["-selection", "clipboard"]
|
|
94030
|
-
},
|
|
94031
|
-
{
|
|
94032
|
-
binary: "xsel",
|
|
94033
|
-
args: ["--clipboard", "--input"]
|
|
94034
|
-
},
|
|
94035
|
-
{
|
|
94036
|
-
binary: "clip",
|
|
94037
|
-
args: []
|
|
94038
|
-
}
|
|
94039
|
-
];
|
|
94040
|
-
const copyToClipboard = (text) => {
|
|
94041
|
-
const command = CLIPBOARD_COMMANDS.find((candidate) => isCommandAvailable(candidate.binary));
|
|
94042
|
-
if (!command) return Promise.resolve(false);
|
|
94043
|
-
return new Promise((resolve) => {
|
|
94044
|
-
const child = spawn(command.binary, command.args);
|
|
94045
|
-
child.on("error", () => resolve(false));
|
|
94046
|
-
child.on("close", (code) => resolve(code === 0));
|
|
94047
|
-
child.stdin.on("error", () => resolve(false));
|
|
94048
|
-
child.stdin.end(text);
|
|
94049
|
-
});
|
|
94050
|
-
};
|
|
94051
|
-
//#endregion
|
|
94052
94091
|
//#region src/cli/utils/handoff-to-agent.ts
|
|
94053
94092
|
const CLIPBOARD_CHOICE = "clipboard";
|
|
94054
94093
|
const SKIP_CHOICE = "skip";
|
|
@@ -94112,10 +94151,6 @@ const maybeOfferActionUpgrade = async (projectRoot) => {
|
|
|
94112
94151
|
}
|
|
94113
94152
|
if (await upgradeGitHubActionsWorkflow(workflow)) recordActionUpgradeDecision(projectRoot, "accepted");
|
|
94114
94153
|
};
|
|
94115
|
-
const detectLaunchableAgents = async () => {
|
|
94116
|
-
const detected = new Set(await detectAvailableAgents());
|
|
94117
|
-
return Object.keys(CLI_AGENT_BINARIES).filter((agentId) => detected.has(agentId) && isCommandAvailable(CLI_AGENT_BINARIES[agentId]));
|
|
94118
|
-
};
|
|
94119
94154
|
const handoffToAgent = async (input) => {
|
|
94120
94155
|
if (!input.interactive || input.diagnostics.length === 0) return;
|
|
94121
94156
|
cliLogger.break();
|
|
@@ -94430,15 +94465,29 @@ const readChangedFilesFrom = (filePath) => {
|
|
|
94430
94465
|
return [...uniqueFiles];
|
|
94431
94466
|
};
|
|
94432
94467
|
//#endregion
|
|
94433
|
-
//#region src/cli/utils/
|
|
94434
|
-
const
|
|
94468
|
+
//#region src/cli/utils/count-unique-scanned-files.ts
|
|
94469
|
+
const countUniqueScannedFiles = (results) => {
|
|
94470
|
+
const uniqueScannedFilePaths = /* @__PURE__ */ new Set();
|
|
94471
|
+
let fileCountFromScansWithoutPaths = 0;
|
|
94472
|
+
for (const result of results) {
|
|
94473
|
+
const scannedFilePaths = result.scannedFilePaths;
|
|
94474
|
+
if (scannedFilePaths && scannedFilePaths.length > 0) for (const filePath of scannedFilePaths) uniqueScannedFilePaths.add(filePath);
|
|
94475
|
+
else fileCountFromScansWithoutPaths += result.scannedFileCount ?? result.project.sourceFileCount;
|
|
94476
|
+
}
|
|
94477
|
+
return uniqueScannedFilePaths.size + fileCountFromScansWithoutPaths;
|
|
94478
|
+
};
|
|
94435
94479
|
//#endregion
|
|
94436
|
-
//#region src/cli/utils/
|
|
94437
|
-
const
|
|
94480
|
+
//#region src/cli/utils/score-band-label.ts
|
|
94481
|
+
const scoreBandLabel = (score) => {
|
|
94438
94482
|
if (score >= 75) return "Great";
|
|
94439
94483
|
if (score >= 50) return "OK";
|
|
94440
94484
|
return "Needs work";
|
|
94441
94485
|
};
|
|
94486
|
+
//#endregion
|
|
94487
|
+
//#region src/cli/utils/filter-scans-for-surface.ts
|
|
94488
|
+
const filterScansForSurface = (completedScans, surface) => completedScans.flatMap((scan) => filterDiagnosticsForSurface([...scan.result.diagnostics], surface, scan.config));
|
|
94489
|
+
//#endregion
|
|
94490
|
+
//#region src/cli/utils/render-multi-project-summary.ts
|
|
94442
94491
|
const buildSummaryLine = (entry, longestProjectNameLength) => {
|
|
94443
94492
|
const paddedName = entry.projectName.padEnd(longestProjectNameLength);
|
|
94444
94493
|
const nameRendering = entry.score !== null ? colorizeByScore(paddedName, entry.score) : highlighter.dim(paddedName);
|
|
@@ -94447,7 +94496,7 @@ const buildSummaryLine = (entry, longestProjectNameLength) => {
|
|
|
94447
94496
|
return ` ${nameRendering} ${highlighter.dim("no score")} ${highlighter.dim(issueLabel)}`;
|
|
94448
94497
|
}
|
|
94449
94498
|
const scoreRendering = colorizeByScore(String(entry.score).padStart(3), entry.score);
|
|
94450
|
-
const label = colorizeByScore(
|
|
94499
|
+
const label = colorizeByScore(scoreBandLabel(entry.score), entry.score);
|
|
94451
94500
|
const issuesParts = [];
|
|
94452
94501
|
if (entry.errorCount > 0) issuesParts.push(highlighter.error(`${entry.errorCount} ${entry.errorCount === 1 ? "error" : "errors"}`));
|
|
94453
94502
|
const warningCount = entry.issueCount - entry.errorCount;
|
|
@@ -94469,14 +94518,7 @@ const printMultiProjectSummary = (input) => gen(function* () {
|
|
|
94469
94518
|
const projectRootByDiagnostic = /* @__PURE__ */ new WeakMap();
|
|
94470
94519
|
for (const scan of completedScans) for (const diagnostic of scan.result.diagnostics) projectRootByDiagnostic.set(diagnostic, scan.result.project.rootDirectory);
|
|
94471
94520
|
const resolveDiagnosticSourceRoot = (diagnostic) => projectRootByDiagnostic.get(diagnostic) ?? "";
|
|
94472
|
-
const
|
|
94473
|
-
let fileCountFromScansWithoutPaths = 0;
|
|
94474
|
-
for (const scan of completedScans) {
|
|
94475
|
-
const scannedFilePaths = scan.result.scannedFilePaths;
|
|
94476
|
-
if (scannedFilePaths && scannedFilePaths.length > 0) for (const filePath of scannedFilePaths) uniqueScannedFilePaths.add(filePath);
|
|
94477
|
-
else fileCountFromScansWithoutPaths += scan.result.scannedFileCount ?? scan.result.project.sourceFileCount;
|
|
94478
|
-
}
|
|
94479
|
-
const totalScannedFileCount = uniqueScannedFilePaths.size + fileCountFromScansWithoutPaths;
|
|
94521
|
+
const totalScannedFileCount = countUniqueScannedFiles(completedScans.map((scan) => scan.result));
|
|
94480
94522
|
yield* log(`${highlighter.success("✔")} Scanned ${totalScannedFileCount} ${totalScannedFileCount === 1 ? "file" : "files"} in ${formatElapsedTime(totalElapsedMilliseconds)}`);
|
|
94481
94523
|
if (displayDiagnostics.length > 0) {
|
|
94482
94524
|
yield* log("");
|
|
@@ -94748,10 +94790,14 @@ const parseFileLineArgument = (rawArgument) => {
|
|
|
94748
94790
|
};
|
|
94749
94791
|
//#endregion
|
|
94750
94792
|
//#region src/cli/utils/select-projects.ts
|
|
94751
|
-
const
|
|
94793
|
+
const discoverWorkspacePackages = (rootDirectory) => {
|
|
94752
94794
|
const hasRootPackageJson = isFile(Path.join(rootDirectory, "package.json"));
|
|
94753
|
-
|
|
94754
|
-
if (packages.length === 0 && (!hasRootPackageJson || isMonorepoRoot(rootDirectory)))
|
|
94795
|
+
const packages = listWorkspacePackages(rootDirectory);
|
|
94796
|
+
if (packages.length === 0 && (!hasRootPackageJson || isMonorepoRoot(rootDirectory))) return discoverReactSubprojects(rootDirectory);
|
|
94797
|
+
return packages;
|
|
94798
|
+
};
|
|
94799
|
+
const selectProjects = async (rootDirectory, projectFlag, skipPrompts, configProjects) => {
|
|
94800
|
+
const packages = discoverWorkspacePackages(rootDirectory);
|
|
94755
94801
|
if (projectFlag) return resolveProjectFlag(projectFlag, packages, rootDirectory);
|
|
94756
94802
|
const configRequestedNames = (configProjects ?? []).map((requestedName) => requestedName.trim()).filter((requestedName) => requestedName.length > 0);
|
|
94757
94803
|
if (configRequestedNames.length > 0) {
|
|
@@ -94880,6 +94926,14 @@ const projectManifestChanged = (rootDirectory, projectDirectory, diffInfo) => {
|
|
|
94880
94926
|
return diffInfo.changedFiles.some((filePath) => toForwardSlashes(filePath) === manifestPath);
|
|
94881
94927
|
};
|
|
94882
94928
|
//#endregion
|
|
94929
|
+
//#region src/cli/utils/should-fail-scan-gate.ts
|
|
94930
|
+
const shouldFailScanGate = (input) => {
|
|
94931
|
+
if (input.blockingLevel === "none") return false;
|
|
94932
|
+
if (input.scans.some(({ result }) => hasLintHardFailure(result))) return true;
|
|
94933
|
+
if (input.diagnosticsAreGateExempt === true) return false;
|
|
94934
|
+
return shouldBlockCi(filterScansForSurface(input.scans, "ciFailure"), input.blockingLevel);
|
|
94935
|
+
};
|
|
94936
|
+
//#endregion
|
|
94883
94937
|
//#region src/cli/utils/warn-deprecated-fail-on.ts
|
|
94884
94938
|
const warnDeprecatedFailOn = (flags, userConfig) => {
|
|
94885
94939
|
const usedFlag = flags.failOn !== void 0;
|
|
@@ -95006,12 +95060,11 @@ const finalizeScans = (input) => {
|
|
|
95006
95060
|
}));
|
|
95007
95061
|
}
|
|
95008
95062
|
const blockingLevel = resolveBlockingLevel(input.flags, input.userConfig);
|
|
95009
|
-
if (
|
|
95010
|
-
|
|
95011
|
-
|
|
95012
|
-
|
|
95013
|
-
|
|
95014
|
-
if (shouldBlockCi(filterScansForSurface(input.completedScans, "ciFailure"), blockingLevel)) process.exitCode = 1;
|
|
95063
|
+
if (shouldFailScanGate({
|
|
95064
|
+
scans: input.completedScans,
|
|
95065
|
+
blockingLevel,
|
|
95066
|
+
diagnosticsAreGateExempt: input.isScoreOnly || baselineDegraded
|
|
95067
|
+
})) process.exitCode = 1;
|
|
95015
95068
|
};
|
|
95016
95069
|
const buildChangedFilesDiffInfo = (changedFiles) => ({
|
|
95017
95070
|
currentBranch: process.env.GITHUB_HEAD_REF?.trim() || null,
|
|
@@ -95287,13 +95340,13 @@ const inspectAction = async (directory, flags, invocationCommand = "inspect") =>
|
|
|
95287
95340
|
completedScans.push(scanOutcome);
|
|
95288
95341
|
}
|
|
95289
95342
|
if (!isQuiet && isMultiProject && completedScans.length > 0) {
|
|
95290
|
-
const
|
|
95343
|
+
const showShareLink = !isShareOptedOut(completedScans, scanOptions.noScore) && !scanOptions.isCi;
|
|
95291
95344
|
await runPromise(printMultiProjectSummary({
|
|
95292
95345
|
completedScans,
|
|
95293
95346
|
categoryFilters,
|
|
95294
95347
|
verbose: Boolean(flags.verbose),
|
|
95295
95348
|
outputDirectory: flags.outputDir,
|
|
95296
|
-
isOffline: !
|
|
95349
|
+
isOffline: !showShareLink,
|
|
95297
95350
|
projectName: Path.basename(resolvedDirectory),
|
|
95298
95351
|
totalElapsedMilliseconds: performance$1.now() - scanLoopStartTime
|
|
95299
95352
|
}));
|
|
@@ -96268,6 +96321,20 @@ const COMMAND_FLAG_SPECS = new Map([
|
|
|
96268
96321
|
longOptionsWithOptionalValues: /* @__PURE__ */ new Set(),
|
|
96269
96322
|
shortOptionsWithoutValues: new Set(["-h"]),
|
|
96270
96323
|
shortOptionsWithRequiredValues: new Set(["-c"])
|
|
96324
|
+
}],
|
|
96325
|
+
["experimental-tui", {
|
|
96326
|
+
longOptionsWithoutValues: new Set([
|
|
96327
|
+
"--color",
|
|
96328
|
+
"--help",
|
|
96329
|
+
"--no-color",
|
|
96330
|
+
"--no-dead-code",
|
|
96331
|
+
"--no-score",
|
|
96332
|
+
"--yes"
|
|
96333
|
+
]),
|
|
96334
|
+
longOptionsWithRequiredValues: new Set(["--blocking", "--project"]),
|
|
96335
|
+
longOptionsWithOptionalValues: /* @__PURE__ */ new Set(),
|
|
96336
|
+
shortOptionsWithoutValues: new Set(["-h", "-y"]),
|
|
96337
|
+
shortOptionsWithRequiredValues: new Set(["-p"])
|
|
96271
96338
|
}]
|
|
96272
96339
|
]);
|
|
96273
96340
|
const isFlagLike = (argument) => argument.startsWith("-") && argument !== "-";
|
|
@@ -96402,7 +96469,7 @@ ${formatExampleLines([
|
|
|
96402
96469
|
])}
|
|
96403
96470
|
|
|
96404
96471
|
${highlighter.dim("Scope:")}
|
|
96405
|
-
Runs
|
|
96472
|
+
Runs every rule tagged ${highlighter.info("design")}; all design rules stay opt-in during a general health scan.
|
|
96406
96473
|
Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
|
|
96407
96474
|
Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
|
|
96408
96475
|
`;
|
|
@@ -96447,6 +96514,35 @@ rules.command("category <category> <severity>").description("Set the severity fo
|
|
|
96447
96514
|
rules.command("ignore-tag <tag>").description("Skip a whole rule family by tag before linting (e.g. design)").option("-c, --cwd <cwd>", "working directory", process.cwd()).action((tag, _options, command) => rulesIgnoreTagAction(tag, command.optsWithGlobals()));
|
|
96448
96515
|
rules.command("unignore-tag <tag>").description("Stop ignoring a tag previously skipped via ignore-tag").option("-c, --cwd <cwd>", "working directory", process.cwd()).action((tag, _options, command) => rulesUnignoreTagAction(tag, command.optsWithGlobals()));
|
|
96449
96516
|
program.command("experimental-lsp", { hidden: false }).description("[experimental] run the React Doctor language server over stdio (for editors)").allowUnknownOption().action(() => {});
|
|
96517
|
+
program.command("experimental-tui [directory]", { hidden: true }).description("[experimental] interactive, scrollable scan report").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").option("--no-dead-code", "skip dead-code analysis").option("--no-score", "skip the score API, the share URL, and crash reporting").option("-p, --project <names>", "scan specific workspace projects (comma-separated, or *)").option("-y, --yes", "skip the project prompt and scan every discovered project").action(async (directory = ".", _localOptions, command) => {
|
|
96518
|
+
const options = command.optsWithGlobals();
|
|
96519
|
+
const deadCode = options.deadCode === false ? false : void 0;
|
|
96520
|
+
const noScore = options.score === false ? true : void 0;
|
|
96521
|
+
const nodeMajorVersion = Number(process.versions.node.split(".")[0]);
|
|
96522
|
+
if (process.stdout.isTTY !== true || process.stdin.isTTY !== true || isNonInteractiveEnvironment() || nodeMajorVersion < 22) {
|
|
96523
|
+
await inspectAction(directory, {
|
|
96524
|
+
deadCode,
|
|
96525
|
+
score: options.score === false ? false : void 0,
|
|
96526
|
+
project: options.project,
|
|
96527
|
+
yes: options.yes,
|
|
96528
|
+
blocking: options.blocking
|
|
96529
|
+
});
|
|
96530
|
+
return;
|
|
96531
|
+
}
|
|
96532
|
+
recordCount(METRIC.cliInvoked, 1, { command: "experimental-tui" });
|
|
96533
|
+
const { runScanApp } = await import("./run-scan-app-DZ5jGWFf.js");
|
|
96534
|
+
const { shouldFail } = await runScanApp({
|
|
96535
|
+
directory,
|
|
96536
|
+
options: {
|
|
96537
|
+
deadCode,
|
|
96538
|
+
noScore
|
|
96539
|
+
},
|
|
96540
|
+
projectFlag: options.project,
|
|
96541
|
+
skipPrompts: options.yes ?? false,
|
|
96542
|
+
blocking: options.blocking
|
|
96543
|
+
});
|
|
96544
|
+
if (shouldFail) process.exitCode = 1;
|
|
96545
|
+
});
|
|
96450
96546
|
process.stdout.on("error", (error) => {
|
|
96451
96547
|
if (error.code === "EPIPE") process.exit(0);
|
|
96452
96548
|
});
|
|
@@ -96473,7 +96569,7 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
96473
96569
|
handleError(error, { sentryEventId });
|
|
96474
96570
|
});
|
|
96475
96571
|
//#endregion
|
|
96476
|
-
export {};
|
|
96572
|
+
export { toForwardSlashes as A, highlighter as B, buildRulePriorityMap as C, resolveBlockingLevel as D, formatLearnMoreLine as E, isCiEnvironment as F, sync as G, mergeReactDoctorConfigs as H, DIAGNOSTIC_CATEGORY_BUCKETS as I, void_ as K, Progress as L, isUnicodeSupported as M, METRIC as N, isReactDoctorWorkflowInstalled as O, TUI_REPORT_DETAIL_WIDTH_FRACTION as P, Reporter as R, hasLintHardFailure as S, formatFixRecipeLine as T, resolveScanTarget as U, mapWithConcurrency as V, runPromise as W, canAnimateOnboarding as _, resolveCliInspectOptions as a, buildCodeFrame as b, detectLaunchableAgents as c, launchCliAgent as d, isShareOptedOut as f, doctorFace as g, easeOutCubic as h, selectProjects as i, findNearestPackageDirectory as j, recordCount as k, CLI_AGENT_BINARIES as l, printFooter as m, shouldFailScanGate as n, countUniqueScannedFiles as o, inspect as p, succeed$3 as q, discoverWorkspacePackages as r, setUpGitHubActions as s, exitGracefully as t, copyToClipboard as u, computeProjectedScore as v, buildSortedRuleGroups as w, buildNoScoreMessage as x, formatElapsedTime as y, getCategoryImpact as z };
|
|
96477
96573
|
|
|
96478
96574
|
//# sourceMappingURL=cli.js.map
|
|
96479
|
-
//# debugId=
|
|
96575
|
+
//# debugId=b50e5764-57f0-54b7-81f8-530e6656066f
|