react-doctor 0.8.1-dev.7818922 → 0.8.1-dev.7eca0ee
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +749 -92
- package/dist/index.d.ts +33 -15
- package/dist/index.js +254 -23
- package/dist/lsp.js +254 -23
- package/package.json +2 -2
package/dist/lsp.js
CHANGED
|
@@ -34173,6 +34173,10 @@ const listWorkspacePackages = (rootDirectory) => {
|
|
|
34173
34173
|
return packages;
|
|
34174
34174
|
};
|
|
34175
34175
|
const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
|
|
34176
|
+
const MOBX_REACT_PACKAGE_NAME = "mobx-react";
|
|
34177
|
+
const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
|
|
34178
|
+
const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
|
|
34179
|
+
const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
|
|
34176
34180
|
const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
|
|
34177
34181
|
const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
|
|
34178
34182
|
const dependencyDeclaration = getDependencyDeclaration({
|
|
@@ -34191,7 +34195,18 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
|
|
|
34191
34195
|
if (nextMajor === null) return false;
|
|
34192
34196
|
return nextMajor < currentMajor;
|
|
34193
34197
|
};
|
|
34194
|
-
const
|
|
34198
|
+
const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
|
|
34199
|
+
if (currentFact.version === null) return true;
|
|
34200
|
+
if (nextFact.version === null) return false;
|
|
34201
|
+
const currentMajor = getLowestDependencyMajor(currentFact.version);
|
|
34202
|
+
const nextMajor = getLowestDependencyMajor(nextFact.version);
|
|
34203
|
+
if (currentMajor === null) return false;
|
|
34204
|
+
if (nextMajor === null) return true;
|
|
34205
|
+
if (currentMajor > latestSupportedMajor) return false;
|
|
34206
|
+
if (nextMajor > latestSupportedMajor) return true;
|
|
34207
|
+
return nextMajor < currentMajor;
|
|
34208
|
+
};
|
|
34209
|
+
const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
|
|
34195
34210
|
if (facts.expo.version === null) {
|
|
34196
34211
|
const spec = getDependencySpec(packageJson, "expo");
|
|
34197
34212
|
if (spec !== null) facts.expo = {
|
|
@@ -34213,13 +34228,65 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
|
34213
34228
|
sourceDirectory: directory
|
|
34214
34229
|
};
|
|
34215
34230
|
}
|
|
34231
|
+
const mobxSpec = getDependencySpec(packageJson, "mobx");
|
|
34232
|
+
if (mobxSpec !== null) {
|
|
34233
|
+
const nextMobxFact = {
|
|
34234
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34235
|
+
rootDirectory: directory,
|
|
34236
|
+
rootPackageJson: packageJson,
|
|
34237
|
+
packageName: "mobx",
|
|
34238
|
+
version: mobxSpec
|
|
34239
|
+
}),
|
|
34240
|
+
sourceDirectory: directory
|
|
34241
|
+
};
|
|
34242
|
+
if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
|
|
34243
|
+
}
|
|
34244
|
+
facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
|
|
34245
|
+
facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
|
|
34246
|
+
facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
|
|
34247
|
+
facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
|
|
34248
|
+
const zustandSpec = getDependencySpec(packageJson, "zustand");
|
|
34249
|
+
if (zustandSpec !== null) {
|
|
34250
|
+
const nextZustandFact = {
|
|
34251
|
+
version: resolveCatalogBackedDependencyVersion({
|
|
34252
|
+
rootDirectory: directory,
|
|
34253
|
+
rootPackageJson: packageJson,
|
|
34254
|
+
packageName: "zustand",
|
|
34255
|
+
version: zustandSpec
|
|
34256
|
+
}),
|
|
34257
|
+
sourceDirectory: directory
|
|
34258
|
+
};
|
|
34259
|
+
if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
|
|
34260
|
+
}
|
|
34216
34261
|
if (facts.reanimatedVersion === null) {
|
|
34217
34262
|
const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
|
|
34218
34263
|
if (spec !== null) facts.reanimatedVersion = spec;
|
|
34219
34264
|
}
|
|
34265
|
+
if (facts.valtioVersion === null) {
|
|
34266
|
+
const spec = getDependencySpec(packageJson, "valtio");
|
|
34267
|
+
if (spec !== null) facts.valtioVersion = spec;
|
|
34268
|
+
}
|
|
34220
34269
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34221
34270
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34222
34271
|
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
34272
|
+
const remotionSpec = getDependencySpec(packageJson, "remotion");
|
|
34273
|
+
if (remotionSpec !== null) {
|
|
34274
|
+
facts.hasRemotionDependency = true;
|
|
34275
|
+
const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
|
|
34276
|
+
rootDirectory,
|
|
34277
|
+
rootPackageJson,
|
|
34278
|
+
packageName: "remotion",
|
|
34279
|
+
version: remotionSpec
|
|
34280
|
+
});
|
|
34281
|
+
const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
|
|
34282
|
+
if (remotionMajorVersion === null) {
|
|
34283
|
+
facts.hasUnknownRemotionVersion = true;
|
|
34284
|
+
facts.remotionVersion = null;
|
|
34285
|
+
} else if (!facts.hasUnknownRemotionVersion) {
|
|
34286
|
+
const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
|
|
34287
|
+
if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
|
|
34288
|
+
}
|
|
34289
|
+
}
|
|
34223
34290
|
};
|
|
34224
34291
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34225
34292
|
const facts = {
|
|
@@ -34239,12 +34306,28 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34239
34306
|
version: null,
|
|
34240
34307
|
sourceDirectory: null
|
|
34241
34308
|
},
|
|
34309
|
+
valtioVersion: null,
|
|
34310
|
+
mobx: {
|
|
34311
|
+
version: null,
|
|
34312
|
+
sourceDirectory: null
|
|
34313
|
+
},
|
|
34314
|
+
hasMobxReact: false,
|
|
34315
|
+
hasMobxReactLite: false,
|
|
34316
|
+
hasMobxStateTree: false,
|
|
34317
|
+
hasMobxReactObserver: false,
|
|
34318
|
+
zustand: {
|
|
34319
|
+
version: null,
|
|
34320
|
+
sourceDirectory: null
|
|
34321
|
+
},
|
|
34242
34322
|
hasReactNativeAwarePackage: false,
|
|
34243
34323
|
hasReanimatedAwarePackage: false,
|
|
34244
34324
|
hasSsrDependency: false,
|
|
34325
|
+
hasRemotionDependency: false,
|
|
34326
|
+
hasUnknownRemotionVersion: false,
|
|
34327
|
+
remotionVersion: null,
|
|
34245
34328
|
reanimatedVersion: null
|
|
34246
34329
|
};
|
|
34247
|
-
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
34330
|
+
evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
|
|
34248
34331
|
let isReactGroupSettled = !collectReactGroup;
|
|
34249
34332
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
34250
34333
|
for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
|
|
@@ -34253,7 +34336,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34253
34336
|
if (visitedDirectories.has(workspaceDirectory)) continue;
|
|
34254
34337
|
visitedDirectories.add(workspaceDirectory);
|
|
34255
34338
|
const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
|
|
34256
|
-
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
|
|
34339
|
+
evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
|
|
34257
34340
|
const info = extractDependencyInfo(workspacePackageJson);
|
|
34258
34341
|
if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
|
|
34259
34342
|
if (isReactGroupSettled) continue;
|
|
@@ -34477,11 +34560,24 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34477
34560
|
tailwindVersion: null,
|
|
34478
34561
|
zodVersion: null,
|
|
34479
34562
|
zodMajorVersion: null,
|
|
34563
|
+
mobxVersion: null,
|
|
34564
|
+
mobxMajorVersion: null,
|
|
34565
|
+
hasMobxReact: false,
|
|
34566
|
+
hasMobxReactLite: false,
|
|
34567
|
+
hasMobxStateTree: false,
|
|
34568
|
+
hasMobxReactObserver: false,
|
|
34569
|
+
zustandVersion: null,
|
|
34570
|
+
zustandMajorVersion: null,
|
|
34480
34571
|
framework: "unknown",
|
|
34481
34572
|
hasTypeScript: hasOwnTsConfig,
|
|
34482
34573
|
hasReactCompiler: false,
|
|
34483
34574
|
hasReactCompilerLintPlugin: false,
|
|
34484
34575
|
hasTanStackQuery: false,
|
|
34576
|
+
valtioVersion: null,
|
|
34577
|
+
valtioMajorVersion: null,
|
|
34578
|
+
hasRemotion: false,
|
|
34579
|
+
remotionVersion: null,
|
|
34580
|
+
remotionMajorVersion: null,
|
|
34485
34581
|
hasSsrDependency: false,
|
|
34486
34582
|
preactVersion: null,
|
|
34487
34583
|
preactMajorVersion: null,
|
|
@@ -34580,6 +34676,12 @@ const discoverProject = (directory) => {
|
|
|
34580
34676
|
packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
|
|
34581
34677
|
version: workspaceFacts.shopifyFlashList.version
|
|
34582
34678
|
}) : null;
|
|
34679
|
+
const zustandVersion = resolveCatalogBackedDependencyVersion({
|
|
34680
|
+
rootDirectory: directory,
|
|
34681
|
+
rootPackageJson: packageJson,
|
|
34682
|
+
packageName: "zustand",
|
|
34683
|
+
version: workspaceFacts.zustand.version
|
|
34684
|
+
});
|
|
34583
34685
|
const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
|
|
34584
34686
|
const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
|
|
34585
34687
|
const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
|
|
@@ -34588,7 +34690,20 @@ const discoverProject = (directory) => {
|
|
|
34588
34690
|
packageName: "next",
|
|
34589
34691
|
version: workspaceFacts.next.version
|
|
34590
34692
|
}) : null;
|
|
34693
|
+
const valtioVersion = resolveCatalogBackedDependencyVersion({
|
|
34694
|
+
rootDirectory: directory,
|
|
34695
|
+
rootPackageJson: packageJson,
|
|
34696
|
+
packageName: "valtio",
|
|
34697
|
+
version: workspaceFacts.valtioVersion
|
|
34698
|
+
});
|
|
34699
|
+
const mobxVersion = resolveCatalogBackedDependencyVersion({
|
|
34700
|
+
rootDirectory: directory,
|
|
34701
|
+
rootPackageJson: packageJson,
|
|
34702
|
+
packageName: "mobx",
|
|
34703
|
+
version: workspaceFacts.mobx.version
|
|
34704
|
+
});
|
|
34591
34705
|
const preactVersion = getPreactVersion(packageJson);
|
|
34706
|
+
const remotionVersion = workspaceFacts.remotionVersion;
|
|
34592
34707
|
const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
|
|
34593
34708
|
const projectInfo = {
|
|
34594
34709
|
rootDirectory: directory,
|
|
@@ -34598,11 +34713,24 @@ const discoverProject = (directory) => {
|
|
|
34598
34713
|
tailwindVersion,
|
|
34599
34714
|
zodVersion,
|
|
34600
34715
|
zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
|
|
34716
|
+
mobxVersion,
|
|
34717
|
+
mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
|
|
34718
|
+
hasMobxReact: workspaceFacts.hasMobxReact,
|
|
34719
|
+
hasMobxReactLite: workspaceFacts.hasMobxReactLite,
|
|
34720
|
+
hasMobxStateTree: workspaceFacts.hasMobxStateTree,
|
|
34721
|
+
hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
|
|
34722
|
+
zustandVersion,
|
|
34723
|
+
zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
|
|
34601
34724
|
framework,
|
|
34602
34725
|
hasTypeScript,
|
|
34603
34726
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34604
34727
|
hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
|
|
34605
34728
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34729
|
+
valtioVersion,
|
|
34730
|
+
valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
|
|
34731
|
+
hasRemotion: workspaceFacts.hasRemotionDependency,
|
|
34732
|
+
remotionVersion,
|
|
34733
|
+
remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
|
|
34606
34734
|
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34607
34735
|
preactVersion,
|
|
34608
34736
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
@@ -34836,7 +34964,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
|
|
|
34836
34964
|
"react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
|
|
34837
34965
|
"react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
|
|
34838
34966
|
"react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
|
|
34839
|
-
"react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
|
|
34840
34967
|
"react/jsx-no-undef": "react-doctor/jsx-no-undef",
|
|
34841
34968
|
"react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
|
|
34842
34969
|
"react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
|
|
@@ -37049,9 +37176,25 @@ const BABEL_CONFIG_FILE_NAMES = [
|
|
|
37049
37176
|
".babelrc.json"
|
|
37050
37177
|
];
|
|
37051
37178
|
const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
|
|
37179
|
+
const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
|
|
37180
|
+
const REACT_NATIVE_PACKAGE = "react-native";
|
|
37181
|
+
const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
|
|
37182
|
+
const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
|
|
37052
37183
|
const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
|
|
37053
37184
|
const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
|
|
37185
|
+
const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
|
|
37186
|
+
const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
|
|
37187
|
+
const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
|
|
37188
|
+
if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
|
|
37189
|
+
const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
|
|
37190
|
+
if (normalizedVersionRange === null) return false;
|
|
37191
|
+
const minimumVersion = import_semver.minVersion(normalizedVersionRange);
|
|
37192
|
+
return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
|
|
37193
|
+
};
|
|
37194
|
+
const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
|
|
37054
37195
|
const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
37196
|
+
const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
|
|
37197
|
+
const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
|
|
37055
37198
|
for (const fileName of BABEL_CONFIG_FILE_NAMES) {
|
|
37056
37199
|
const filePath = Path.join(rootDirectory, fileName);
|
|
37057
37200
|
if (!isFile(filePath)) continue;
|
|
@@ -37061,7 +37204,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
|
|
|
37061
37204
|
} catch {
|
|
37062
37205
|
continue;
|
|
37063
37206
|
}
|
|
37064
|
-
if (
|
|
37207
|
+
if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
|
|
37065
37208
|
filePath: fileName,
|
|
37066
37209
|
rule: "rn-no-metro-babel-preset",
|
|
37067
37210
|
severity: "error",
|
|
@@ -37084,12 +37227,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
|
|
|
37084
37227
|
return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
|
|
37085
37228
|
};
|
|
37086
37229
|
const RULE_KEY = "no-vulnerable-react-server-components";
|
|
37087
|
-
const DEPENDENCY_SECTIONS = [
|
|
37088
|
-
"dependencies",
|
|
37089
|
-
"devDependencies",
|
|
37090
|
-
"peerDependencies",
|
|
37091
|
-
"optionalDependencies"
|
|
37092
|
-
];
|
|
37093
37230
|
const REACT_RSC_ADVISORIES_BY_MINOR = {
|
|
37094
37231
|
"19.0": {
|
|
37095
37232
|
rceFixedVersion: "19.0.1",
|
|
@@ -37136,20 +37273,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
|
|
|
37136
37273
|
for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
|
|
37137
37274
|
return [...directories];
|
|
37138
37275
|
};
|
|
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
37276
|
const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
|
|
37147
37277
|
const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
|
|
37148
37278
|
if (isFile(manifestPath)) {
|
|
37149
37279
|
const installedVersion = import_semver.valid(readPackageJson(manifestPath).version ?? null);
|
|
37150
37280
|
if (installedVersion !== null) return installedVersion;
|
|
37151
37281
|
}
|
|
37152
|
-
const candidateSpecs = [
|
|
37282
|
+
const candidateSpecs = [getDependencySpec(readPackageJson(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
|
|
37153
37283
|
for (const spec of candidateSpecs) {
|
|
37154
37284
|
const pinnedVersion = spec === null ? null : import_semver.valid(spec);
|
|
37155
37285
|
if (pinnedVersion !== null) return pinnedVersion;
|
|
@@ -37829,9 +37959,24 @@ const buildCapabilities = (project) => {
|
|
|
37829
37959
|
})) capabilities.add("tailwind:3.4");
|
|
37830
37960
|
if (project.zodVersion !== null) capabilities.add("zod");
|
|
37831
37961
|
if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
|
|
37962
|
+
if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
|
|
37963
|
+
if (project.hasMobxReact === true) capabilities.add("mobx-react");
|
|
37964
|
+
if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
|
|
37965
|
+
if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
|
|
37966
|
+
if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
|
|
37967
|
+
if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
|
|
37968
|
+
if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
|
|
37969
|
+
if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
|
|
37970
|
+
if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
|
|
37832
37971
|
if (project.isPreES2023Target) capabilities.add("pre-es2023");
|
|
37833
37972
|
if (project.hasReactCompiler) capabilities.add("react-compiler");
|
|
37834
37973
|
if (project.hasTanStackQuery) capabilities.add("tanstack-query");
|
|
37974
|
+
if (project.valtioVersion !== null) capabilities.add("valtio");
|
|
37975
|
+
addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
|
|
37976
|
+
if (project.hasRemotion) {
|
|
37977
|
+
capabilities.add("remotion");
|
|
37978
|
+
addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
|
|
37979
|
+
}
|
|
37835
37980
|
if (project.hasTypeScript) capabilities.add("typescript");
|
|
37836
37981
|
if (project.preactVersion !== null) capabilities.add("preact");
|
|
37837
37982
|
addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
|
|
@@ -39068,6 +39213,35 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
39068
39213
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
39069
39214
|
};
|
|
39070
39215
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
39216
|
+
const parseBaselineDiffPlan = (value) => {
|
|
39217
|
+
const entries = splitNullSeparated(value);
|
|
39218
|
+
const baseFiles = /* @__PURE__ */ new Set();
|
|
39219
|
+
const headFiles = /* @__PURE__ */ new Set();
|
|
39220
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
39221
|
+
const status = entries[entryIndex];
|
|
39222
|
+
const filePath = entries[entryIndex + 1];
|
|
39223
|
+
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
39224
|
+
if (status === "A") {
|
|
39225
|
+
headFiles.add(filePath);
|
|
39226
|
+
continue;
|
|
39227
|
+
}
|
|
39228
|
+
if (status === "D") {
|
|
39229
|
+
baseFiles.add(filePath);
|
|
39230
|
+
continue;
|
|
39231
|
+
}
|
|
39232
|
+
if (status === "M" || status === "T") {
|
|
39233
|
+
baseFiles.add(filePath);
|
|
39234
|
+
headFiles.add(filePath);
|
|
39235
|
+
continue;
|
|
39236
|
+
}
|
|
39237
|
+
return null;
|
|
39238
|
+
}
|
|
39239
|
+
return {
|
|
39240
|
+
baseFiles: [...baseFiles],
|
|
39241
|
+
headFiles: [...headFiles],
|
|
39242
|
+
untrackedFiles: []
|
|
39243
|
+
};
|
|
39244
|
+
};
|
|
39071
39245
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
39072
39246
|
/**
|
|
39073
39247
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -39270,6 +39444,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39270
39444
|
githubViewerPermission,
|
|
39271
39445
|
branchExists,
|
|
39272
39446
|
mergeBase,
|
|
39447
|
+
baselineDiffPlan: (input) => {
|
|
39448
|
+
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
39449
|
+
return gen(function* () {
|
|
39450
|
+
const unmerged = yield* runGit(input.directory, [
|
|
39451
|
+
"diff",
|
|
39452
|
+
"--no-ext-diff",
|
|
39453
|
+
"-z",
|
|
39454
|
+
"--name-only",
|
|
39455
|
+
"--diff-filter=U",
|
|
39456
|
+
"--relative"
|
|
39457
|
+
]);
|
|
39458
|
+
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
39459
|
+
const result = yield* runGit(input.directory, [
|
|
39460
|
+
"diff",
|
|
39461
|
+
"--no-ext-diff",
|
|
39462
|
+
"--no-textconv",
|
|
39463
|
+
"--no-renames",
|
|
39464
|
+
"-z",
|
|
39465
|
+
"--name-status",
|
|
39466
|
+
"--relative",
|
|
39467
|
+
input.ref
|
|
39468
|
+
]);
|
|
39469
|
+
if (result.status !== 0) return null;
|
|
39470
|
+
const plan = parseBaselineDiffPlan(result.stdout);
|
|
39471
|
+
if (plan === null) return null;
|
|
39472
|
+
const untracked = yield* runGit(input.directory, [
|
|
39473
|
+
"ls-files",
|
|
39474
|
+
"--others",
|
|
39475
|
+
"--exclude-standard",
|
|
39476
|
+
"-z"
|
|
39477
|
+
]);
|
|
39478
|
+
if (untracked.status !== 0) return null;
|
|
39479
|
+
return {
|
|
39480
|
+
baseFiles: plan.baseFiles,
|
|
39481
|
+
headFiles: plan.headFiles,
|
|
39482
|
+
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
39483
|
+
};
|
|
39484
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
39485
|
+
},
|
|
39273
39486
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
39274
39487
|
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
39488
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -39419,6 +39632,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39419
39632
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
39420
39633
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
39421
39634
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
39635
|
+
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
39422
39636
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
39423
39637
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
39424
39638
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -40756,12 +40970,17 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
|
|
|
40756
40970
|
const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
|
|
40757
40971
|
const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
|
|
40758
40972
|
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`.";
|
|
40973
|
+
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
40974
|
const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
|
|
40760
40975
|
const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
|
|
40761
40976
|
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
40762
40977
|
if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
|
|
40763
40978
|
return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
|
|
40764
40979
|
};
|
|
40980
|
+
const buildSetStateInEffectMessage = (reasonSummary) => {
|
|
40981
|
+
const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
|
|
40982
|
+
return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
|
|
40983
|
+
};
|
|
40765
40984
|
const PLUGIN_CATEGORY_MAP = {
|
|
40766
40985
|
react: "Bugs",
|
|
40767
40986
|
"react-hooks": "Bugs",
|
|
@@ -40819,6 +41038,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
|
|
|
40819
41038
|
message: REACT_ERROR_BOUNDARY_MESSAGE,
|
|
40820
41039
|
help: reasonDetail || help
|
|
40821
41040
|
};
|
|
41041
|
+
if (rule === "set-state-in-effect") return {
|
|
41042
|
+
message: buildSetStateInEffectMessage(reasonSummary.trim()),
|
|
41043
|
+
help: reasonDetail || help
|
|
41044
|
+
};
|
|
40822
41045
|
return {
|
|
40823
41046
|
message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
|
|
40824
41047
|
help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
|
|
@@ -43144,12 +43367,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
43144
43367
|
*/
|
|
43145
43368
|
const materializeSourceTree = (input) => gen(function* () {
|
|
43146
43369
|
const materializedFiles = [];
|
|
43370
|
+
const unmaterializedFiles = [];
|
|
43147
43371
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
43148
43372
|
for (const relativePath of input.files) {
|
|
43149
43373
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
43150
|
-
if (content === null)
|
|
43374
|
+
if (content === null) {
|
|
43375
|
+
unmaterializedFiles.push(relativePath);
|
|
43376
|
+
continue;
|
|
43377
|
+
}
|
|
43151
43378
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
43152
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
43379
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
|
|
43380
|
+
unmaterializedFiles.push(relativePath);
|
|
43381
|
+
continue;
|
|
43382
|
+
}
|
|
43153
43383
|
yield* sync(() => {
|
|
43154
43384
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
43155
43385
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -43166,6 +43396,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
43166
43396
|
return {
|
|
43167
43397
|
tempDirectory: input.tempDirectory,
|
|
43168
43398
|
materializedFiles,
|
|
43399
|
+
unmaterializedFiles,
|
|
43169
43400
|
cleanup: () => {
|
|
43170
43401
|
try {
|
|
43171
43402
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -45371,5 +45602,5 @@ const startLanguageServer = () => {
|
|
|
45371
45602
|
};
|
|
45372
45603
|
//#endregion
|
|
45373
45604
|
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=
|
|
45605
|
+
!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]="f2369b82-a22a-50e5-b71b-2ceb30eaee9f")}catch(e){}}();
|
|
45606
|
+
//# debugId=f2369b82-a22a-50e5-b71b-2ceb30eaee9f
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.8.1-dev.
|
|
3
|
+
"version": "0.8.1-dev.7eca0ee",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
68
|
"deslop-js": "0.8.1",
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.8.1-dev.
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.8.1-dev.7eca0ee"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|