oxlint-plugin-react-doctor 0.7.3-dev.82187a3 → 0.7.3-dev.f91ede7
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/index.d.ts +46 -0
- package/dist/index.js +72 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4836,6 +4836,29 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
4836
4836
|
readonly recommendationFor?: (hasCapability: CapabilityQuery) => string | undefined;
|
|
4837
4837
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
4838
4838
|
};
|
|
4839
|
+
}, {
|
|
4840
|
+
readonly key: "react-doctor/no-match-media-in-state-initializer";
|
|
4841
|
+
readonly id: "no-match-media-in-state-initializer";
|
|
4842
|
+
readonly source: "react-doctor";
|
|
4843
|
+
readonly originallyExternal: false;
|
|
4844
|
+
readonly rule: {
|
|
4845
|
+
readonly framework: "global";
|
|
4846
|
+
readonly category: "Bugs";
|
|
4847
|
+
readonly requires: readonly Capability[];
|
|
4848
|
+
readonly id: string;
|
|
4849
|
+
readonly title?: string;
|
|
4850
|
+
readonly severity: RuleSeverity;
|
|
4851
|
+
readonly disabledWhen?: ReadonlyArray<Capability>;
|
|
4852
|
+
readonly tags?: ReadonlyArray<string>;
|
|
4853
|
+
readonly matchByOccurrence?: boolean;
|
|
4854
|
+
readonly defaultEnabled?: boolean;
|
|
4855
|
+
readonly lifecycle?: "retired";
|
|
4856
|
+
readonly scan?: FileScan;
|
|
4857
|
+
readonly committedFilesOnly?: boolean;
|
|
4858
|
+
readonly recommendation?: string;
|
|
4859
|
+
readonly recommendationFor?: (hasCapability: CapabilityQuery) => string | undefined;
|
|
4860
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
4861
|
+
};
|
|
4839
4862
|
}, {
|
|
4840
4863
|
readonly key: "react-doctor/no-mirror-prop-effect";
|
|
4841
4864
|
readonly id: "no-mirror-prop-effect";
|
|
@@ -13964,6 +13987,29 @@ declare const RULES: readonly [{
|
|
|
13964
13987
|
readonly recommendationFor?: (hasCapability: CapabilityQuery) => string | undefined;
|
|
13965
13988
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
13966
13989
|
};
|
|
13990
|
+
}, {
|
|
13991
|
+
readonly key: "react-doctor/no-match-media-in-state-initializer";
|
|
13992
|
+
readonly id: "no-match-media-in-state-initializer";
|
|
13993
|
+
readonly source: "react-doctor";
|
|
13994
|
+
readonly originallyExternal: false;
|
|
13995
|
+
readonly rule: {
|
|
13996
|
+
readonly framework: "global";
|
|
13997
|
+
readonly category: "Bugs";
|
|
13998
|
+
readonly requires: readonly Capability[];
|
|
13999
|
+
readonly id: string;
|
|
14000
|
+
readonly title?: string;
|
|
14001
|
+
readonly severity: RuleSeverity;
|
|
14002
|
+
readonly disabledWhen?: ReadonlyArray<Capability>;
|
|
14003
|
+
readonly tags?: ReadonlyArray<string>;
|
|
14004
|
+
readonly matchByOccurrence?: boolean;
|
|
14005
|
+
readonly defaultEnabled?: boolean;
|
|
14006
|
+
readonly lifecycle?: "retired";
|
|
14007
|
+
readonly scan?: FileScan;
|
|
14008
|
+
readonly committedFilesOnly?: boolean;
|
|
14009
|
+
readonly recommendation?: string;
|
|
14010
|
+
readonly recommendationFor?: (hasCapability: CapabilityQuery) => string | undefined;
|
|
14011
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
14012
|
+
};
|
|
13967
14013
|
}, {
|
|
13968
14014
|
readonly key: "react-doctor/no-mirror-prop-effect";
|
|
13969
14015
|
readonly id: "no-mirror-prop-effect";
|
package/dist/index.js
CHANGED
|
@@ -31160,6 +31160,64 @@ const noManyBooleanProps = defineRule({
|
|
|
31160
31160
|
}
|
|
31161
31161
|
});
|
|
31162
31162
|
//#endregion
|
|
31163
|
+
//#region src/plugin/utils/is-global-match-media-call.ts
|
|
31164
|
+
const isGlobalMatchMediaCall = (node, scopes) => {
|
|
31165
|
+
if (!isNodeOfType(node, "CallExpression")) return false;
|
|
31166
|
+
const callee = stripParenExpression(node.callee);
|
|
31167
|
+
if (isNodeOfType(callee, "Identifier")) return callee.name === "matchMedia" && scopes.isGlobalReference(callee);
|
|
31168
|
+
if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(callee.property, "Identifier") || callee.property.name !== "matchMedia") return false;
|
|
31169
|
+
const receiver = stripParenExpression(callee.object);
|
|
31170
|
+
return isNodeOfType(receiver, "Identifier") && (receiver.name === "window" || receiver.name === "globalThis") && scopes.isGlobalReference(receiver);
|
|
31171
|
+
};
|
|
31172
|
+
//#endregion
|
|
31173
|
+
//#region src/plugin/rules/performance/no-match-media-in-state-initializer.ts
|
|
31174
|
+
const REACT_USE_STATE_OPTIONS = {
|
|
31175
|
+
allowGlobalReactNamespace: true,
|
|
31176
|
+
allowUnboundBareCalls: false
|
|
31177
|
+
};
|
|
31178
|
+
const isReactUseStateCall = (node, context) => isReactApiCall(node, "useState", context.scopes, REACT_USE_STATE_OPTIONS);
|
|
31179
|
+
const findDirectMatchMediaCall = (root, context) => {
|
|
31180
|
+
let matchMediaCall = null;
|
|
31181
|
+
walkAst(root, (visitedNode) => {
|
|
31182
|
+
if (matchMediaCall) return false;
|
|
31183
|
+
if (isFunctionLike$1(visitedNode)) return false;
|
|
31184
|
+
if (isGlobalMatchMediaCall(visitedNode, context.scopes)) {
|
|
31185
|
+
matchMediaCall = visitedNode;
|
|
31186
|
+
return false;
|
|
31187
|
+
}
|
|
31188
|
+
});
|
|
31189
|
+
return matchMediaCall;
|
|
31190
|
+
};
|
|
31191
|
+
const findMatchMediaCallDuringInitialization = (initializer, context) => {
|
|
31192
|
+
const rootInitializer = stripParenExpression(initializer);
|
|
31193
|
+
if (!isFunctionLike$1(rootInitializer)) return findDirectMatchMediaCall(rootInitializer, context);
|
|
31194
|
+
if (rootInitializer.async || rootInitializer.generator) return null;
|
|
31195
|
+
return findDirectMatchMediaCall(rootInitializer.body, context);
|
|
31196
|
+
};
|
|
31197
|
+
const noMatchMediaInStateInitializer = defineRule({
|
|
31198
|
+
id: "no-match-media-in-state-initializer",
|
|
31199
|
+
title: "matchMedia in state initializer",
|
|
31200
|
+
severity: "warn",
|
|
31201
|
+
category: "Correctness",
|
|
31202
|
+
disabledWhen: ["vite", "cra"],
|
|
31203
|
+
recommendation: "Prefer CSS media queries for layout, or subscribe with `useSyncExternalStore` and provide a stable server snapshot.",
|
|
31204
|
+
create: (context) => {
|
|
31205
|
+
if (isTestlikeFilename(context.filename)) return {};
|
|
31206
|
+
if (classifyReactNativeFileTarget(context) === "react-native") return {};
|
|
31207
|
+
return { CallExpression(node) {
|
|
31208
|
+
if (!isReactUseStateCall(node, context)) return;
|
|
31209
|
+
const initializer = node.arguments?.[0];
|
|
31210
|
+
if (!initializer || initializer.type === "SpreadElement") return;
|
|
31211
|
+
const matchMediaCall = findMatchMediaCallDuringInitialization(initializer, context);
|
|
31212
|
+
if (!matchMediaCall) return;
|
|
31213
|
+
context.report({
|
|
31214
|
+
node: matchMediaCall,
|
|
31215
|
+
message: "`matchMedia()` in a useState initializer can cause an SSR crash or seed different server and hydration state. Prefer CSS media queries for layout, or use `useSyncExternalStore` with a stable server snapshot."
|
|
31216
|
+
});
|
|
31217
|
+
} };
|
|
31218
|
+
}
|
|
31219
|
+
});
|
|
31220
|
+
//#endregion
|
|
31163
31221
|
//#region src/plugin/rules/state-and-effects/no-mirror-prop-effect.ts
|
|
31164
31222
|
const getPropRootName = (expression, propNames) => {
|
|
31165
31223
|
const rootName = getRootIdentifierName(expression, { followCallChains: true });
|
|
@@ -55255,6 +55313,18 @@ const reactDoctorRules = [
|
|
|
55255
55313
|
category: "Maintainability"
|
|
55256
55314
|
}
|
|
55257
55315
|
},
|
|
55316
|
+
{
|
|
55317
|
+
key: "react-doctor/no-match-media-in-state-initializer",
|
|
55318
|
+
id: "no-match-media-in-state-initializer",
|
|
55319
|
+
source: "react-doctor",
|
|
55320
|
+
originallyExternal: false,
|
|
55321
|
+
rule: {
|
|
55322
|
+
...noMatchMediaInStateInitializer,
|
|
55323
|
+
framework: "global",
|
|
55324
|
+
category: "Bugs",
|
|
55325
|
+
requires: [...new Set(["react", ...noMatchMediaInStateInitializer.requires ?? []])]
|
|
55326
|
+
}
|
|
55327
|
+
},
|
|
55258
55328
|
{
|
|
55259
55329
|
key: "react-doctor/no-mirror-prop-effect",
|
|
55260
55330
|
id: "no-mirror-prop-effect",
|
|
@@ -58123,6 +58193,7 @@ const CROSS_FILE_RULE_IDS = new Set([
|
|
|
58123
58193
|
"no-full-lodash-import",
|
|
58124
58194
|
"no-indeterminate-attribute",
|
|
58125
58195
|
"no-locale-format-in-render",
|
|
58196
|
+
"no-match-media-in-state-initializer",
|
|
58126
58197
|
"no-mutating-reducer-state",
|
|
58127
58198
|
"prefer-dynamic-import",
|
|
58128
58199
|
"rendering-hydration-mismatch-time",
|
|
@@ -58259,6 +58330,7 @@ const CROSS_FILE_DEPENDENCY_COLLECTORS = new Map([
|
|
|
58259
58330
|
["no-full-lodash-import", collectNearestManifestDependencies],
|
|
58260
58331
|
["no-indeterminate-attribute", collectNearestManifestDependencies],
|
|
58261
58332
|
["no-locale-format-in-render", collectNearestManifestDependencies],
|
|
58333
|
+
["no-match-media-in-state-initializer", collectNearestManifestDependencies],
|
|
58262
58334
|
["no-mutating-reducer-state", collectMutatingReducerDependencies],
|
|
58263
58335
|
["prefer-dynamic-import", collectNearestManifestDependencies],
|
|
58264
58336
|
["rendering-hydration-mismatch-time", collectNearestManifestDependencies],
|