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/index.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]="4ef51735-a42d-5161-b990-86e4fa9e4d19")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
@@ -33040,7 +33040,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
33040
33040
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
33041
33041
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
33042
33042
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
33043
|
-
const CORE_PACKAGE_VERSION = "0.8.
|
|
33043
|
+
const CORE_PACKAGE_VERSION = "0.8.1";
|
|
33044
33044
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
33045
33045
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
33046
33046
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -33375,10 +33375,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
|
|
|
33375
33375
|
const FRAMEWORK_PACKAGES = {
|
|
33376
33376
|
next: "nextjs",
|
|
33377
33377
|
"@tanstack/react-start": "tanstack-start",
|
|
33378
|
-
vite: "vite",
|
|
33379
|
-
"react-scripts": "cra",
|
|
33380
33378
|
"@remix-run/react": "remix",
|
|
33381
33379
|
gatsby: "gatsby",
|
|
33380
|
+
vite: "vite",
|
|
33381
|
+
"react-scripts": "cra",
|
|
33382
33382
|
expo: "expo",
|
|
33383
33383
|
"react-native": "react-native"
|
|
33384
33384
|
};
|
|
@@ -33402,11 +33402,17 @@ const NEXT_CONFIG_FILENAMES = [
|
|
|
33402
33402
|
];
|
|
33403
33403
|
const BABEL_CONFIG_FILENAMES = [
|
|
33404
33404
|
".babelrc",
|
|
33405
|
+
".babelrc.js",
|
|
33405
33406
|
".babelrc.json",
|
|
33407
|
+
".babelrc.cjs",
|
|
33408
|
+
".babelrc.mjs",
|
|
33409
|
+
".babelrc.cts",
|
|
33406
33410
|
"babel.config.js",
|
|
33407
33411
|
"babel.config.json",
|
|
33408
33412
|
"babel.config.cjs",
|
|
33409
|
-
"babel.config.mjs"
|
|
33413
|
+
"babel.config.mjs",
|
|
33414
|
+
"babel.config.ts",
|
|
33415
|
+
"babel.config.cts"
|
|
33410
33416
|
];
|
|
33411
33417
|
const VITE_CONFIG_FILENAMES = [
|
|
33412
33418
|
"vite.config.js",
|
|
@@ -33418,12 +33424,28 @@ const VITE_CONFIG_FILENAMES = [
|
|
|
33418
33424
|
"vitest.config.ts",
|
|
33419
33425
|
"vitest.config.js"
|
|
33420
33426
|
];
|
|
33427
|
+
const RSBUILD_CONFIG_FILENAMES = [
|
|
33428
|
+
"rsbuild.config.ts",
|
|
33429
|
+
"rsbuild.config.js",
|
|
33430
|
+
"rsbuild.config.mts",
|
|
33431
|
+
"rsbuild.config.mjs",
|
|
33432
|
+
"rsbuild.config.cts",
|
|
33433
|
+
"rsbuild.config.cjs"
|
|
33434
|
+
];
|
|
33435
|
+
const RSPACK_CONFIG_FILENAMES = [
|
|
33436
|
+
"rspack.config.ts",
|
|
33437
|
+
"rspack.config.js",
|
|
33438
|
+
"rspack.config.mts",
|
|
33439
|
+
"rspack.config.mjs",
|
|
33440
|
+
"rspack.config.cts",
|
|
33441
|
+
"rspack.config.cjs"
|
|
33442
|
+
];
|
|
33421
33443
|
const EXPO_APP_CONFIG_FILENAMES = [
|
|
33422
33444
|
"app.json",
|
|
33423
33445
|
"app.config.js",
|
|
33424
33446
|
"app.config.ts"
|
|
33425
33447
|
];
|
|
33426
|
-
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
|
|
33448
|
+
const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
|
|
33427
33449
|
const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
|
|
33428
33450
|
const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
|
|
33429
33451
|
const hasCompilerPackage = (packageJson, compilerPackages) => {
|
|
@@ -33458,6 +33480,8 @@ const detectReactCompiler = (directory, packageJson) => {
|
|
|
33458
33480
|
if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
|
|
33459
33481
|
if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
|
|
33460
33482
|
if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
|
|
33483
|
+
if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
|
|
33484
|
+
if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
|
|
33461
33485
|
if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
|
|
33462
33486
|
return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
|
|
33463
33487
|
};
|
|
@@ -33905,19 +33929,6 @@ const getPreactVersion = (packageJson) => {
|
|
|
33905
33929
|
...packageJson.devDependencies
|
|
33906
33930
|
}.preact ?? null;
|
|
33907
33931
|
};
|
|
33908
|
-
const TANSTACK_QUERY_PACKAGES = new Set([
|
|
33909
|
-
"@tanstack/react-query",
|
|
33910
|
-
"@tanstack/query-core",
|
|
33911
|
-
"react-query"
|
|
33912
|
-
]);
|
|
33913
|
-
const hasTanStackQuery = (packageJson) => {
|
|
33914
|
-
const allDependencies = {
|
|
33915
|
-
...packageJson.peerDependencies,
|
|
33916
|
-
...packageJson.dependencies,
|
|
33917
|
-
...packageJson.devDependencies
|
|
33918
|
-
};
|
|
33919
|
-
return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
|
|
33920
|
-
};
|
|
33921
33932
|
const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
|
|
33922
33933
|
if (version === null || !isCatalogReference(version)) return version;
|
|
33923
33934
|
const catalogName = extractCatalogName(version);
|
|
@@ -34120,7 +34131,60 @@ const listWorkspacePackages = (rootDirectory) => {
|
|
|
34120
34131
|
}
|
|
34121
34132
|
return packages;
|
|
34122
34133
|
};
|
|
34134
|
+
const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
|
|
34135
|
+
const allDependencies = {
|
|
34136
|
+
...packageJson.devDependencies,
|
|
34137
|
+
...packageJson.peerDependencies,
|
|
34138
|
+
...packageJson.dependencies
|
|
34139
|
+
};
|
|
34140
|
+
for (const packageName of packageNames) {
|
|
34141
|
+
const version = allDependencies[packageName];
|
|
34142
|
+
if (version !== void 0) return version;
|
|
34143
|
+
}
|
|
34144
|
+
return null;
|
|
34145
|
+
};
|
|
34146
|
+
const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
|
|
34147
|
+
const getTanStackQueryVersion = (packageJson) => {
|
|
34148
|
+
return getPreferredDependencyVersion({
|
|
34149
|
+
packageJson,
|
|
34150
|
+
packageNames: TANSTACK_REACT_QUERY_PACKAGES
|
|
34151
|
+
});
|
|
34152
|
+
};
|
|
34153
|
+
const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
|
|
34154
|
+
const getStyledComponentsVersion = (packageJson) => {
|
|
34155
|
+
return getPreferredDependencyVersion({
|
|
34156
|
+
packageJson,
|
|
34157
|
+
packageNames: STYLED_COMPONENTS_PACKAGES
|
|
34158
|
+
});
|
|
34159
|
+
};
|
|
34160
|
+
const I18N_PACKAGES = [
|
|
34161
|
+
"i18next",
|
|
34162
|
+
"react-i18next",
|
|
34163
|
+
"next-i18next",
|
|
34164
|
+
"react-intl",
|
|
34165
|
+
"next-intl",
|
|
34166
|
+
"use-intl",
|
|
34167
|
+
"@formatjs/intl",
|
|
34168
|
+
"@lingui/core",
|
|
34169
|
+
"@lingui/react",
|
|
34170
|
+
"typesafe-i18n",
|
|
34171
|
+
"@tolgee/react",
|
|
34172
|
+
"react-intl-universal"
|
|
34173
|
+
];
|
|
34174
|
+
const hasI18nDependency = (packageJson) => {
|
|
34175
|
+
const allDependencies = {
|
|
34176
|
+
...packageJson.peerDependencies,
|
|
34177
|
+
...packageJson.dependencies,
|
|
34178
|
+
...packageJson.devDependencies,
|
|
34179
|
+
...packageJson.optionalDependencies
|
|
34180
|
+
};
|
|
34181
|
+
return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
|
|
34182
|
+
};
|
|
34123
34183
|
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
34184
|
+
const MOBX_REACT_PACKAGE_NAME = "mobx-react";
|
|
34185
|
+
const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
|
|
34186
|
+
const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
|
|
34187
|
+
const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
|
|
34124
34188
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
34125
34189
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
34126
34190
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
@@ -34139,7 +34203,26 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
34139
34203
|
if (nextMajor === null) return false;
|
|
34140
34204
|
return nextMajor < currentMajor;
|
|
34141
34205
|
};
|
|
34142
|
-
const
|
|
34206
|
+
const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
|
|
34207
|
+
if (currentFact.version === null) return true;
|
|
34208
|
+
if (nextFact.version === null) return false;
|
|
34209
|
+
const currentMajor = getLowestDependencyMajor(currentFact.version);
|
|
34210
|
+
const nextMajor = getLowestDependencyMajor(nextFact.version);
|
|
34211
|
+
if (currentMajor === null) return false;
|
|
34212
|
+
if (nextMajor === null) return true;
|
|
34213
|
+
if (currentMajor > latestSupportedMajor) return false;
|
|
34214
|
+
if (nextMajor > latestSupportedMajor) return true;
|
|
34215
|
+
return nextMajor < currentMajor;
|
|
34216
|
+
};
|
|
34217
|
+
const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
|
|
34218
|
+
if (!currentVersion) return true;
|
|
34219
|
+
const currentMajor = getLowestDependencyMajor(currentVersion);
|
|
34220
|
+
const nextMajor = getLowestDependencyMajor(nextVersion);
|
|
34221
|
+
if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
|
|
34222
|
+
if (nextMajor === null) return currentMajor >= 6;
|
|
34223
|
+
return nextMajor < currentMajor;
|
|
34224
|
+
};
|
|
34225
|
+
const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
|
|
34143
34226
|
if (facts.expo.version === null) {
|
|
34144
34227
|
const spec = getDependencySpec(packageJson, "expo");
|
|
34145
34228
|
if (spec !== null) facts.expo = {
|
|
@@ -34161,13 +34244,74 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
|
34161
34244
|
sourceDirectory: directory
|
|
34162
34245
|
};
|
|
34163
34246
|
}
|
|
34247
|
+
const mobxSpec = getDependencySpec(packageJson, "mobx");
|
|
34248
|
+
if (mobxSpec !== null) {
|
|
34249
|
+
const nextMobxFact = {
|
|
34250
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34251
|
+
rootDirectory: directory,
|
|
34252
|
+
rootPackageJson: packageJson,
|
|
34253
|
+
packageName: "mobx",
|
|
34254
|
+
version: mobxSpec
|
|
34255
|
+
}),
|
|
34256
|
+
sourceDirectory: directory
|
|
34257
|
+
};
|
|
34258
|
+
if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
|
|
34259
|
+
}
|
|
34260
|
+
facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
|
|
34261
|
+
facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
|
|
34262
|
+
facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
|
|
34263
|
+
facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
|
|
34264
|
+
const zustandSpec = getDependencySpec(packageJson, "zustand");
|
|
34265
|
+
if (zustandSpec !== null) {
|
|
34266
|
+
const nextZustandFact = {
|
|
34267
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34268
|
+
rootDirectory: directory,
|
|
34269
|
+
rootPackageJson: packageJson,
|
|
34270
|
+
packageName: "zustand",
|
|
34271
|
+
version: zustandSpec
|
|
34272
|
+
}),
|
|
34273
|
+
sourceDirectory: directory
|
|
34274
|
+
};
|
|
34275
|
+
if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
|
|
34276
|
+
}
|
|
34164
34277
|
if (facts.reanimatedVersion === null) {
|
|
34165
34278
|
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
34166
34279
|
if (spec !== null) facts.reanimatedVersion = spec;
|
|
34167
34280
|
}
|
|
34281
|
+
if (facts.valtioVersion === null) {
|
|
34282
|
+
const spec = getDependencySpec(packageJson, "valtio");
|
|
34283
|
+
if (spec !== null) facts.valtioVersion = spec;
|
|
34284
|
+
}
|
|
34285
|
+
facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
|
|
34286
|
+
const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
|
|
34287
|
+
rootDirectory: directory,
|
|
34288
|
+
rootPackageJson: packageJson,
|
|
34289
|
+
packageName: "styled-components",
|
|
34290
|
+
version: getStyledComponentsVersion(packageJson)
|
|
34291
|
+
});
|
|
34292
|
+
if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
|
|
34293
|
+
facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
|
|
34168
34294
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34169
34295
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34170
34296
|
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
34297
|
+
const remotionSpec = getDependencySpec(packageJson, "remotion");
|
|
34298
|
+
if (remotionSpec !== null) {
|
|
34299
|
+
facts.hasRemotionDependency = true;
|
|
34300
|
+
const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
|
|
34301
|
+
rootDirectory,
|
|
34302
|
+
rootPackageJson,
|
|
34303
|
+
packageName: "remotion",
|
|
34304
|
+
version: remotionSpec
|
|
34305
|
+
});
|
|
34306
|
+
const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
|
|
34307
|
+
if (remotionMajorVersion === null) {
|
|
34308
|
+
facts.hasUnknownRemotionVersion = true;
|
|
34309
|
+
facts.remotionVersion = null;
|
|
34310
|
+
} else if (!facts.hasUnknownRemotionVersion) {
|
|
34311
|
+
const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
|
|
34312
|
+
if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
|
|
34313
|
+
}
|
|
34314
|
+
}
|
|
34171
34315
|
};
|
|
34172
34316
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34173
34317
|
const facts = {
|
|
@@ -34187,12 +34331,31 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34187
34331
|
version: null,
|
|
34188
34332
|
sourceDirectory: null
|
|
34189
34333
|
},
|
|
34334
|
+
valtioVersion: null,
|
|
34335
|
+
mobx: {
|
|
34336
|
+
version: null,
|
|
34337
|
+
sourceDirectory: null
|
|
34338
|
+
},
|
|
34339
|
+
hasMobxReact: false,
|
|
34340
|
+
hasMobxReactLite: false,
|
|
34341
|
+
hasMobxStateTree: false,
|
|
34342
|
+
hasMobxReactObserver: false,
|
|
34343
|
+
zustand: {
|
|
34344
|
+
version: null,
|
|
34345
|
+
sourceDirectory: null
|
|
34346
|
+
},
|
|
34347
|
+
tanstackQueryVersion: null,
|
|
34348
|
+
styledComponentsVersion: null,
|
|
34349
|
+
hasI18nLibrary: false,
|
|
34190
34350
|
hasReactNativeAwarePackage: false,
|
|
34191
34351
|
hasReanimatedAwarePackage: false,
|
|
34192
34352
|
hasSsrDependency: false,
|
|
34353
|
+
hasRemotionDependency: false,
|
|
34354
|
+
hasUnknownRemotionVersion: false,
|
|
34355
|
+
remotionVersion: null,
|
|
34193
34356
|
reanimatedVersion: null
|
|
34194
34357
|
};
|
|
34195
|
-
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
34358
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
|
|
34196
34359
|
let isReactGroupSettled = !collectReactGroup;
|
|
34197
34360
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
34198
34361
|
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
@@ -34201,7 +34364,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34201
34364
|
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
34202
34365
|
visitedDirectories.add(workspaceDirectory);
|
|
34203
34366
|
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34204
|
-
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
34367
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
|
|
34205
34368
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
34206
34369
|
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
34207
34370
|
if (isReactGroupSettled) continue;
|
|
@@ -34425,11 +34588,27 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34425
34588
|
tailwindVersion: null,
|
|
34426
34589
|
zodVersion: null,
|
|
34427
34590
|
zodMajorVersion: null,
|
|
34591
|
+
mobxVersion: null,
|
|
34592
|
+
mobxMajorVersion: null,
|
|
34593
|
+
hasMobxReact: false,
|
|
34594
|
+
hasMobxReactLite: false,
|
|
34595
|
+
hasMobxStateTree: false,
|
|
34596
|
+
hasMobxReactObserver: false,
|
|
34597
|
+
zustandVersion: null,
|
|
34598
|
+
zustandMajorVersion: null,
|
|
34428
34599
|
framework: "unknown",
|
|
34429
34600
|
hasTypeScript: hasOwnTsConfig,
|
|
34430
34601
|
hasReactCompiler: false,
|
|
34431
34602
|
hasReactCompilerLintPlugin: false,
|
|
34432
34603
|
hasTanStackQuery: false,
|
|
34604
|
+
valtioVersion: null,
|
|
34605
|
+
valtioMajorVersion: null,
|
|
34606
|
+
hasRemotion: false,
|
|
34607
|
+
remotionVersion: null,
|
|
34608
|
+
remotionMajorVersion: null,
|
|
34609
|
+
hasI18nLibrary: false,
|
|
34610
|
+
tanstackQueryVersion: null,
|
|
34611
|
+
styledComponentsVersion: null,
|
|
34433
34612
|
hasSsrDependency: false,
|
|
34434
34613
|
preactVersion: null,
|
|
34435
34614
|
preactMajorVersion: null,
|
|
@@ -34528,6 +34707,12 @@ const discoverProject = (directory) => {
|
|
|
34528
34707
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
34529
34708
|
version: workspaceFacts.shopifyFlashList.version
|
|
34530
34709
|
}) : null;
|
|
34710
|
+
const zustandVersion = resolveCatalogBackedDependencyVersion({
|
|
34711
|
+
rootDirectory: directory,
|
|
34712
|
+
rootPackageJson: packageJson,
|
|
34713
|
+
packageName: "zustand",
|
|
34714
|
+
version: workspaceFacts.zustand.version
|
|
34715
|
+
});
|
|
34531
34716
|
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
34532
34717
|
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
34533
34718
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
@@ -34536,7 +34721,21 @@ const discoverProject = (directory) => {
|
|
|
34536
34721
|
packageName: "next",
|
|
34537
34722
|
version: workspaceFacts.next.version
|
|
34538
34723
|
}) : null;
|
|
34724
|
+
const valtioVersion = resolveCatalogBackedDependencyVersion({
|
|
34725
|
+
rootDirectory: directory,
|
|
34726
|
+
rootPackageJson: packageJson,
|
|
34727
|
+
packageName: "valtio",
|
|
34728
|
+
version: workspaceFacts.valtioVersion
|
|
34729
|
+
});
|
|
34730
|
+
const mobxVersion = resolveCatalogBackedDependencyVersion({
|
|
34731
|
+
rootDirectory: directory,
|
|
34732
|
+
rootPackageJson: packageJson,
|
|
34733
|
+
packageName: "mobx",
|
|
34734
|
+
version: workspaceFacts.mobx.version
|
|
34735
|
+
});
|
|
34539
34736
|
const preactVersion = getPreactVersion(packageJson);
|
|
34737
|
+
const remotionVersion = workspaceFacts.remotionVersion;
|
|
34738
|
+
const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
|
|
34540
34739
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
34541
34740
|
const projectInfo = {
|
|
34542
34741
|
rootDirectory: directory,
|
|
@@ -34546,11 +34745,27 @@ const discoverProject = (directory) => {
|
|
|
34546
34745
|
tailwindVersion,
|
|
34547
34746
|
zodVersion,
|
|
34548
34747
|
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
34748
|
+
mobxVersion,
|
|
34749
|
+
mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
|
|
34750
|
+
hasMobxReact: workspaceFacts.hasMobxReact,
|
|
34751
|
+
hasMobxReactLite: workspaceFacts.hasMobxReactLite,
|
|
34752
|
+
hasMobxStateTree: workspaceFacts.hasMobxStateTree,
|
|
34753
|
+
hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
|
|
34754
|
+
zustandVersion,
|
|
34755
|
+
zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
|
|
34549
34756
|
framework,
|
|
34550
34757
|
hasTypeScript,
|
|
34551
34758
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34552
34759
|
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34553
|
-
hasTanStackQuery:
|
|
34760
|
+
hasTanStackQuery: tanstackQueryVersion !== null,
|
|
34761
|
+
hasI18nLibrary: workspaceFacts.hasI18nLibrary,
|
|
34762
|
+
tanstackQueryVersion,
|
|
34763
|
+
styledComponentsVersion: workspaceFacts.styledComponentsVersion,
|
|
34764
|
+
valtioVersion,
|
|
34765
|
+
valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
|
|
34766
|
+
hasRemotion: workspaceFacts.hasRemotionDependency,
|
|
34767
|
+
remotionVersion,
|
|
34768
|
+
remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
|
|
34554
34769
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34555
34770
|
preactVersion,
|
|
34556
34771
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
@@ -34784,7 +34999,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
|
34784
34999
|
"react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
|
|
34785
35000
|
"react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
|
|
34786
35001
|
"react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
|
|
34787
|
-
"react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
|
|
34788
35002
|
"react/jsx-no-undef": "react-doctor/jsx-no-undef",
|
|
34789
35003
|
"react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
|
|
34790
35004
|
"react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
|
|
@@ -37071,9 +37285,25 @@ const BABEL_CONFIG_FILE_NAMES = [
|
|
|
37071
37285
|
".babelrc.json"
|
|
37072
37286
|
];
|
|
37073
37287
|
const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
|
|
37288
|
+
const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
|
|
37289
|
+
const REACT_NATIVE_PACKAGE = "react-native";
|
|
37290
|
+
const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
|
|
37291
|
+
const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
|
|
37074
37292
|
const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
|
|
37075
37293
|
const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
|
|
37294
|
+
const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
|
|
37295
|
+
const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
|
|
37296
|
+
const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
|
|
37297
|
+
if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
|
|
37298
|
+
const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
|
|
37299
|
+
if (normalizedVersionRange === null) return false;
|
|
37300
|
+
const minimumVersion = import_semver.minVersion(normalizedVersionRange);
|
|
37301
|
+
return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
|
|
37302
|
+
};
|
|
37303
|
+
const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
|
|
37076
37304
|
const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
37305
|
+
const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
|
|
37306
|
+
const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
|
|
37077
37307
|
for (const fileName of BABEL_CONFIG_FILE_NAMES) {
|
|
37078
37308
|
const filePath = Path.join(rootDirectory, fileName);
|
|
37079
37309
|
if (!isFile(filePath)) continue;
|
|
@@ -37083,7 +37313,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
|
37083
37313
|
} catch {
|
|
37084
37314
|
continue;
|
|
37085
37315
|
}
|
|
37086
|
-
if (
|
|
37316
|
+
if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
|
|
37087
37317
|
filePath: fileName,
|
|
37088
37318
|
rule: "rn-no-metro-babel-preset",
|
|
37089
37319
|
severity: "error",
|
|
@@ -37106,12 +37336,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
|
|
|
37106
37336
|
return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
|
|
37107
37337
|
};
|
|
37108
37338
|
const RULE_KEY = "no-vulnerable-react-server-components";
|
|
37109
|
-
const DEPENDENCY_SECTIONS = [
|
|
37110
|
-
"dependencies",
|
|
37111
|
-
"devDependencies",
|
|
37112
|
-
"peerDependencies",
|
|
37113
|
-
"optionalDependencies"
|
|
37114
|
-
];
|
|
37115
37339
|
const REACT_RSC_ADVISORIES_BY_MINOR = {
|
|
37116
37340
|
"19.0": {
|
|
37117
37341
|
rceFixedVersion: "19.0.1",
|
|
@@ -37158,20 +37382,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
|
|
|
37158
37382
|
for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
|
|
37159
37383
|
return [...directories];
|
|
37160
37384
|
};
|
|
37161
|
-
const readDeclaredSpec = (packageJson, packageName) => {
|
|
37162
|
-
for (const section of DEPENDENCY_SECTIONS) {
|
|
37163
|
-
const spec = packageJson[section]?.[packageName];
|
|
37164
|
-
if (typeof spec === "string") return spec;
|
|
37165
|
-
}
|
|
37166
|
-
return null;
|
|
37167
|
-
};
|
|
37168
37385
|
const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
|
|
37169
37386
|
const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
|
|
37170
37387
|
if (isFile(manifestPath)) {
|
|
37171
37388
|
const installedVersion = import_semver.valid(readPackageJson(manifestPath).version ?? null);
|
|
37172
37389
|
if (installedVersion !== null) return installedVersion;
|
|
37173
37390
|
}
|
|
37174
|
-
const candidateSpecs = [
|
|
37391
|
+
const candidateSpecs = [getDependencySpec(readPackageJson(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
|
|
37175
37392
|
for (const spec of candidateSpecs) {
|
|
37176
37393
|
const pinnedVersion = spec === null ? null : import_semver.valid(spec);
|
|
37177
37394
|
if (pinnedVersion !== null) return pinnedVersion;
|
|
@@ -37839,21 +38056,50 @@ const buildCapabilities = (project) => {
|
|
|
37839
38056
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37840
38057
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37841
38058
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
38059
|
+
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
|
|
37842
38060
|
addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
|
|
37843
38061
|
if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
|
|
37844
38062
|
major: 19,
|
|
37845
38063
|
minor: 2
|
|
37846
38064
|
})) capabilities.add("react:19.2");
|
|
37847
|
-
if (project.tailwindVersion !== null)
|
|
37848
|
-
|
|
37849
|
-
|
|
37850
|
-
|
|
37851
|
-
|
|
38065
|
+
if (project.tailwindVersion !== null) {
|
|
38066
|
+
capabilities.add("tailwind");
|
|
38067
|
+
const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
|
|
38068
|
+
if (isMajorMinorAtLeast(tailwindVersion, {
|
|
38069
|
+
major: 3,
|
|
38070
|
+
minor: 4
|
|
38071
|
+
})) capabilities.add("tailwind:3.4");
|
|
38072
|
+
if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
|
|
38073
|
+
major: 4,
|
|
38074
|
+
minor: 0
|
|
38075
|
+
})) capabilities.add("tailwind:4");
|
|
38076
|
+
}
|
|
37852
38077
|
if (project.zodVersion !== null) capabilities.add("zod");
|
|
37853
38078
|
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
38079
|
+
if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
|
|
38080
|
+
if (project.hasMobxReact === true) capabilities.add("mobx-react");
|
|
38081
|
+
if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
|
|
38082
|
+
if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
|
|
38083
|
+
if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
|
|
38084
|
+
if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
|
|
38085
|
+
if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
|
|
38086
|
+
if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
|
|
38087
|
+
if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
|
|
37854
38088
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
37855
38089
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
37856
|
-
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
38090
|
+
if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
|
|
38091
|
+
if (project.styledComponentsVersion) {
|
|
38092
|
+
capabilities.add("styled-components");
|
|
38093
|
+
const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
|
|
38094
|
+
if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
|
|
38095
|
+
}
|
|
38096
|
+
if (project.hasI18nLibrary) capabilities.add("i18n");
|
|
38097
|
+
if (project.valtioVersion !== null) capabilities.add("valtio");
|
|
38098
|
+
addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
|
|
38099
|
+
if (project.hasRemotion) {
|
|
38100
|
+
capabilities.add("remotion");
|
|
38101
|
+
addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
|
|
38102
|
+
}
|
|
37857
38103
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
37858
38104
|
if (project.preactVersion !== null) capabilities.add("preact");
|
|
37859
38105
|
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
@@ -37868,7 +38114,7 @@ const getCapabilities = (project) => {
|
|
|
37868
38114
|
capabilitiesByProject.set(project, capabilities);
|
|
37869
38115
|
return capabilities;
|
|
37870
38116
|
};
|
|
37871
|
-
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
|
|
38117
|
+
const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
|
|
37872
38118
|
if (requires) {
|
|
37873
38119
|
for (const capability of requires) if (!capabilities.has(capability)) return false;
|
|
37874
38120
|
}
|
|
@@ -37879,20 +38125,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
|
|
|
37879
38125
|
if (tags) {
|
|
37880
38126
|
for (const tag of tags) if (ignoredTags.has(tag)) return false;
|
|
37881
38127
|
}
|
|
38128
|
+
if (includedTags && includedTags.size > 0) {
|
|
38129
|
+
if (!tags?.some((tag) => includedTags.has(tag))) return false;
|
|
38130
|
+
}
|
|
37882
38131
|
return true;
|
|
37883
38132
|
};
|
|
38133
|
+
const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
|
|
37884
38134
|
const yieldToEventLoop = () => new Promise((resolve) => {
|
|
37885
38135
|
setImmediate(resolve);
|
|
37886
38136
|
});
|
|
37887
38137
|
const createSecurityScanSession = (rootDirectory, options) => {
|
|
37888
38138
|
const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
|
|
37889
38139
|
const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
|
|
38140
|
+
const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
|
|
37890
38141
|
const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
|
|
37891
38142
|
const rule = entry.rule;
|
|
37892
38143
|
const scan = rule.scan;
|
|
37893
38144
|
if (typeof scan !== "function") return [];
|
|
37894
|
-
if (
|
|
37895
|
-
|
|
38145
|
+
if (!shouldEnableRuleByDefaultStatus({
|
|
38146
|
+
defaultEnabled: rule.defaultEnabled,
|
|
38147
|
+
includeTagDefaults: options.includeTagDefaults === true,
|
|
38148
|
+
hasIncludedTags: includedTags.size > 0
|
|
38149
|
+
})) return [];
|
|
38150
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
|
|
37896
38151
|
return [{
|
|
37897
38152
|
entry,
|
|
37898
38153
|
scan,
|
|
@@ -39090,6 +39345,35 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
39090
39345
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
39091
39346
|
};
|
|
39092
39347
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
39348
|
+
const parseBaselineDiffPlan = (value) => {
|
|
39349
|
+
const entries = splitNullSeparated(value);
|
|
39350
|
+
const baseFiles = /* @__PURE__ */ new Set();
|
|
39351
|
+
const headFiles = /* @__PURE__ */ new Set();
|
|
39352
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
39353
|
+
const status = entries[entryIndex];
|
|
39354
|
+
const filePath = entries[entryIndex + 1];
|
|
39355
|
+
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
39356
|
+
if (status === "A") {
|
|
39357
|
+
headFiles.add(filePath);
|
|
39358
|
+
continue;
|
|
39359
|
+
}
|
|
39360
|
+
if (status === "D") {
|
|
39361
|
+
baseFiles.add(filePath);
|
|
39362
|
+
continue;
|
|
39363
|
+
}
|
|
39364
|
+
if (status === "M" || status === "T") {
|
|
39365
|
+
baseFiles.add(filePath);
|
|
39366
|
+
headFiles.add(filePath);
|
|
39367
|
+
continue;
|
|
39368
|
+
}
|
|
39369
|
+
return null;
|
|
39370
|
+
}
|
|
39371
|
+
return {
|
|
39372
|
+
baseFiles: [...baseFiles],
|
|
39373
|
+
headFiles: [...headFiles],
|
|
39374
|
+
untrackedFiles: []
|
|
39375
|
+
};
|
|
39376
|
+
};
|
|
39093
39377
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
39094
39378
|
/**
|
|
39095
39379
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -39292,6 +39576,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39292
39576
|
githubViewerPermission,
|
|
39293
39577
|
branchExists,
|
|
39294
39578
|
mergeBase,
|
|
39579
|
+
baselineDiffPlan: (input) => {
|
|
39580
|
+
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
39581
|
+
return gen(function* () {
|
|
39582
|
+
const unmerged = yield* runGit(input.directory, [
|
|
39583
|
+
"diff",
|
|
39584
|
+
"--no-ext-diff",
|
|
39585
|
+
"-z",
|
|
39586
|
+
"--name-only",
|
|
39587
|
+
"--diff-filter=U",
|
|
39588
|
+
"--relative"
|
|
39589
|
+
]);
|
|
39590
|
+
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
39591
|
+
const result = yield* runGit(input.directory, [
|
|
39592
|
+
"diff",
|
|
39593
|
+
"--no-ext-diff",
|
|
39594
|
+
"--no-textconv",
|
|
39595
|
+
"--no-renames",
|
|
39596
|
+
"-z",
|
|
39597
|
+
"--name-status",
|
|
39598
|
+
"--relative",
|
|
39599
|
+
input.ref
|
|
39600
|
+
]);
|
|
39601
|
+
if (result.status !== 0) return null;
|
|
39602
|
+
const plan = parseBaselineDiffPlan(result.stdout);
|
|
39603
|
+
if (plan === null) return null;
|
|
39604
|
+
const untracked = yield* runGit(input.directory, [
|
|
39605
|
+
"ls-files",
|
|
39606
|
+
"--others",
|
|
39607
|
+
"--exclude-standard",
|
|
39608
|
+
"-z"
|
|
39609
|
+
]);
|
|
39610
|
+
if (untracked.status !== 0) return null;
|
|
39611
|
+
return {
|
|
39612
|
+
baseFiles: plan.baseFiles,
|
|
39613
|
+
headFiles: plan.headFiles,
|
|
39614
|
+
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
39615
|
+
};
|
|
39616
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
39617
|
+
},
|
|
39295
39618
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
39296
39619
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
39297
39620
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -39441,6 +39764,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39441
39764
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
39442
39765
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
39443
39766
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
39767
|
+
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
39444
39768
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
39445
39769
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
39446
39770
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -39809,8 +40133,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
|
|
|
39809
40133
|
}
|
|
39810
40134
|
return enabled;
|
|
39811
40135
|
};
|
|
39812
|
-
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
39813
|
-
const
|
|
40136
|
+
const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
|
|
40137
|
+
const hasIncludedTags = includedTags.size > 0;
|
|
40138
|
+
const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
|
|
39814
40139
|
const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
|
|
39815
40140
|
const jsPlugins = [];
|
|
39816
40141
|
if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
|
|
@@ -39825,9 +40150,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39825
40150
|
if (rule.scan !== void 0) continue;
|
|
39826
40151
|
if (customRulesOnly && registryEntry.originallyExternal) continue;
|
|
39827
40152
|
if (rule.framework !== "global" && !rule.requires) continue;
|
|
39828
|
-
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
|
|
40153
|
+
if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
|
|
39829
40154
|
const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
|
|
39830
|
-
if (
|
|
40155
|
+
if (!shouldEnableRuleByDefaultStatus({
|
|
40156
|
+
defaultEnabled: rule.defaultEnabled,
|
|
40157
|
+
includeTagDefaults,
|
|
40158
|
+
hasIncludedTags,
|
|
40159
|
+
hasExplicitOverride: explicitRuleOverride !== void 0
|
|
40160
|
+
})) continue;
|
|
39831
40161
|
const severity = resolveRuleSeverityOverride({
|
|
39832
40162
|
ruleKey: registryEntry.key,
|
|
39833
40163
|
category: rule.category
|
|
@@ -39836,7 +40166,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
|
|
|
39836
40166
|
enabledReactDoctorRules[registryEntry.key] = severity;
|
|
39837
40167
|
}
|
|
39838
40168
|
const userPluginRules = {};
|
|
39839
|
-
if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
|
|
40169
|
+
if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
|
|
39840
40170
|
Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
|
|
39841
40171
|
jsPlugins.push(userPlugin.entry);
|
|
39842
40172
|
}
|
|
@@ -40053,6 +40383,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
40053
40383
|
}
|
|
40054
40384
|
};
|
|
40055
40385
|
};
|
|
40386
|
+
const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
|
|
40387
|
+
const fingerprintFileContents = (filePath, fingerprintLength) => {
|
|
40388
|
+
const fileStats = NFS.statSync(filePath, { bigint: true });
|
|
40389
|
+
const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
|
|
40390
|
+
if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
|
|
40391
|
+
const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
|
|
40392
|
+
fingerprintCacheByFilePath.set(filePath, {
|
|
40393
|
+
fingerprint,
|
|
40394
|
+
modifiedTimeNanoseconds: fileStats.mtimeNs,
|
|
40395
|
+
sizeBytes: fileStats.size
|
|
40396
|
+
});
|
|
40397
|
+
return fingerprint;
|
|
40398
|
+
};
|
|
40056
40399
|
const bundledRequire = createRequire(import.meta.url);
|
|
40057
40400
|
const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
|
|
40058
40401
|
const resolveChildNodeVersion = (nodeBinaryPath) => {
|
|
@@ -40076,6 +40419,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
|
40076
40419
|
"oxlint-plugin-react-doctor/package.json",
|
|
40077
40420
|
"eslint-plugin-react-hooks/package.json"
|
|
40078
40421
|
];
|
|
40422
|
+
const resolvePluginFingerprint = () => {
|
|
40423
|
+
try {
|
|
40424
|
+
return fingerprintFileContents(bundledRequire.resolve("oxlint-plugin-react-doctor"), 16);
|
|
40425
|
+
} catch {
|
|
40426
|
+
return "unresolved";
|
|
40427
|
+
}
|
|
40428
|
+
};
|
|
40079
40429
|
const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
40080
40430
|
const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
|
|
40081
40431
|
for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
|
|
@@ -40085,6 +40435,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
|
|
|
40085
40435
|
} catch {
|
|
40086
40436
|
versions.push(`${specifier}=missing`);
|
|
40087
40437
|
}
|
|
40438
|
+
versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
|
|
40088
40439
|
return versions;
|
|
40089
40440
|
};
|
|
40090
40441
|
const esmRequire = createRequire(import.meta.url);
|
|
@@ -40778,12 +41129,17 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
|
|
|
40778
41129
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40779
41130
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40780
41131
|
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`.";
|
|
41132
|
+
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`.";
|
|
40781
41133
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
40782
41134
|
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
40783
41135
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
40784
41136
|
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
40785
41137
|
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
40786
41138
|
};
|
|
41139
|
+
const buildSetStateInEffectMessage = (reasonSummary) => {
|
|
41140
|
+
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
41141
|
+
return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
|
|
41142
|
+
};
|
|
40787
41143
|
const PLUGIN_CATEGORY_MAP = {
|
|
40788
41144
|
react: "Bugs",
|
|
40789
41145
|
"react-hooks": "Bugs",
|
|
@@ -40841,6 +41197,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40841
41197
|
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40842
41198
|
help: reasonDetail || help
|
|
40843
41199
|
};
|
|
41200
|
+
if (rule === "set-state-in-effect") return {
|
|
41201
|
+
message: buildSetStateInEffectMessage(reasonSummary.trim()),
|
|
41202
|
+
help: reasonDetail || help
|
|
41203
|
+
};
|
|
40844
41204
|
return {
|
|
40845
41205
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40846
41206
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -41551,7 +41911,7 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
41551
41911
|
* 6. always restore disable directives + clean up the temp dir
|
|
41552
41912
|
*/
|
|
41553
41913
|
const runOxlint = async (options) => {
|
|
41554
|
-
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;
|
|
41914
|
+
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;
|
|
41555
41915
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
41556
41916
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
41557
41917
|
validateRuleRegistration();
|
|
@@ -41565,13 +41925,15 @@ const runOxlint = async (options) => {
|
|
|
41565
41925
|
}
|
|
41566
41926
|
const pluginPath = resolvePluginPath();
|
|
41567
41927
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
41568
|
-
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
41928
|
+
const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
41569
41929
|
const buildConfig = (overrides) => createOxlintConfig({
|
|
41570
41930
|
pluginPath,
|
|
41571
41931
|
project,
|
|
41572
41932
|
customRulesOnly,
|
|
41573
41933
|
extendsPaths: overrides.extendsPaths,
|
|
41574
41934
|
ignoredTags,
|
|
41935
|
+
includedTags,
|
|
41936
|
+
includeTagDefaults,
|
|
41575
41937
|
serverAuthFunctionNames,
|
|
41576
41938
|
severityControls,
|
|
41577
41939
|
userPlugins,
|
|
@@ -41960,6 +42322,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
41960
42322
|
respectInlineDisables: input.respectInlineDisables,
|
|
41961
42323
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
41962
42324
|
ignoredTags: input.ignoredTags,
|
|
42325
|
+
includedTags: input.includedTags,
|
|
42326
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
41963
42327
|
userConfig: input.userConfig ?? null,
|
|
41964
42328
|
configSourceDirectory: input.configSourceDirectory,
|
|
41965
42329
|
onPartialFailure: (reason) => {
|
|
@@ -42808,7 +43172,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42808
43172
|
const securityScanFailedRef = yield* make$13(false);
|
|
42809
43173
|
const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
|
|
42810
43174
|
project,
|
|
42811
|
-
ignoredTags: input.ignoredTags
|
|
43175
|
+
ignoredTags: input.ignoredTags,
|
|
43176
|
+
includedTags: input.includedTags,
|
|
43177
|
+
includeTagDefaults: input.includeTagDefaults
|
|
42812
43178
|
})).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
|
|
42813
43179
|
const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
|
|
42814
43180
|
const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
|
|
@@ -42899,6 +43265,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42899
43265
|
respectInlineDisables: input.respectInlineDisables,
|
|
42900
43266
|
adoptExistingLintConfig: input.adoptExistingLintConfig,
|
|
42901
43267
|
ignoredTags: input.ignoredTags,
|
|
43268
|
+
includedTags: input.includedTags,
|
|
43269
|
+
includeTagDefaults: input.includeTagDefaults,
|
|
42902
43270
|
userConfig: resolvedConfig.config ?? void 0,
|
|
42903
43271
|
configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
|
|
42904
43272
|
onFileProgress: (scannedFileCount, totalFileCount) => {
|
|
@@ -43166,12 +43534,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
43166
43534
|
*/
|
|
43167
43535
|
const materializeSourceTree = (input) => gen(function* () {
|
|
43168
43536
|
const materializedFiles = [];
|
|
43537
|
+
const unmaterializedFiles = [];
|
|
43169
43538
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
43170
43539
|
for (const relativePath of input.files) {
|
|
43171
43540
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
43172
|
-
if (content === null)
|
|
43541
|
+
if (content === null) {
|
|
43542
|
+
unmaterializedFiles.push(relativePath);
|
|
43543
|
+
continue;
|
|
43544
|
+
}
|
|
43173
43545
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
43174
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
43546
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
|
|
43547
|
+
unmaterializedFiles.push(relativePath);
|
|
43548
|
+
continue;
|
|
43549
|
+
}
|
|
43175
43550
|
yield* sync(() => {
|
|
43176
43551
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
43177
43552
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -43188,6 +43563,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
43188
43563
|
return {
|
|
43189
43564
|
tempDirectory: input.tempDirectory,
|
|
43190
43565
|
materializedFiles,
|
|
43566
|
+
unmaterializedFiles,
|
|
43191
43567
|
cleanup: () => {
|
|
43192
43568
|
try {
|
|
43193
43569
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -43751,4 +44127,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
43751
44127
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
43752
44128
|
|
|
43753
44129
|
//# sourceMappingURL=index.js.map
|
|
43754
|
-
//# debugId=
|
|
44130
|
+
//# debugId=4ef51735-a42d-5161-b990-86e4fa9e4d19
|