react-doctor 0.8.0-dev.eb2d687 → 0.8.1-dev.0b0b5ac
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 +14 -4
- package/dist/cli.js +1018 -169
- package/dist/index.d.ts +36 -15
- package/dist/index.js +435 -59
- package/dist/lsp.js +436 -60
- package/dist/skills/react-doctor/SKILL.md +5 -0
- package/package.json +6 -6
package/dist/lsp.js
CHANGED
|
@@ -33092,7 +33092,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
33092
33092
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
33093
33093
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
33094
33094
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
33095
|
-
const CORE_PACKAGE_VERSION = "0.8.
|
|
33095
|
+
const CORE_PACKAGE_VERSION = "0.8.1";
|
|
33096
33096
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
33097
33097
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
33098
33098
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -33427,10 +33427,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
|
|
|
33427
33427
|
const FRAMEWORK_PACKAGES = {
|
|
33428
33428
|
next: "nextjs",
|
|
33429
33429
|
"@tanstack/react-start": "tanstack-start",
|
|
33430
|
-
vite: "vite",
|
|
33431
|
-
"react-scripts": "cra",
|
|
33432
33430
|
"@remix-run/react": "remix",
|
|
33433
33431
|
gatsby: "gatsby",
|
|
33432
|
+
vite: "vite",
|
|
33433
|
+
"react-scripts": "cra",
|
|
33434
33434
|
expo: "expo",
|
|
33435
33435
|
"react-native": "react-native"
|
|
33436
33436
|
};
|
|
@@ -33454,11 +33454,17 @@ const NEXT_CONFIG_FILENAMES = [
|
|
|
33454
33454
|
];
|
|
33455
33455
|
const BABEL_CONFIG_FILENAMES = [
|
|
33456
33456
|
".babelrc",
|
|
33457
|
+
".babelrc.js",
|
|
33457
33458
|
".babelrc.json",
|
|
33459
|
+
".babelrc.cjs",
|
|
33460
|
+
".babelrc.mjs",
|
|
33461
|
+
".babelrc.cts",
|
|
33458
33462
|
"babel.config.js",
|
|
33459
33463
|
"babel.config.json",
|
|
33460
33464
|
"babel.config.cjs",
|
|
33461
|
-
"babel.config.mjs"
|
|
33465
|
+
"babel.config.mjs",
|
|
33466
|
+
"babel.config.ts",
|
|
33467
|
+
"babel.config.cts"
|
|
33462
33468
|
];
|
|
33463
33469
|
const VITE_CONFIG_FILENAMES = [
|
|
33464
33470
|
"vite.config.js",
|
|
@@ -33470,12 +33476,28 @@ const VITE_CONFIG_FILENAMES = [
|
|
|
33470
33476
|
"vitest.config.ts",
|
|
33471
33477
|
"vitest.config.js"
|
|
33472
33478
|
];
|
|
33479
|
+
const RSBUILD_CONFIG_FILENAMES = [
|
|
33480
|
+
"rsbuild.config.ts",
|
|
33481
|
+
"rsbuild.config.js",
|
|
33482
|
+
"rsbuild.config.mts",
|
|
33483
|
+
"rsbuild.config.mjs",
|
|
33484
|
+
"rsbuild.config.cts",
|
|
33485
|
+
"rsbuild.config.cjs"
|
|
33486
|
+
];
|
|
33487
|
+
const RSPACK_CONFIG_FILENAMES = [
|
|
33488
|
+
"rspack.config.ts",
|
|
33489
|
+
"rspack.config.js",
|
|
33490
|
+
"rspack.config.mts",
|
|
33491
|
+
"rspack.config.mjs",
|
|
33492
|
+
"rspack.config.cts",
|
|
33493
|
+
"rspack.config.cjs"
|
|
33494
|
+
];
|
|
33473
33495
|
const EXPO_APP_CONFIG_FILENAMES = [
|
|
33474
33496
|
"app.json",
|
|
33475
33497
|
"app.config.js",
|
|
33476
33498
|
"app.config.ts"
|
|
33477
33499
|
];
|
|
33478
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33500
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
|
|
33479
33501
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33480
33502
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33481
33503
|
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
@@ -33510,6 +33532,8 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
33510
33532
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33511
33533
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33512
33534
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33535
|
+
if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
|
|
33536
|
+
if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
|
|
33513
33537
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
33514
33538
|
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33515
33539
|
};
|
|
@@ -33957,19 +33981,6 @@ const getPreactVersion = (packageJson) => {
|
|
|
33957
33981
|
...packageJson.devDependencies
|
|
33958
33982
|
}.preact ?? null;
|
|
33959
33983
|
};
|
|
33960
|
-
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33961
|
-
"@tanstack/react-query",
|
|
33962
|
-
"@tanstack/query-core",
|
|
33963
|
-
"react-query"
|
|
33964
|
-
]);
|
|
33965
|
-
const hasTanStackQuery = (packageJson) => {
|
|
33966
|
-
const allDependencies = {
|
|
33967
|
-
...packageJson.peerDependencies,
|
|
33968
|
-
...packageJson.dependencies,
|
|
33969
|
-
...packageJson.devDependencies
|
|
33970
|
-
};
|
|
33971
|
-
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33972
|
-
};
|
|
33973
33984
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33974
33985
|
if (version === null || !isCatalogReference(version)) return version;
|
|
33975
33986
|
const catalogName = extractCatalogName(version);
|
|
@@ -34172,7 +34183,60 @@ const listWorkspacePackages = (rootDirectory) => {
|
|
|
34172
34183
|
}
|
|
34173
34184
|
return packages;
|
|
34174
34185
|
};
|
|
34186
|
+
const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
|
|
34187
|
+
const allDependencies = {
|
|
34188
|
+
...packageJson.devDependencies,
|
|
34189
|
+
...packageJson.peerDependencies,
|
|
34190
|
+
...packageJson.dependencies
|
|
34191
|
+
};
|
|
34192
|
+
for (const packageName of packageNames) {
|
|
34193
|
+
const version = allDependencies[packageName];
|
|
34194
|
+
if (version !== void 0) return version;
|
|
34195
|
+
}
|
|
34196
|
+
return null;
|
|
34197
|
+
};
|
|
34198
|
+
const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
|
|
34199
|
+
const getTanStackQueryVersion = (packageJson) => {
|
|
34200
|
+
return getPreferredDependencyVersion({
|
|
34201
|
+
packageJson,
|
|
34202
|
+
packageNames: TANSTACK_REACT_QUERY_PACKAGES
|
|
34203
|
+
});
|
|
34204
|
+
};
|
|
34205
|
+
const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
|
|
34206
|
+
const getStyledComponentsVersion = (packageJson) => {
|
|
34207
|
+
return getPreferredDependencyVersion({
|
|
34208
|
+
packageJson,
|
|
34209
|
+
packageNames: STYLED_COMPONENTS_PACKAGES
|
|
34210
|
+
});
|
|
34211
|
+
};
|
|
34212
|
+
const I18N_PACKAGES = [
|
|
34213
|
+
"i18next",
|
|
34214
|
+
"react-i18next",
|
|
34215
|
+
"next-i18next",
|
|
34216
|
+
"react-intl",
|
|
34217
|
+
"next-intl",
|
|
34218
|
+
"use-intl",
|
|
34219
|
+
"@formatjs/intl",
|
|
34220
|
+
"@lingui/core",
|
|
34221
|
+
"@lingui/react",
|
|
34222
|
+
"typesafe-i18n",
|
|
34223
|
+
"@tolgee/react",
|
|
34224
|
+
"react-intl-universal"
|
|
34225
|
+
];
|
|
34226
|
+
const hasI18nDependency = (packageJson) => {
|
|
34227
|
+
const allDependencies = {
|
|
34228
|
+
...packageJson.peerDependencies,
|
|
34229
|
+
...packageJson.dependencies,
|
|
34230
|
+
...packageJson.devDependencies,
|
|
34231
|
+
...packageJson.optionalDependencies
|
|
34232
|
+
};
|
|
34233
|
+
return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
|
|
34234
|
+
};
|
|
34175
34235
|
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
34236
|
+
const MOBX_REACT_PACKAGE_NAME = "mobx-react";
|
|
34237
|
+
const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
|
|
34238
|
+
const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
|
|
34239
|
+
const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
|
|
34176
34240
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
34177
34241
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
34178
34242
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
@@ -34191,7 +34255,26 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
34191
34255
|
if (nextMajor === null) return false;
|
|
34192
34256
|
return nextMajor < currentMajor;
|
|
34193
34257
|
};
|
|
34194
|
-
const
|
|
34258
|
+
const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
|
|
34259
|
+
if (currentFact.version === null) return true;
|
|
34260
|
+
if (nextFact.version === null) return false;
|
|
34261
|
+
const currentMajor = getLowestDependencyMajor(currentFact.version);
|
|
34262
|
+
const nextMajor = getLowestDependencyMajor(nextFact.version);
|
|
34263
|
+
if (currentMajor === null) return false;
|
|
34264
|
+
if (nextMajor === null) return true;
|
|
34265
|
+
if (currentMajor > latestSupportedMajor) return false;
|
|
34266
|
+
if (nextMajor > latestSupportedMajor) return true;
|
|
34267
|
+
return nextMajor < currentMajor;
|
|
34268
|
+
};
|
|
34269
|
+
const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
|
|
34270
|
+
if (!currentVersion) return true;
|
|
34271
|
+
const currentMajor = getLowestDependencyMajor(currentVersion);
|
|
34272
|
+
const nextMajor = getLowestDependencyMajor(nextVersion);
|
|
34273
|
+
if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
|
|
34274
|
+
if (nextMajor === null) return currentMajor >= 6;
|
|
34275
|
+
return nextMajor < currentMajor;
|
|
34276
|
+
};
|
|
34277
|
+
const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
|
|
34195
34278
|
if (facts.expo.version === null) {
|
|
34196
34279
|
const spec = getDependencySpec(packageJson, "expo");
|
|
34197
34280
|
if (spec !== null) facts.expo = {
|
|
@@ -34213,13 +34296,74 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
|
34213
34296
|
sourceDirectory: directory
|
|
34214
34297
|
};
|
|
34215
34298
|
}
|
|
34299
|
+
const mobxSpec = getDependencySpec(packageJson, "mobx");
|
|
34300
|
+
if (mobxSpec !== null) {
|
|
34301
|
+
const nextMobxFact = {
|
|
34302
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34303
|
+
rootDirectory: directory,
|
|
34304
|
+
rootPackageJson: packageJson,
|
|
34305
|
+
packageName: "mobx",
|
|
34306
|
+
version: mobxSpec
|
|
34307
|
+
}),
|
|
34308
|
+
sourceDirectory: directory
|
|
34309
|
+
};
|
|
34310
|
+
if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
|
|
34311
|
+
}
|
|
34312
|
+
facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
|
|
34313
|
+
facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
|
|
34314
|
+
facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
|
|
34315
|
+
facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
|
|
34316
|
+
const zustandSpec = getDependencySpec(packageJson, "zustand");
|
|
34317
|
+
if (zustandSpec !== null) {
|
|
34318
|
+
const nextZustandFact = {
|
|
34319
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34320
|
+
rootDirectory: directory,
|
|
34321
|
+
rootPackageJson: packageJson,
|
|
34322
|
+
packageName: "zustand",
|
|
34323
|
+
version: zustandSpec
|
|
34324
|
+
}),
|
|
34325
|
+
sourceDirectory: directory
|
|
34326
|
+
};
|
|
34327
|
+
if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
|
|
34328
|
+
}
|
|
34216
34329
|
if (facts.reanimatedVersion === null) {
|
|
34217
34330
|
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
34218
34331
|
if (spec !== null) facts.reanimatedVersion = spec;
|
|
34219
34332
|
}
|
|
34333
|
+
if (facts.valtioVersion === null) {
|
|
34334
|
+
const spec = getDependencySpec(packageJson, "valtio");
|
|
34335
|
+
if (spec !== null) facts.valtioVersion = spec;
|
|
34336
|
+
}
|
|
34337
|
+
facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
|
|
34338
|
+
const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
|
|
34339
|
+
rootDirectory: directory,
|
|
34340
|
+
rootPackageJson: packageJson,
|
|
34341
|
+
packageName: "styled-components",
|
|
34342
|
+
version: getStyledComponentsVersion(packageJson)
|
|
34343
|
+
});
|
|
34344
|
+
if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
|
|
34345
|
+
facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
|
|
34220
34346
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34221
34347
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34222
34348
|
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
34349
|
+
const remotionSpec = getDependencySpec(packageJson, "remotion");
|
|
34350
|
+
if (remotionSpec !== null) {
|
|
34351
|
+
facts.hasRemotionDependency = true;
|
|
34352
|
+
const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
|
|
34353
|
+
rootDirectory,
|
|
34354
|
+
rootPackageJson,
|
|
34355
|
+
packageName: "remotion",
|
|
34356
|
+
version: remotionSpec
|
|
34357
|
+
});
|
|
34358
|
+
const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
|
|
34359
|
+
if (remotionMajorVersion === null) {
|
|
34360
|
+
facts.hasUnknownRemotionVersion = true;
|
|
34361
|
+
facts.remotionVersion = null;
|
|
34362
|
+
} else if (!facts.hasUnknownRemotionVersion) {
|
|
34363
|
+
const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
|
|
34364
|
+
if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
|
|
34365
|
+
}
|
|
34366
|
+
}
|
|
34223
34367
|
};
|
|
34224
34368
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34225
34369
|
const facts = {
|
|
@@ -34239,12 +34383,31 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34239
34383
|
version: null,
|
|
34240
34384
|
sourceDirectory: null
|
|
34241
34385
|
},
|
|
34386
|
+
valtioVersion: null,
|
|
34387
|
+
mobx: {
|
|
34388
|
+
version: null,
|
|
34389
|
+
sourceDirectory: null
|
|
34390
|
+
},
|
|
34391
|
+
hasMobxReact: false,
|
|
34392
|
+
hasMobxReactLite: false,
|
|
34393
|
+
hasMobxStateTree: false,
|
|
34394
|
+
hasMobxReactObserver: false,
|
|
34395
|
+
zustand: {
|
|
34396
|
+
version: null,
|
|
34397
|
+
sourceDirectory: null
|
|
34398
|
+
},
|
|
34399
|
+
tanstackQueryVersion: null,
|
|
34400
|
+
styledComponentsVersion: null,
|
|
34401
|
+
hasI18nLibrary: false,
|
|
34242
34402
|
hasReactNativeAwarePackage: false,
|
|
34243
34403
|
hasReanimatedAwarePackage: false,
|
|
34244
34404
|
hasSsrDependency: false,
|
|
34405
|
+
hasRemotionDependency: false,
|
|
34406
|
+
hasUnknownRemotionVersion: false,
|
|
34407
|
+
remotionVersion: null,
|
|
34245
34408
|
reanimatedVersion: null
|
|
34246
34409
|
};
|
|
34247
|
-
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
34410
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
|
|
34248
34411
|
let isReactGroupSettled = !collectReactGroup;
|
|
34249
34412
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
34250
34413
|
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
@@ -34253,7 +34416,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34253
34416
|
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
34254
34417
|
visitedDirectories.add(workspaceDirectory);
|
|
34255
34418
|
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34256
|
-
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
34419
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
|
|
34257
34420
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
34258
34421
|
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
34259
34422
|
if (isReactGroupSettled) continue;
|
|
@@ -34477,11 +34640,27 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34477
34640
|
tailwindVersion: null,
|
|
34478
34641
|
zodVersion: null,
|
|
34479
34642
|
zodMajorVersion: null,
|
|
34643
|
+
mobxVersion: null,
|
|
34644
|
+
mobxMajorVersion: null,
|
|
34645
|
+
hasMobxReact: false,
|
|
34646
|
+
hasMobxReactLite: false,
|
|
34647
|
+
hasMobxStateTree: false,
|
|
34648
|
+
hasMobxReactObserver: false,
|
|
34649
|
+
zustandVersion: null,
|
|
34650
|
+
zustandMajorVersion: null,
|
|
34480
34651
|
framework: "unknown",
|
|
34481
34652
|
hasTypeScript: hasOwnTsConfig,
|
|
34482
34653
|
hasReactCompiler: false,
|
|
34483
34654
|
hasReactCompilerLintPlugin: false,
|
|
34484
34655
|
hasTanStackQuery: false,
|
|
34656
|
+
valtioVersion: null,
|
|
34657
|
+
valtioMajorVersion: null,
|
|
34658
|
+
hasRemotion: false,
|
|
34659
|
+
remotionVersion: null,
|
|
34660
|
+
remotionMajorVersion: null,
|
|
34661
|
+
hasI18nLibrary: false,
|
|
34662
|
+
tanstackQueryVersion: null,
|
|
34663
|
+
styledComponentsVersion: null,
|
|
34485
34664
|
hasSsrDependency: false,
|
|
34486
34665
|
preactVersion: null,
|
|
34487
34666
|
preactMajorVersion: null,
|
|
@@ -34580,6 +34759,12 @@ const discoverProject = (directory) => {
|
|
|
34580
34759
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
34581
34760
|
version: workspaceFacts.shopifyFlashList.version
|
|
34582
34761
|
}) : null;
|
|
34762
|
+
const zustandVersion = resolveCatalogBackedDependencyVersion({
|
|
34763
|
+
rootDirectory: directory,
|
|
34764
|
+
rootPackageJson: packageJson,
|
|
34765
|
+
packageName: "zustand",
|
|
34766
|
+
version: workspaceFacts.zustand.version
|
|
34767
|
+
});
|
|
34583
34768
|
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
34584
34769
|
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
34585
34770
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
@@ -34588,7 +34773,21 @@ const discoverProject = (directory) => {
|
|
|
34588
34773
|
packageName: "next",
|
|
34589
34774
|
version: workspaceFacts.next.version
|
|
34590
34775
|
}) : null;
|
|
34776
|
+
const valtioVersion = resolveCatalogBackedDependencyVersion({
|
|
34777
|
+
rootDirectory: directory,
|
|
34778
|
+
rootPackageJson: packageJson,
|
|
34779
|
+
packageName: "valtio",
|
|
34780
|
+
version: workspaceFacts.valtioVersion
|
|
34781
|
+
});
|
|
34782
|
+
const mobxVersion = resolveCatalogBackedDependencyVersion({
|
|
34783
|
+
rootDirectory: directory,
|
|
34784
|
+
rootPackageJson: packageJson,
|
|
34785
|
+
packageName: "mobx",
|
|
34786
|
+
version: workspaceFacts.mobx.version
|
|
34787
|
+
});
|
|
34591
34788
|
const preactVersion = getPreactVersion(packageJson);
|
|
34789
|
+
const remotionVersion = workspaceFacts.remotionVersion;
|
|
34790
|
+
const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
|
|
34592
34791
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
34593
34792
|
const projectInfo = {
|
|
34594
34793
|
rootDirectory: directory,
|
|
@@ -34598,11 +34797,27 @@ const discoverProject = (directory) => {
|
|
|
34598
34797
|
tailwindVersion,
|
|
34599
34798
|
zodVersion,
|
|
34600
34799
|
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
34800
|
+
mobxVersion,
|
|
34801
|
+
mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
|
|
34802
|
+
hasMobxReact: workspaceFacts.hasMobxReact,
|
|
34803
|
+
hasMobxReactLite: workspaceFacts.hasMobxReactLite,
|
|
34804
|
+
hasMobxStateTree: workspaceFacts.hasMobxStateTree,
|
|
34805
|
+
hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
|
|
34806
|
+
zustandVersion,
|
|
34807
|
+
zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
|
|
34601
34808
|
framework,
|
|
34602
34809
|
hasTypeScript,
|
|
34603
34810
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34604
34811
|
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34605
|
-
hasTanStackQuery:
|
|
34812
|
+
hasTanStackQuery: tanstackQueryVersion !== null,
|
|
34813
|
+
hasI18nLibrary: workspaceFacts.hasI18nLibrary,
|
|
34814
|
+
tanstackQueryVersion,
|
|
34815
|
+
styledComponentsVersion: workspaceFacts.styledComponentsVersion,
|
|
34816
|
+
valtioVersion,
|
|
34817
|
+
valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
|
|
34818
|
+
hasRemotion: workspaceFacts.hasRemotionDependency,
|
|
34819
|
+
remotionVersion,
|
|
34820
|
+
remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
|
|
34606
34821
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34607
34822
|
preactVersion,
|
|
34608
34823
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
@@ -34836,7 +35051,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
|
34836
35051
|
"react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
|
|
34837
35052
|
"react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
|
|
34838
35053
|
"react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
|
|
34839
|
-
"react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
|
|
34840
35054
|
"react/jsx-no-undef": "react-doctor/jsx-no-undef",
|
|
34841
35055
|
"react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
|
|
34842
35056
|
"react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
|
|
@@ -37049,9 +37263,25 @@ const BABEL_CONFIG_FILE_NAMES = [
|
|
|
37049
37263
|
".babelrc.json"
|
|
37050
37264
|
];
|
|
37051
37265
|
const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
|
|
37266
|
+
const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
|
|
37267
|
+
const REACT_NATIVE_PACKAGE = "react-native";
|
|
37268
|
+
const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
|
|
37269
|
+
const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
|
|
37052
37270
|
const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
|
|
37053
37271
|
const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
|
|
37272
|
+
const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
|
|
37273
|
+
const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
|
|
37274
|
+
const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
|
|
37275
|
+
if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
|
|
37276
|
+
const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
|
|
37277
|
+
if (normalizedVersionRange === null) return false;
|
|
37278
|
+
const minimumVersion = import_semver.minVersion(normalizedVersionRange);
|
|
37279
|
+
return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
|
|
37280
|
+
};
|
|
37281
|
+
const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
|
|
37054
37282
|
const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
37283
|
+
const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
|
|
37284
|
+
const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
|
|
37055
37285
|
for (const fileName of BABEL_CONFIG_FILE_NAMES) {
|
|
37056
37286
|
const filePath = Path.join(rootDirectory, fileName);
|
|
37057
37287
|
if (!isFile(filePath)) continue;
|
|
@@ -37061,7 +37291,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
|
37061
37291
|
} catch {
|
|
37062
37292
|
continue;
|
|
37063
37293
|
}
|
|
37064
|
-
if (
|
|
37294
|
+
if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
|
|
37065
37295
|
filePath: fileName,
|
|
37066
37296
|
rule: "rn-no-metro-babel-preset",
|
|
37067
37297
|
severity: "error",
|
|
@@ -37084,12 +37314,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
|
|
|
37084
37314
|
return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
|
|
37085
37315
|
};
|
|
37086
37316
|
const RULE_KEY = "no-vulnerable-react-server-components";
|
|
37087
|
-
const DEPENDENCY_SECTIONS = [
|
|
37088
|
-
"dependencies",
|
|
37089
|
-
"devDependencies",
|
|
37090
|
-
"peerDependencies",
|
|
37091
|
-
"optionalDependencies"
|
|
37092
|
-
];
|
|
37093
37317
|
const REACT_RSC_ADVISORIES_BY_MINOR = {
|
|
37094
37318
|
"19.0": {
|
|
37095
37319
|
rceFixedVersion: "19.0.1",
|
|
@@ -37136,20 +37360,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
|
|
|
37136
37360
|
for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
|
|
37137
37361
|
return [...directories];
|
|
37138
37362
|
};
|
|
37139
|
-
const readDeclaredSpec = (packageJson, packageName) => {
|
|
37140
|
-
for (const section of DEPENDENCY_SECTIONS) {
|
|
37141
|
-
const spec = packageJson[section]?.[packageName];
|
|
37142
|
-
if (typeof spec === "string") return spec;
|
|
37143
|
-
}
|
|
37144
|
-
return null;
|
|
37145
|
-
};
|
|
37146
37363
|
const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
|
|
37147
37364
|
const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
|
|
37148
37365
|
if (isFile(manifestPath)) {
|
|
37149
37366
|
const installedVersion = import_semver.valid(readPackageJson(manifestPath).version ?? null);
|
|
37150
37367
|
if (installedVersion !== null) return installedVersion;
|
|
37151
37368
|
}
|
|
37152
|
-
const candidateSpecs = [
|
|
37369
|
+
const candidateSpecs = [getDependencySpec(readPackageJson(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
|
|
37153
37370
|
for (const spec of candidateSpecs) {
|
|
37154
37371
|
const pinnedVersion = spec === null ? null : import_semver.valid(spec);
|
|
37155
37372
|
if (pinnedVersion !== null) return pinnedVersion;
|
|
@@ -37817,21 +38034,50 @@ const buildCapabilities = (project) => {
|
|
|
37817
38034
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37818
38035
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37819
38036
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
38037
|
+
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
|
|
37820
38038
|
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
37821
38039
|
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
37822
38040
|
major: 19,
|
|
37823
38041
|
minor: 2
|
|
37824
38042
|
})) capabilities.add("react:19.2");
|
|
37825
|
-
if (project.tailwindVersion !== null)
|
|
37826
|
-
|
|
37827
|
-
|
|
37828
|
-
|
|
37829
|
-
|
|
38043
|
+
if (project.tailwindVersion !== null) {
|
|
38044
|
+
capabilities.add("tailwind");
|
|
38045
|
+
const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
|
|
38046
|
+
if (isMajorMinorAtLeast(tailwindVersion, {
|
|
38047
|
+
major: 3,
|
|
38048
|
+
minor: 4
|
|
38049
|
+
})) capabilities.add("tailwind:3.4");
|
|
38050
|
+
if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
|
|
38051
|
+
major: 4,
|
|
38052
|
+
minor: 0
|
|
38053
|
+
})) capabilities.add("tailwind:4");
|
|
38054
|
+
}
|
|
37830
38055
|
if (project.zodVersion !== null) capabilities.add("zod");
|
|
37831
38056
|
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
38057
|
+
if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
|
|
38058
|
+
if (project.hasMobxReact === true) capabilities.add("mobx-react");
|
|
38059
|
+
if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
|
|
38060
|
+
if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
|
|
38061
|
+
if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
|
|
38062
|
+
if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
|
|
38063
|
+
if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
|
|
38064
|
+
if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
|
|
38065
|
+
if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
|
|
37832
38066
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
37833
38067
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
37834
|
-
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
38068
|
+
if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
|
|
38069
|
+
if (project.styledComponentsVersion) {
|
|
38070
|
+
capabilities.add("styled-components");
|
|
38071
|
+
const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
|
|
38072
|
+
if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
|
|
38073
|
+
}
|
|
38074
|
+
if (project.hasI18nLibrary) capabilities.add("i18n");
|
|
38075
|
+
if (project.valtioVersion !== null) capabilities.add("valtio");
|
|
38076
|
+
addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
|
|
38077
|
+
if (project.hasRemotion) {
|
|
38078
|
+
capabilities.add("remotion");
|
|
38079
|
+
addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
|
|
38080
|
+
}
|
|
37835
38081
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
37836
38082
|
if (project.preactVersion !== null) capabilities.add("preact");
|
|
37837
38083
|
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
@@ -37846,7 +38092,7 @@ const getCapabilities = (project) => {
|
|
|
37846
38092
|
capabilitiesByProject.set(project, capabilities);
|
|
37847
38093
|
return capabilities;
|
|
37848
38094
|
};
|
|
37849
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
38095
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
|
|
37850
38096
|
if (requires) {
|
|
37851
38097
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
37852
38098
|
}
|
|
@@ -37857,20 +38103,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
37857
38103
|
if (tags) {
|
|
37858
38104
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
37859
38105
|
}
|
|
38106
|
+
if (includedTags && includedTags.size > 0) {
|
|
38107
|
+
if (!tags?.some((tag) => includedTags.has(tag))) return false;
|
|
38108
|
+
}
|
|
37860
38109
|
return true;
|
|
37861
38110
|
};
|
|
38111
|
+
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
37862
38112
|
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
37863
38113
|
setImmediate(resolve);
|
|
37864
38114
|
});
|
|
37865
38115
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
37866
38116
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
37867
38117
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
38118
|
+
const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
|
|
37868
38119
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
37869
38120
|
const rule = entry.rule;
|
|
37870
38121
|
const scan = rule.scan;
|
|
37871
38122
|
if (typeof scan !== "function") return [];
|
|
37872
|
-
if (
|
|
37873
|
-
|
|
38123
|
+
if (!shouldEnableRuleByDefaultStatus({
|
|
38124
|
+
defaultEnabled: rule.defaultEnabled,
|
|
38125
|
+
includeTagDefaults: options.includeTagDefaults === true,
|
|
38126
|
+
hasIncludedTags: includedTags.size > 0
|
|
38127
|
+
})) return [];
|
|
38128
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
|
|
37874
38129
|
return [{
|
|
37875
38130
|
entry,
|
|
37876
38131
|
scan,
|
|
@@ -39068,6 +39323,35 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
39068
39323
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
39069
39324
|
};
|
|
39070
39325
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
39326
|
+
const parseBaselineDiffPlan = (value) => {
|
|
39327
|
+
const entries = splitNullSeparated(value);
|
|
39328
|
+
const baseFiles = /* @__PURE__ */ new Set();
|
|
39329
|
+
const headFiles = /* @__PURE__ */ new Set();
|
|
39330
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
39331
|
+
const status = entries[entryIndex];
|
|
39332
|
+
const filePath = entries[entryIndex + 1];
|
|
39333
|
+
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
39334
|
+
if (status === "A") {
|
|
39335
|
+
headFiles.add(filePath);
|
|
39336
|
+
continue;
|
|
39337
|
+
}
|
|
39338
|
+
if (status === "D") {
|
|
39339
|
+
baseFiles.add(filePath);
|
|
39340
|
+
continue;
|
|
39341
|
+
}
|
|
39342
|
+
if (status === "M" || status === "T") {
|
|
39343
|
+
baseFiles.add(filePath);
|
|
39344
|
+
headFiles.add(filePath);
|
|
39345
|
+
continue;
|
|
39346
|
+
}
|
|
39347
|
+
return null;
|
|
39348
|
+
}
|
|
39349
|
+
return {
|
|
39350
|
+
baseFiles: [...baseFiles],
|
|
39351
|
+
headFiles: [...headFiles],
|
|
39352
|
+
untrackedFiles: []
|
|
39353
|
+
};
|
|
39354
|
+
};
|
|
39071
39355
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
39072
39356
|
/**
|
|
39073
39357
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -39270,6 +39554,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39270
39554
|
githubViewerPermission,
|
|
39271
39555
|
branchExists,
|
|
39272
39556
|
mergeBase,
|
|
39557
|
+
baselineDiffPlan: (input) => {
|
|
39558
|
+
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
39559
|
+
return gen(function* () {
|
|
39560
|
+
const unmerged = yield* runGit(input.directory, [
|
|
39561
|
+
"diff",
|
|
39562
|
+
"--no-ext-diff",
|
|
39563
|
+
"-z",
|
|
39564
|
+
"--name-only",
|
|
39565
|
+
"--diff-filter=U",
|
|
39566
|
+
"--relative"
|
|
39567
|
+
]);
|
|
39568
|
+
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
39569
|
+
const result = yield* runGit(input.directory, [
|
|
39570
|
+
"diff",
|
|
39571
|
+
"--no-ext-diff",
|
|
39572
|
+
"--no-textconv",
|
|
39573
|
+
"--no-renames",
|
|
39574
|
+
"-z",
|
|
39575
|
+
"--name-status",
|
|
39576
|
+
"--relative",
|
|
39577
|
+
input.ref
|
|
39578
|
+
]);
|
|
39579
|
+
if (result.status !== 0) return null;
|
|
39580
|
+
const plan = parseBaselineDiffPlan(result.stdout);
|
|
39581
|
+
if (plan === null) return null;
|
|
39582
|
+
const untracked = yield* runGit(input.directory, [
|
|
39583
|
+
"ls-files",
|
|
39584
|
+
"--others",
|
|
39585
|
+
"--exclude-standard",
|
|
39586
|
+
"-z"
|
|
39587
|
+
]);
|
|
39588
|
+
if (untracked.status !== 0) return null;
|
|
39589
|
+
return {
|
|
39590
|
+
baseFiles: plan.baseFiles,
|
|
39591
|
+
headFiles: plan.headFiles,
|
|
39592
|
+
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
39593
|
+
};
|
|
39594
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
39595
|
+
},
|
|
39273
39596
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
39274
39597
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
39275
39598
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -39419,6 +39742,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39419
39742
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
39420
39743
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
39421
39744
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
39745
|
+
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
39422
39746
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
39423
39747
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
39424
39748
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -39787,8 +40111,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39787
40111
|
}
|
|
39788
40112
|
return enabled;
|
|
39789
40113
|
};
|
|
39790
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
39791
|
-
const
|
|
40114
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
40115
|
+
const hasIncludedTags = includedTags.size > 0;
|
|
40116
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39792
40117
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39793
40118
|
const jsPlugins = [];
|
|
39794
40119
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -39803,9 +40128,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39803
40128
|
if (rule.scan !== void 0) continue;
|
|
39804
40129
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
39805
40130
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
39806
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
40131
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
|
|
39807
40132
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
39808
|
-
if (
|
|
40133
|
+
if (!shouldEnableRuleByDefaultStatus({
|
|
40134
|
+
defaultEnabled: rule.defaultEnabled,
|
|
40135
|
+
includeTagDefaults,
|
|
40136
|
+
hasIncludedTags,
|
|
40137
|
+
hasExplicitOverride: explicitRuleOverride !== void 0
|
|
40138
|
+
})) continue;
|
|
39809
40139
|
const severity = resolveRuleSeverityOverride({
|
|
39810
40140
|
ruleKey: registryEntry.key,
|
|
39811
40141
|
category: rule.category
|
|
@@ -39814,7 +40144,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39814
40144
|
enabledReactDoctorRules[registryEntry.key] = severity;
|
|
39815
40145
|
}
|
|
39816
40146
|
const userPluginRules = {};
|
|
39817
|
-
if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
|
|
40147
|
+
if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
|
|
39818
40148
|
Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
|
|
39819
40149
|
jsPlugins.push(userPlugin.entry);
|
|
39820
40150
|
}
|
|
@@ -40031,6 +40361,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
40031
40361
|
}
|
|
40032
40362
|
};
|
|
40033
40363
|
};
|
|
40364
|
+
const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
|
|
40365
|
+
const fingerprintFileContents = (filePath, fingerprintLength) => {
|
|
40366
|
+
const fileStats = NFS.statSync(filePath, { bigint: true });
|
|
40367
|
+
const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
|
|
40368
|
+
if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
|
|
40369
|
+
const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
|
|
40370
|
+
fingerprintCacheByFilePath.set(filePath, {
|
|
40371
|
+
fingerprint,
|
|
40372
|
+
modifiedTimeNanoseconds: fileStats.mtimeNs,
|
|
40373
|
+
sizeBytes: fileStats.size
|
|
40374
|
+
});
|
|
40375
|
+
return fingerprint;
|
|
40376
|
+
};
|
|
40034
40377
|
const bundledRequire = createRequire(import.meta.url);
|
|
40035
40378
|
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
40036
40379
|
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
@@ -40054,6 +40397,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
|
40054
40397
|
"oxlint-plugin-react-doctor/package.json",
|
|
40055
40398
|
"eslint-plugin-react-hooks/package.json"
|
|
40056
40399
|
];
|
|
40400
|
+
const resolvePluginFingerprint = () => {
|
|
40401
|
+
try {
|
|
40402
|
+
return fingerprintFileContents(bundledRequire.resolve("oxlint-plugin-react-doctor"), 16);
|
|
40403
|
+
} catch {
|
|
40404
|
+
return "unresolved";
|
|
40405
|
+
}
|
|
40406
|
+
};
|
|
40057
40407
|
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
40058
40408
|
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
40059
40409
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
@@ -40063,6 +40413,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
|
40063
40413
|
} catch {
|
|
40064
40414
|
versions.push(`${specifier}=missing`);
|
|
40065
40415
|
}
|
|
40416
|
+
versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
|
|
40066
40417
|
return versions;
|
|
40067
40418
|
};
|
|
40068
40419
|
const esmRequire = createRequire(import.meta.url);
|
|
@@ -40756,12 +41107,17 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
|
|
|
40756
41107
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40757
41108
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40758
41109
|
const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
|
|
41110
|
+
const SET_STATE_IN_EFFECT_ACTION = "Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with `// react-doctor-disable-next-line react-hooks-js/set-state-in-effect`.";
|
|
40759
41111
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
40760
41112
|
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
40761
41113
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
40762
41114
|
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
40763
41115
|
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
40764
41116
|
};
|
|
41117
|
+
const buildSetStateInEffectMessage = (reasonSummary) => {
|
|
41118
|
+
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
41119
|
+
return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
|
|
41120
|
+
};
|
|
40765
41121
|
const PLUGIN_CATEGORY_MAP = {
|
|
40766
41122
|
react: "Bugs",
|
|
40767
41123
|
"react-hooks": "Bugs",
|
|
@@ -40819,6 +41175,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40819
41175
|
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40820
41176
|
help: reasonDetail || help
|
|
40821
41177
|
};
|
|
41178
|
+
if (rule === "set-state-in-effect") return {
|
|
41179
|
+
message: buildSetStateInEffectMessage(reasonSummary.trim()),
|
|
41180
|
+
help: reasonDetail || help
|
|
41181
|
+
};
|
|
40822
41182
|
return {
|
|
40823
41183
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40824
41184
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -41529,7 +41889,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
41529
41889
|
* 6. always restore disable directives + clean up the temp dir
|
|
41530
41890
|
*/
|
|
41531
41891
|
const runOxlint = async (options) => {
|
|
41532
|
-
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
41892
|
+
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
41533
41893
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
41534
41894
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
41535
41895
|
validateRuleRegistration();
|
|
@@ -41543,13 +41903,15 @@ const runOxlint = async (options) => {
|
|
|
41543
41903
|
}
|
|
41544
41904
|
const pluginPath = resolvePluginPath();
|
|
41545
41905
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
41546
|
-
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
41906
|
+
const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
41547
41907
|
const buildConfig = (overrides) => createOxlintConfig({
|
|
41548
41908
|
pluginPath,
|
|
41549
41909
|
project,
|
|
41550
41910
|
customRulesOnly,
|
|
41551
41911
|
extendsPaths: overrides.extendsPaths,
|
|
41552
41912
|
ignoredTags,
|
|
41913
|
+
includedTags,
|
|
41914
|
+
includeTagDefaults,
|
|
41553
41915
|
serverAuthFunctionNames,
|
|
41554
41916
|
severityControls,
|
|
41555
41917
|
userPlugins,
|
|
@@ -41938,6 +42300,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
41938
42300
|
respectInlineDisables: input.respectInlineDisables,
|
|
41939
42301
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
41940
42302
|
ignoredTags: input.ignoredTags,
|
|
42303
|
+
includedTags: input.includedTags,
|
|
42304
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
41941
42305
|
userConfig: input.userConfig ?? null,
|
|
41942
42306
|
configSourceDirectory: input.configSourceDirectory,
|
|
41943
42307
|
onPartialFailure: (reason) => {
|
|
@@ -42786,7 +43150,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42786
43150
|
const securityScanFailedRef = yield* make$13(false);
|
|
42787
43151
|
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
42788
43152
|
project,
|
|
42789
|
-
ignoredTags: input.ignoredTags
|
|
43153
|
+
ignoredTags: input.ignoredTags,
|
|
43154
|
+
includedTags: input.includedTags,
|
|
43155
|
+
includeTagDefaults: input.includeTagDefaults
|
|
42790
43156
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
42791
43157
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
42792
43158
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
@@ -42877,6 +43243,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42877
43243
|
respectInlineDisables: input.respectInlineDisables,
|
|
42878
43244
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
42879
43245
|
ignoredTags: input.ignoredTags,
|
|
43246
|
+
includedTags: input.includedTags,
|
|
43247
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
42880
43248
|
userConfig: resolvedConfig.config ?? void 0,
|
|
42881
43249
|
configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
|
|
42882
43250
|
onFileProgress: (scannedFileCount, totalFileCount) => {
|
|
@@ -43144,12 +43512,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
43144
43512
|
*/
|
|
43145
43513
|
const materializeSourceTree = (input) => gen(function* () {
|
|
43146
43514
|
const materializedFiles = [];
|
|
43515
|
+
const unmaterializedFiles = [];
|
|
43147
43516
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
43148
43517
|
for (const relativePath of input.files) {
|
|
43149
43518
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
43150
|
-
if (content === null)
|
|
43519
|
+
if (content === null) {
|
|
43520
|
+
unmaterializedFiles.push(relativePath);
|
|
43521
|
+
continue;
|
|
43522
|
+
}
|
|
43151
43523
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
43152
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
43524
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
|
|
43525
|
+
unmaterializedFiles.push(relativePath);
|
|
43526
|
+
continue;
|
|
43527
|
+
}
|
|
43153
43528
|
yield* sync(() => {
|
|
43154
43529
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
43155
43530
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -43166,6 +43541,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
43166
43541
|
return {
|
|
43167
43542
|
tempDirectory: input.tempDirectory,
|
|
43168
43543
|
materializedFiles,
|
|
43544
|
+
unmaterializedFiles,
|
|
43169
43545
|
cleanup: () => {
|
|
43170
43546
|
try {
|
|
43171
43547
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -43341,7 +43717,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
|
|
|
43341
43717
|
/** Display name used in client-facing messages and progress titles. */
|
|
43342
43718
|
const SERVER_DISPLAY_NAME = "React Doctor";
|
|
43343
43719
|
/** Server version reported in `serverInfo`; injected at build, `dev` from source. */
|
|
43344
|
-
const SERVER_VERSION = "0.8.
|
|
43720
|
+
const SERVER_VERSION = "0.8.1";
|
|
43345
43721
|
/** `Diagnostic.source` shown next to every published diagnostic. */
|
|
43346
43722
|
const DIAGNOSTIC_SOURCE = "react-doctor";
|
|
43347
43723
|
/**
|
|
@@ -45371,5 +45747,5 @@ const startLanguageServer = () => {
|
|
|
45371
45747
|
};
|
|
45372
45748
|
//#endregion
|
|
45373
45749
|
export { startLanguageServer };
|
|
45374
|
-
!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]="
|
|
45375
|
-
//# debugId=
|
|
45750
|
+
!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]="6c3f6717-c00e-5081-bb66-501f2fd8a0d1")}catch(e){}}();
|
|
45751
|
+
//# debugId=6c3f6717-c00e-5081-bb66-501f2fd8a0d1
|