oxlint-plugin-react-doctor 0.4.2-dev.98066c2 → 0.4.2-dev.a254414
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 +348 -348
- package/dist/index.js +613 -437
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -719,7 +719,7 @@ const activityWrapsEffectHeavySubtree = defineRule({
|
|
|
719
719
|
if (totalEffects === 0) return;
|
|
720
720
|
context.report({
|
|
721
721
|
node: openingElement,
|
|
722
|
-
message: `Every hide
|
|
722
|
+
message: `Every hide and show rebuilds ${effectfulChildren.join(", ")} from scratch because <Activity> wraps components with ${totalEffects} effect hook${totalEffects === 1 ? "" : "s"}.`
|
|
723
723
|
});
|
|
724
724
|
}
|
|
725
725
|
};
|
|
@@ -1414,12 +1414,12 @@ const objectHasAccessibleChild = (jsxElement, settings) => {
|
|
|
1414
1414
|
};
|
|
1415
1415
|
//#endregion
|
|
1416
1416
|
//#region src/plugin/rules/a11y/alt-text.ts
|
|
1417
|
-
const MISSING_ALT_PROP = "
|
|
1418
|
-
const MISSING_ALT_VALUE = "
|
|
1419
|
-
const ARIA_LABEL_VALUE = "
|
|
1420
|
-
const ARIA_LABELLEDBY_VALUE = "
|
|
1417
|
+
const MISSING_ALT_PROP = "Screen reader users cannot access this image without `alt`. Add `alt=\"image_description\"`, or `alt=\"\"` if it is decorative.";
|
|
1418
|
+
const MISSING_ALT_VALUE = "Screen reader users cannot access this image because its `alt` is empty or invalid. Add a short description, or `alt=\"\"` if it is decorative.";
|
|
1419
|
+
const ARIA_LABEL_VALUE = "Screen reader users hear nothing here because `aria-label` has no value, so give it a short description.";
|
|
1420
|
+
const ARIA_LABELLEDBY_VALUE = "Screen reader users hear nothing here because `aria-labelledby` has no value, so point it at the id of the text that labels this.";
|
|
1421
1421
|
const PREFER_ALT = "Screen readers skip a decorative image more reliably with `alt=\"\"` than `role=\"presentation\"`, so use `alt=\"\"` instead.";
|
|
1422
|
-
const MESSAGE_OBJECT = "
|
|
1422
|
+
const MESSAGE_OBJECT = "Screen reader users cannot use this `<object>` because assistive tech cannot describe it, so add `alt`, `aria-label`, `aria-labelledby`, `title`, or inner fallback text.";
|
|
1423
1423
|
const MESSAGE_AREA = "Blind users can't use this `<area>` of the image map because screen readers can't describe it, so add `alt`, `aria-label`, or `aria-labelledby`.";
|
|
1424
1424
|
const MESSAGE_INPUT_IMAGE = "Blind users can't use this image button because screen readers can't describe it, so add `alt`, `aria-label`, or `aria-labelledby`.";
|
|
1425
1425
|
const resolveSettings$52 = (settings) => {
|
|
@@ -2748,7 +2748,7 @@ const ABSTRACT_ROLES = new Set([
|
|
|
2748
2748
|
const PRESENTATION_ROLES$2 = new Set(["presentation", "none"]);
|
|
2749
2749
|
//#endregion
|
|
2750
2750
|
//#region src/plugin/rules/a11y/aria-role.ts
|
|
2751
|
-
const buildBaseMessage = (suffix) => `
|
|
2751
|
+
const buildBaseMessage = (suffix) => `This \`role\` is not a valid ARIA role, so assistive tech cannot expose it correctly. Use a real, non-abstract role.${suffix}`;
|
|
2752
2752
|
const resolveSettings$49 = (settings) => {
|
|
2753
2753
|
const reactDoctor = settings?.["react-doctor"];
|
|
2754
2754
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.ariaRole ?? {} : {};
|
|
@@ -2762,7 +2762,7 @@ const ariaRole = defineRule({
|
|
|
2762
2762
|
title: "Invalid ARIA role",
|
|
2763
2763
|
tags: ["react-jsx-only"],
|
|
2764
2764
|
severity: "error",
|
|
2765
|
-
recommendation: "Use a real, non-abstract ARIA role.",
|
|
2765
|
+
recommendation: "Use a real, non-abstract ARIA role so assistive tech can expose the element correctly.",
|
|
2766
2766
|
category: "Accessibility",
|
|
2767
2767
|
create: (context) => {
|
|
2768
2768
|
const settings = resolveSettings$49(context.settings);
|
|
@@ -3557,7 +3557,7 @@ const asyncDeferAwait = defineRule({
|
|
|
3557
3557
|
title: "await before an early-return guard",
|
|
3558
3558
|
severity: "warn",
|
|
3559
3559
|
tags: ["test-noise"],
|
|
3560
|
-
recommendation: "Move the `await` below the early-return guard so the skip path stays fast",
|
|
3560
|
+
recommendation: "Move the `await` below the early-return guard so the skip path stays fast and avoids unnecessary async work.",
|
|
3561
3561
|
create: (context) => {
|
|
3562
3562
|
const inspectStatements = (statements) => {
|
|
3563
3563
|
for (let statementIndex = 0; statementIndex < statements.length - 1; statementIndex++) {
|
|
@@ -3800,7 +3800,7 @@ const autocompleteValid = defineRule({
|
|
|
3800
3800
|
title: "Invalid autocomplete value",
|
|
3801
3801
|
tags: ["react-jsx-only"],
|
|
3802
3802
|
severity: "warn",
|
|
3803
|
-
recommendation: "Use a valid autofill token in `autoComplete
|
|
3803
|
+
recommendation: "Use a valid autofill token in `autoComplete` so browsers can fill the right field reliably.",
|
|
3804
3804
|
category: "Accessibility",
|
|
3805
3805
|
create: (context) => {
|
|
3806
3806
|
const settings = resolveSettings$48(context.settings);
|
|
@@ -3855,7 +3855,7 @@ const isCreateElementCall = (node) => {
|
|
|
3855
3855
|
//#endregion
|
|
3856
3856
|
//#region src/plugin/rules/react-builtins/button-has-type.ts
|
|
3857
3857
|
const MISSING_MESSAGE$2 = "Your users can submit the form by accident because a `<button>` with no `type` defaults to submit.";
|
|
3858
|
-
const INVALID_MESSAGE = "This button
|
|
3858
|
+
const INVALID_MESSAGE = "This button has an invalid `type`, so the browser may treat it like a submit button.";
|
|
3859
3859
|
const resolveSettings$47 = (settings) => {
|
|
3860
3860
|
const reactDoctor = settings?.["react-doctor"];
|
|
3861
3861
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.buttonHasType ?? {} : {};
|
|
@@ -3896,7 +3896,7 @@ const buttonHasType = defineRule({
|
|
|
3896
3896
|
id: "button-has-type",
|
|
3897
3897
|
title: "Button missing explicit type",
|
|
3898
3898
|
severity: "warn",
|
|
3899
|
-
recommendation: "
|
|
3899
|
+
recommendation: "Set an explicit button `type` so plain buttons do not submit forms by accident: `type=\"button\"`, `\"submit\"`, or `\"reset\"`.",
|
|
3900
3900
|
create: (context) => {
|
|
3901
3901
|
const settings = resolveSettings$47(context.settings);
|
|
3902
3902
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -3966,7 +3966,7 @@ const buttonHasType = defineRule({
|
|
|
3966
3966
|
//#endregion
|
|
3967
3967
|
//#region src/plugin/rules/react-builtins/checked-requires-onchange-or-readonly.ts
|
|
3968
3968
|
const MISSING_MESSAGE$1 = "Your users can't toggle this input because `checked` has no `onChange`.";
|
|
3969
|
-
const EXCLUSIVE_MESSAGE = "This input
|
|
3969
|
+
const EXCLUSIVE_MESSAGE = "This input mixes `checked` with `defaultChecked`, so React can't tell whether it is controlled or uncontrolled.";
|
|
3970
3970
|
const resolveSettings$46 = (settings) => {
|
|
3971
3971
|
const reactDoctor = settings?.["react-doctor"];
|
|
3972
3972
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.checkedRequiresOnchangeOrReadonly ?? {} : {};
|
|
@@ -4017,7 +4017,7 @@ const checkedRequiresOnchangeOrReadonly = defineRule({
|
|
|
4017
4017
|
id: "checked-requires-onchange-or-readonly",
|
|
4018
4018
|
title: "Checked input without onChange",
|
|
4019
4019
|
severity: "warn",
|
|
4020
|
-
recommendation: "Add `onChange`
|
|
4020
|
+
recommendation: "Add `onChange`, `readOnly`, or `defaultChecked` so React knows whether the checkbox is editable, display-only, or uncontrolled.",
|
|
4021
4021
|
category: "Correctness",
|
|
4022
4022
|
create: (context) => {
|
|
4023
4023
|
const settings = resolveSettings$46(context.settings);
|
|
@@ -4511,7 +4511,7 @@ const noRedundantPaddingAxes = defineRule({
|
|
|
4511
4511
|
severity: "warn",
|
|
4512
4512
|
defaultEnabled: false,
|
|
4513
4513
|
category: "Architecture",
|
|
4514
|
-
recommendation: "Collapse
|
|
4514
|
+
recommendation: "Collapse matching padding axes to `p-N` so duplicated classes do not make spacing harder to scan; keep split axes only when breakpoints differ.",
|
|
4515
4515
|
create: (context) => ({ JSXAttribute(jsxAttribute) {
|
|
4516
4516
|
if (!isNodeOfType(jsxAttribute.name, "JSXIdentifier") || jsxAttribute.name.name !== "className") return;
|
|
4517
4517
|
const classNameLiteral = getClassNameLiteral(jsxAttribute);
|
|
@@ -4521,7 +4521,7 @@ const noRedundantPaddingAxes = defineRule({
|
|
|
4521
4521
|
if (matchedPairs.length === 0) return;
|
|
4522
4522
|
for (const matchedPair of matchedPairs) context.report({
|
|
4523
4523
|
node: jsxAttribute,
|
|
4524
|
-
message: `px-${matchedPair.value}
|
|
4524
|
+
message: `px-${matchedPair.value} and py-${matchedPair.value} duplicate p-${matchedPair.value}, so the class list is noisier without changing spacing.`
|
|
4525
4525
|
});
|
|
4526
4526
|
} })
|
|
4527
4527
|
});
|
|
@@ -4535,7 +4535,7 @@ const noRedundantSizeAxes = defineRule({
|
|
|
4535
4535
|
severity: "warn",
|
|
4536
4536
|
defaultEnabled: false,
|
|
4537
4537
|
category: "Architecture",
|
|
4538
|
-
recommendation: "Collapse
|
|
4538
|
+
recommendation: "Collapse matching width and height to `size-N` so duplicated classes do not make layout harder to scan.",
|
|
4539
4539
|
create: (context) => ({ JSXAttribute(jsxAttribute) {
|
|
4540
4540
|
if (!isNodeOfType(jsxAttribute.name, "JSXIdentifier") || jsxAttribute.name.name !== "className") return;
|
|
4541
4541
|
const classNameLiteral = getClassNameLiteral(jsxAttribute);
|
|
@@ -4545,7 +4545,7 @@ const noRedundantSizeAxes = defineRule({
|
|
|
4545
4545
|
if (matchedPairs.length === 0) return;
|
|
4546
4546
|
for (const matchedPair of matchedPairs) context.report({
|
|
4547
4547
|
node: jsxAttribute,
|
|
4548
|
-
message: `w-${matchedPair.value}
|
|
4548
|
+
message: `w-${matchedPair.value} and h-${matchedPair.value} duplicate size-${matchedPair.value}, so the class list is noisier without changing layout.`
|
|
4549
4549
|
});
|
|
4550
4550
|
} })
|
|
4551
4551
|
});
|
|
@@ -4580,7 +4580,7 @@ const noSpaceOnFlexChildren = defineRule({
|
|
|
4580
4580
|
const spaceValue = spaceMatch[2];
|
|
4581
4581
|
context.report({
|
|
4582
4582
|
node: jsxAttribute,
|
|
4583
|
-
message: `space-${spaceAxis}-${spaceValue} on a flex or grid parent
|
|
4583
|
+
message: `space-${spaceAxis}-${spaceValue} on a flex or grid parent can leave uneven gaps when children hide, wrap, or render in RTL layouts.`
|
|
4584
4584
|
});
|
|
4585
4585
|
} })
|
|
4586
4586
|
});
|
|
@@ -4593,14 +4593,14 @@ const noThreePeriodEllipsis = defineRule({
|
|
|
4593
4593
|
severity: "warn",
|
|
4594
4594
|
defaultEnabled: false,
|
|
4595
4595
|
category: "Architecture",
|
|
4596
|
-
recommendation: "Use the real ellipsis \"…\"
|
|
4596
|
+
recommendation: "Use the real ellipsis character (\"…\") so UI labels look polished and consistent instead of like three separate periods.",
|
|
4597
4597
|
create: (context) => ({ JSXText(jsxTextNode) {
|
|
4598
4598
|
const textValue = typeof jsxTextNode.value === "string" ? jsxTextNode.value : "";
|
|
4599
4599
|
if (!TRAILING_THREE_PERIOD_ELLIPSIS_PATTERN.test(textValue)) return;
|
|
4600
4600
|
if (isInsideExcludedTypographyAncestor(jsxTextNode)) return;
|
|
4601
4601
|
context.report({
|
|
4602
4602
|
node: jsxTextNode,
|
|
4603
|
-
message: "
|
|
4603
|
+
message: "Use the real ellipsis character (\"…\") instead of three period characters."
|
|
4604
4604
|
});
|
|
4605
4605
|
} })
|
|
4606
4606
|
});
|
|
@@ -4662,7 +4662,7 @@ const noVagueButtonLabel = defineRule({
|
|
|
4662
4662
|
if (!VAGUE_BUTTON_LABELS.has(normalizedLabel)) return;
|
|
4663
4663
|
context.report({
|
|
4664
4664
|
node: jsxElementNode.openingElement ?? jsxElementNode,
|
|
4665
|
-
message: `Screen reader
|
|
4665
|
+
message: `Screen reader users may not know what "${labelText}" does. Use a specific action label.`
|
|
4666
4666
|
});
|
|
4667
4667
|
} })
|
|
4668
4668
|
});
|
|
@@ -5248,10 +5248,10 @@ const effectNeedsCleanup = defineRule({
|
|
|
5248
5248
|
if (usages.length === 0) return;
|
|
5249
5249
|
if (effectHasCleanupReturn(callback, usages)) return;
|
|
5250
5250
|
const firstUsage = usages[0];
|
|
5251
|
-
const
|
|
5251
|
+
const resourceKind = firstUsage.kind === "timer" ? "timer" : "subscription";
|
|
5252
5252
|
context.report({
|
|
5253
5253
|
node,
|
|
5254
|
-
message: `\`${firstUsage.resourceName}
|
|
5254
|
+
message: `\`${firstUsage.resourceName}\` creates a ${resourceKind} in useEffect without returning cleanup. Return a cleanup function so it does not leak after unmount.`
|
|
5255
5255
|
});
|
|
5256
5256
|
} })
|
|
5257
5257
|
});
|
|
@@ -5899,21 +5899,21 @@ const isOutsideAllFunctions = (symbol) => {
|
|
|
5899
5899
|
//#region src/plugin/rules/react-builtins/exhaustive-deps-messages.ts
|
|
5900
5900
|
const buildMissingDepMessage = (hookName, depName) => `\`${hookName}\` can run with a stale \`${depName}\` & show your users old data.`;
|
|
5901
5901
|
const buildUnnecessaryDepMessage = (hookName, depName) => `\`${hookName}\` re-runs whenever \`${depName}\` changes even though it never uses it.`;
|
|
5902
|
-
const buildDuplicateDepMessage = (hookName, depName) => `\`${hookName}\` lists \`${depName}\` twice
|
|
5903
|
-
const buildLiteralDepMessage = (hookName) => `A literal in \`${hookName}\`'s dependency array never changes
|
|
5902
|
+
const buildDuplicateDepMessage = (hookName, depName) => `\`${hookName}\` lists \`${depName}\` twice, adding dependency-array noise without changing when it runs.`;
|
|
5903
|
+
const buildLiteralDepMessage = (hookName) => `A literal in \`${hookName}\`'s dependency array never changes, so it adds noise without protecting against stale values.`;
|
|
5904
5904
|
const buildRefCurrentDepMessage = (hookName, depName) => `\`${hookName}\` won't re-run when \`${depName}\` changes, since a ref never triggers a redraw.`;
|
|
5905
|
-
const buildNonArrayDepsMessage = (hookName) => `\`${hookName}\`'s dependencies can't be checked because its second argument isn't an inline array.`;
|
|
5905
|
+
const buildNonArrayDepsMessage = (hookName) => `\`${hookName}\`'s dependencies can't be checked because its second argument isn't an inline array, so stale values can slip through.`;
|
|
5906
5906
|
const buildMissingDepArrayMessage = (hookName) => `\`${hookName}\` re-runs on every render with no dependency array.`;
|
|
5907
5907
|
const buildMissingCallbackMessage = (hookName) => `\`${hookName}\` crashes without a function as its first argument.`;
|
|
5908
|
-
const buildEffectEventDepMessage = () => `A function from \`useEffectEvent\` is stable
|
|
5909
|
-
const buildSpreadDepMessage = (hookName) =>
|
|
5910
|
-
const buildComplexDepMessage = (hookName) =>
|
|
5908
|
+
const buildEffectEventDepMessage = () => `A function from \`useEffectEvent\` is stable, so listing it adds noise and defeats the event/dependency split.`;
|
|
5909
|
+
const buildSpreadDepMessage = (hookName) => `A spread in \`${hookName}\`'s dependency array hides the actual deps, so stale values can slip through.`;
|
|
5910
|
+
const buildComplexDepMessage = (hookName) => `A complex expression in \`${hookName}\`'s dependency array hides the real value, so stale values can slip through.`;
|
|
5911
5911
|
const buildAsyncEffectMessage = (hookName) => `\`${hookName}\` was given an async function, so its cleanup breaks.`;
|
|
5912
|
-
const buildUnknownCallbackMessage = (hookName) => `\`${hookName}\`'s dependencies can't be checked
|
|
5912
|
+
const buildUnknownCallbackMessage = (hookName) => `\`${hookName}\`'s callback is defined elsewhere, so dependencies can't be checked and stale values can slip through.`;
|
|
5913
5913
|
const buildUnstableDepMessage = (hookName, depName) => `\`${depName}\` is rebuilt every render, so \`${hookName}\` runs every time.`;
|
|
5914
5914
|
const buildSetStateWithoutDepsMessage = (hookName, setterName) => `\`${hookName}\` calls \`${setterName}\` with no dependency array, so it can loop forever & freeze the component.`;
|
|
5915
5915
|
const buildRefCleanupMessage = (depName) => `Your cleanup may read the wrong node since the ref \`${depName}\` can change before it runs.`;
|
|
5916
|
-
const buildAssignmentMessage = (name) => `Assigning to \`${name}\` inside a hook is thrown away after each render.`;
|
|
5916
|
+
const buildAssignmentMessage = (name) => `Assigning to \`${name}\` inside a hook is thrown away after each render, so the next render reads the old value.`;
|
|
5917
5917
|
//#endregion
|
|
5918
5918
|
//#region src/plugin/rules/react-builtins/exhaustive-deps-settings.ts
|
|
5919
5919
|
const resolveExhaustiveDepsSettings = (settings) => {
|
|
@@ -6816,13 +6816,13 @@ const flattenJsxName = (name) => {
|
|
|
6816
6816
|
return "";
|
|
6817
6817
|
};
|
|
6818
6818
|
const isSupportedJsxName = (name) => isNodeOfType(name, "JSXIdentifier") || isNodeOfType(name, "JSXMemberExpression");
|
|
6819
|
-
const buildMessage$24 = (propName, message) => message ?? `Your project blocks the \`${propName}\` prop on this component.`;
|
|
6819
|
+
const buildMessage$24 = (propName, message) => message ?? `Your project blocks the \`${propName}\` prop on this component, so this bypasses the component API contract.`;
|
|
6820
6820
|
const forbidComponentProps = defineRule({
|
|
6821
6821
|
id: "forbid-component-props",
|
|
6822
|
-
title: "
|
|
6822
|
+
title: "Blocked component prop bypasses API contract",
|
|
6823
6823
|
severity: "warn",
|
|
6824
6824
|
defaultEnabled: false,
|
|
6825
|
-
recommendation: "
|
|
6825
|
+
recommendation: "Configure blocked component props so callers cannot bypass the component API contract.",
|
|
6826
6826
|
category: "Architecture",
|
|
6827
6827
|
create: (context) => {
|
|
6828
6828
|
const entries = resolveSettings$43(context.settings).forbid.map(normalizeEntry);
|
|
@@ -6853,7 +6853,7 @@ const forbidComponentProps = defineRule({
|
|
|
6853
6853
|
});
|
|
6854
6854
|
//#endregion
|
|
6855
6855
|
//#region src/plugin/rules/react-builtins/forbid-dom-props.ts
|
|
6856
|
-
const buildMessage$23 = (propName, customMessage) => customMessage ?? `Your project blocks the \`${propName}\` prop on plain HTML tags.`;
|
|
6856
|
+
const buildMessage$23 = (propName, customMessage) => customMessage ?? `Your project blocks the \`${propName}\` prop on plain HTML tags, so this bypasses the agreed DOM API contract.`;
|
|
6857
6857
|
const resolveSettings$42 = (settings) => {
|
|
6858
6858
|
const reactDoctor = settings?.["react-doctor"];
|
|
6859
6859
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.forbidDomProps ?? {} : {};
|
|
@@ -6871,9 +6871,9 @@ const resolveSettings$42 = (settings) => {
|
|
|
6871
6871
|
};
|
|
6872
6872
|
const forbidDomProps = defineRule({
|
|
6873
6873
|
id: "forbid-dom-props",
|
|
6874
|
-
title: "
|
|
6874
|
+
title: "Blocked DOM prop bypasses project contract",
|
|
6875
6875
|
severity: "warn",
|
|
6876
|
-
recommendation: "
|
|
6876
|
+
recommendation: "Configure blocked DOM props so plain HTML tags stay on the agreed DOM API surface.",
|
|
6877
6877
|
category: "Architecture",
|
|
6878
6878
|
create: (context) => {
|
|
6879
6879
|
const forbidMap = resolveSettings$42(context.settings);
|
|
@@ -6934,7 +6934,7 @@ const isReactFunctionCall = (node, expectedCall) => {
|
|
|
6934
6934
|
};
|
|
6935
6935
|
//#endregion
|
|
6936
6936
|
//#region src/plugin/rules/react-builtins/forbid-elements.ts
|
|
6937
|
-
const buildMessage$22 = (element, customHelp) => customHelp ? `Your project blocks \`<${element}>\` here. ${customHelp}` : `Your project blocks \`<${element}>\` here.`;
|
|
6937
|
+
const buildMessage$22 = (element, customHelp) => customHelp ? `Your project blocks \`<${element}>\` here. ${customHelp}` : `Your project blocks \`<${element}>\` here, so code stays on the approved UI surface.`;
|
|
6938
6938
|
const resolveSettings$41 = (settings) => {
|
|
6939
6939
|
const reactDoctor = settings?.["react-doctor"];
|
|
6940
6940
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.forbidElements ?? {} : {};
|
|
@@ -6946,9 +6946,9 @@ const resolveSettings$41 = (settings) => {
|
|
|
6946
6946
|
const flattenMemberName$1 = flattenCalleeName;
|
|
6947
6947
|
const forbidElements = defineRule({
|
|
6948
6948
|
id: "forbid-elements",
|
|
6949
|
-
title: "
|
|
6949
|
+
title: "Blocked element bypasses approved UI primitives",
|
|
6950
6950
|
severity: "warn",
|
|
6951
|
-
recommendation: "
|
|
6951
|
+
recommendation: "Configure blocked elements so code stays on the approved UI primitives.",
|
|
6952
6952
|
category: "Architecture",
|
|
6953
6953
|
create: (context) => {
|
|
6954
6954
|
const forbidMap = resolveSettings$41(context.settings);
|
|
@@ -6992,7 +6992,7 @@ const forwardRefUsesRef = defineRule({
|
|
|
6992
6992
|
id: "forward-ref-uses-ref",
|
|
6993
6993
|
title: "forwardRef without ref parameter",
|
|
6994
6994
|
severity: "warn",
|
|
6995
|
-
recommendation: "
|
|
6995
|
+
recommendation: "Accept the `ref` parameter or drop `forwardRef` so parents are not promised a ref that never reaches the node.",
|
|
6996
6996
|
category: "Architecture",
|
|
6997
6997
|
create: (context) => ({ CallExpression(node) {
|
|
6998
6998
|
if (getCalleeName$1(node) !== "forwardRef") return;
|
|
@@ -7053,8 +7053,8 @@ const headingHasContent = defineRule({
|
|
|
7053
7053
|
});
|
|
7054
7054
|
//#endregion
|
|
7055
7055
|
//#region src/plugin/rules/react-builtins/hook-use-state.ts
|
|
7056
|
-
const REQUIRE_DESTRUCTURE_MESSAGE = "
|
|
7057
|
-
const NAMING_CONVENTION_MESSAGE = "
|
|
7056
|
+
const REQUIRE_DESTRUCTURE_MESSAGE = "`useState` should be destructured as `[value, setValue]` so readers can see the state value and setter together.";
|
|
7057
|
+
const NAMING_CONVENTION_MESSAGE = "This `useState` setter does not match its value name, so updates are harder to trace.";
|
|
7058
7058
|
const resolveSettings$39 = (settings) => {
|
|
7059
7059
|
const reactDoctor = settings?.["react-doctor"];
|
|
7060
7060
|
return { allowDestructuredState: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.hookUseState ?? {} : {}).allowDestructuredState ?? false };
|
|
@@ -7079,7 +7079,7 @@ const hookUseState = defineRule({
|
|
|
7079
7079
|
title: "useState not destructured",
|
|
7080
7080
|
severity: "warn",
|
|
7081
7081
|
defaultEnabled: false,
|
|
7082
|
-
recommendation: "Destructure useState as `const [thing, setThing] = useState(…)
|
|
7082
|
+
recommendation: "Destructure `useState` as `const [thing, setThing] = useState(…)` so state reads and writes stay visible together.",
|
|
7083
7083
|
category: "Architecture",
|
|
7084
7084
|
create: (context) => {
|
|
7085
7085
|
const { allowDestructuredState } = resolveSettings$39(context.settings);
|
|
@@ -7157,7 +7157,7 @@ const HOOKS_WITH_DEP_ARRAY = new Set([
|
|
|
7157
7157
|
"useMemo",
|
|
7158
7158
|
"useImperativeHandle"
|
|
7159
7159
|
]);
|
|
7160
|
-
const NAN_MESSAGE = "`NaN` in a dependency array
|
|
7160
|
+
const NAN_MESSAGE = "`NaN` in a dependency array never compares as changed with `Object.is`, so normalize the value before passing it as a dependency.";
|
|
7161
7161
|
const isNanLiteral = (node) => {
|
|
7162
7162
|
if (isNodeOfType(node, "Identifier") && node.name === "NaN") return true;
|
|
7163
7163
|
if (isNodeOfType(node, "MemberExpression") && !node.computed && isNodeOfType(node.object, "Identifier") && node.object.name === "Number" && isNodeOfType(node.property, "Identifier") && node.property.name === "NaN") return true;
|
|
@@ -7460,7 +7460,7 @@ const htmlNoNestedInteractive = defineRule({
|
|
|
7460
7460
|
});
|
|
7461
7461
|
//#endregion
|
|
7462
7462
|
//#region src/plugin/rules/a11y/iframe-has-title.ts
|
|
7463
|
-
const MESSAGE$43 = "
|
|
7463
|
+
const MESSAGE$43 = "Screen reader users cannot identify this `<iframe>` because it has no title. Add a `title` that describes its content.";
|
|
7464
7464
|
const evaluateTitleValue = (value) => {
|
|
7465
7465
|
if (!value) return "missing";
|
|
7466
7466
|
if (isNodeOfType(value, "Literal")) {
|
|
@@ -7490,7 +7490,7 @@ const iframeHasTitle = defineRule({
|
|
|
7490
7490
|
title: "iframe missing title",
|
|
7491
7491
|
tags: ["react-jsx-only"],
|
|
7492
7492
|
severity: "warn",
|
|
7493
|
-
recommendation: "Add a descriptive `title`
|
|
7493
|
+
recommendation: "Add a descriptive `title` so screen reader users know what the embedded frame contains.",
|
|
7494
7494
|
category: "Accessibility",
|
|
7495
7495
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
7496
7496
|
const tag = getElementType(node, context.settings);
|
|
@@ -7558,7 +7558,7 @@ const iframeMissingSandbox = defineRule({
|
|
|
7558
7558
|
id: "iframe-missing-sandbox",
|
|
7559
7559
|
title: "iframe missing sandbox attribute",
|
|
7560
7560
|
severity: "warn",
|
|
7561
|
-
recommendation: "Add `sandbox=\"\"`
|
|
7561
|
+
recommendation: "Add `sandbox=\"\"` or a curated value so embedded pages cannot get full access to your site by default.",
|
|
7562
7562
|
category: "Security",
|
|
7563
7563
|
create: (context) => ({
|
|
7564
7564
|
JSXOpeningElement(node) {
|
|
@@ -7766,7 +7766,7 @@ const interactiveSupportsFocus = defineRule({
|
|
|
7766
7766
|
title: "Interactive element not focusable",
|
|
7767
7767
|
tags: ["react-jsx-only"],
|
|
7768
7768
|
severity: "warn",
|
|
7769
|
-
recommendation: "Add
|
|
7769
|
+
recommendation: "Add keyboard focus support so users can reach interactive elements without a pointer.",
|
|
7770
7770
|
category: "Accessibility",
|
|
7771
7771
|
create: (context) => {
|
|
7772
7772
|
const settings = resolveSettings$36(context.settings);
|
|
@@ -8584,7 +8584,7 @@ const jsHoistRegexp = defineRule({
|
|
|
8584
8584
|
create: (context) => createLoopAwareVisitors({ NewExpression(node) {
|
|
8585
8585
|
if (isNodeOfType(node.callee, "Identifier") && node.callee.name === "RegExp") context.report({
|
|
8586
8586
|
node,
|
|
8587
|
-
message: "
|
|
8587
|
+
message: "`new RegExp()` rebuilds the pattern on every loop pass. Move it to a constant outside the loop."
|
|
8588
8588
|
});
|
|
8589
8589
|
} })
|
|
8590
8590
|
});
|
|
@@ -8958,7 +8958,7 @@ const jsSetMapLookups = defineRule({
|
|
|
8958
8958
|
if (isIndexedArrayElementWithStringArgument(node.callee.object, node.arguments?.[0])) return;
|
|
8959
8959
|
context.report({
|
|
8960
8960
|
node,
|
|
8961
|
-
message: `This
|
|
8961
|
+
message: `This scales poorly because \`array.${methodName}()\` inside a loop scans the whole list every time. Use a Set for constant-time lookups.`
|
|
8962
8962
|
});
|
|
8963
8963
|
} })
|
|
8964
8964
|
});
|
|
@@ -8969,7 +8969,7 @@ const jsTosortedImmutable = defineRule({
|
|
|
8969
8969
|
title: "Spread copy before sort()",
|
|
8970
8970
|
tags: ["test-noise"],
|
|
8971
8971
|
severity: "warn",
|
|
8972
|
-
disabledBy: ["react-native"],
|
|
8972
|
+
disabledBy: ["react-native", "pre-es2023"],
|
|
8973
8973
|
recommendation: "Use `array.toSorted()` (ES2023) instead of `[...array].sort()` so you sort without copying the array first",
|
|
8974
8974
|
create: (context) => ({ CallExpression(node) {
|
|
8975
8975
|
if (!isMemberProperty(node.callee, "sort")) return;
|
|
@@ -8982,9 +8982,9 @@ const jsTosortedImmutable = defineRule({
|
|
|
8982
8982
|
});
|
|
8983
8983
|
//#endregion
|
|
8984
8984
|
//#region src/plugin/rules/react-builtins/jsx-boolean-value.ts
|
|
8985
|
-
const NEVER_MESSAGE$2 = () =>
|
|
8986
|
-
const ALWAYS_MESSAGE$2 = () =>
|
|
8987
|
-
const FALSE_OMITTED_MESSAGE = (attributeName) => `\`${attributeName}={false}\` does nothing.`;
|
|
8985
|
+
const NEVER_MESSAGE$2 = () => "This boolean prop style disagrees with the project setting, so equivalent true props are harder to scan consistently.";
|
|
8986
|
+
const ALWAYS_MESSAGE$2 = () => "This boolean prop style disagrees with the project setting, so equivalent true props are harder to scan consistently.";
|
|
8987
|
+
const FALSE_OMITTED_MESSAGE = (attributeName) => `\`${attributeName}={false}\` does nothing, so the explicit false value adds noise without changing output.`;
|
|
8988
8988
|
const resolveSettings$35 = (settings) => {
|
|
8989
8989
|
const reactDoctor = settings?.["react-doctor"];
|
|
8990
8990
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.jsxBooleanValue ?? {} : {};
|
|
@@ -9000,7 +9000,7 @@ const jsxBooleanValue = defineRule({
|
|
|
9000
9000
|
title: "Inconsistent boolean prop notation",
|
|
9001
9001
|
severity: "warn",
|
|
9002
9002
|
defaultEnabled: false,
|
|
9003
|
-
recommendation: "
|
|
9003
|
+
recommendation: "Use one boolean-attribute style so equivalent true props scan the same across the codebase.",
|
|
9004
9004
|
category: "Architecture",
|
|
9005
9005
|
create: (context) => {
|
|
9006
9006
|
const settings = resolveSettings$35(context.settings);
|
|
@@ -9054,8 +9054,8 @@ const jsxBooleanValue = defineRule({
|
|
|
9054
9054
|
});
|
|
9055
9055
|
//#endregion
|
|
9056
9056
|
//#region src/plugin/rules/react-builtins/jsx-curly-brace-presence.ts
|
|
9057
|
-
const UNNECESSARY_BRACES_MESSAGE = "These curly braces
|
|
9058
|
-
const REQUIRED_BRACES_MESSAGE = "This value needs
|
|
9057
|
+
const UNNECESSARY_BRACES_MESSAGE = "These curly braces wrap a literal value, so they add JSX noise without changing output.";
|
|
9058
|
+
const REQUIRED_BRACES_MESSAGE = "This JSX value needs `{ }` so React reads it as an expression instead of text.";
|
|
9059
9059
|
const isAllowedMode = (value) => value === "always" || value === "never" || value === "ignore";
|
|
9060
9060
|
const resolveSettings$34 = (settings) => {
|
|
9061
9061
|
const reactDoctor = settings?.["react-doctor"];
|
|
@@ -9150,7 +9150,7 @@ const jsxCurlyBracePresence = defineRule({
|
|
|
9150
9150
|
title: "Unnecessary curly braces in JSX",
|
|
9151
9151
|
severity: "warn",
|
|
9152
9152
|
defaultEnabled: false,
|
|
9153
|
-
recommendation: "
|
|
9153
|
+
recommendation: "Use one JSX literal style so equivalent markup scans the same without extra JSX noise.",
|
|
9154
9154
|
category: "Architecture",
|
|
9155
9155
|
create: (context) => {
|
|
9156
9156
|
const settings = resolveSettings$34(context.settings);
|
|
@@ -9234,8 +9234,8 @@ const containsJsxElement = (root) => {
|
|
|
9234
9234
|
};
|
|
9235
9235
|
//#endregion
|
|
9236
9236
|
//#region src/plugin/rules/react-builtins/jsx-filename-extension.ts
|
|
9237
|
-
const JSX_NOT_ALLOWED = (extension) => `This file
|
|
9238
|
-
const EXTENSION_ONLY_FOR_JSX = (extension) => `\`${extension}\` files are
|
|
9237
|
+
const JSX_NOT_ALLOWED = (extension) => `This file contains JSX but uses a \`${extension}\` name, so the filename no longer signals JSX to readers or tooling conventions.`;
|
|
9238
|
+
const EXTENSION_ONLY_FOR_JSX = (extension) => `\`${extension}\` files are reserved for JSX here, so using that extension without JSX makes file-type conventions less useful.`;
|
|
9239
9239
|
const resolveSettings$33 = (settings) => {
|
|
9240
9240
|
const reactDoctor = settings?.["react-doctor"];
|
|
9241
9241
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.jsxFilenameExtension ?? {} : {};
|
|
@@ -9255,7 +9255,7 @@ const jsxFilenameExtension = defineRule({
|
|
|
9255
9255
|
title: "JSX in disallowed file extension",
|
|
9256
9256
|
severity: "warn",
|
|
9257
9257
|
defaultEnabled: false,
|
|
9258
|
-
recommendation: "Name files with
|
|
9258
|
+
recommendation: "Name JSX files with the configured extension so file names accurately signal which files contain JSX.",
|
|
9259
9259
|
category: "Architecture",
|
|
9260
9260
|
create: (context) => {
|
|
9261
9261
|
const settings = resolveSettings$33(context.settings);
|
|
@@ -9310,8 +9310,8 @@ const isJsxFragmentElement = (node) => {
|
|
|
9310
9310
|
};
|
|
9311
9311
|
//#endregion
|
|
9312
9312
|
//#region src/plugin/rules/react-builtins/jsx-fragments.ts
|
|
9313
|
-
const SYNTAX_MESSAGE = "
|
|
9314
|
-
const ELEMENT_MESSAGE = "
|
|
9313
|
+
const SYNTAX_MESSAGE = "`<React.Fragment>` is used where shorthand fragments are configured, so similar wrappers look different across the codebase.";
|
|
9314
|
+
const ELEMENT_MESSAGE = "Fragment shorthand is used where explicit fragments are configured, so similar wrappers look different across the codebase.";
|
|
9315
9315
|
const resolveSettings$32 = (settings) => {
|
|
9316
9316
|
const reactDoctor = settings?.["react-doctor"];
|
|
9317
9317
|
return { mode: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.jsxFragments ?? {} : {}).mode ?? "syntax" };
|
|
@@ -9321,7 +9321,7 @@ const jsxFragments = defineRule({
|
|
|
9321
9321
|
title: "Inconsistent fragment syntax",
|
|
9322
9322
|
severity: "warn",
|
|
9323
9323
|
defaultEnabled: false,
|
|
9324
|
-
recommendation: "
|
|
9324
|
+
recommendation: "Use one fragment style so identical wrappers do not look different across files.",
|
|
9325
9325
|
category: "Architecture",
|
|
9326
9326
|
create: (context) => {
|
|
9327
9327
|
const { mode } = resolveSettings$32(context.settings);
|
|
@@ -9349,8 +9349,8 @@ const jsxFragments = defineRule({
|
|
|
9349
9349
|
});
|
|
9350
9350
|
//#endregion
|
|
9351
9351
|
//#region src/plugin/rules/react-builtins/jsx-handler-names.ts
|
|
9352
|
-
const buildHandlerNameMessage = (handlerName, propKey) => `The handler "${handlerName}"
|
|
9353
|
-
const buildHandlerPropMessage = (propKey, propValue) => `The prop "${propKey}" passes
|
|
9352
|
+
const buildHandlerNameMessage = (handlerName, propKey) => `The handler "${handlerName}" does not match the "${propKey}" event prop convention, so readers cannot trace event flow quickly.`;
|
|
9353
|
+
const buildHandlerPropMessage = (propKey, propValue) => `The prop "${propKey}" passes handler "${propValue}" but is not named like an event prop, so callers cannot tell it fires an event.`;
|
|
9354
9354
|
const DEFAULT_HANDLER_PREFIX = "handle";
|
|
9355
9355
|
const DEFAULT_HANDLER_PROP_PREFIX = "on";
|
|
9356
9356
|
const splitPrefixes = (prefixes) => prefixes.split("|").map((token) => token.trim()).filter((token) => token.length > 0);
|
|
@@ -9441,7 +9441,7 @@ const jsxHandlerNames = defineRule({
|
|
|
9441
9441
|
title: "Inconsistent event handler names",
|
|
9442
9442
|
severity: "warn",
|
|
9443
9443
|
defaultEnabled: false,
|
|
9444
|
-
recommendation: "Use the `on…` prefix for event-handler props and `handle…` for handlers.",
|
|
9444
|
+
recommendation: "Use the `on…` prefix for event-handler props and `handle…` for handlers so readers can trace event flow.",
|
|
9445
9445
|
category: "Architecture",
|
|
9446
9446
|
create: (context) => {
|
|
9447
9447
|
const settings = resolveSettings$31(context.settings);
|
|
@@ -9675,7 +9675,7 @@ const jsxKey = defineRule({
|
|
|
9675
9675
|
id: "jsx-key",
|
|
9676
9676
|
title: "Missing key in list",
|
|
9677
9677
|
severity: "error",
|
|
9678
|
-
recommendation: "Add a `key
|
|
9678
|
+
recommendation: "Add a stable `key` prop so React can keep list items matched to the right data when the list changes.",
|
|
9679
9679
|
create: (context) => {
|
|
9680
9680
|
const settings = resolveSettings$30(context.settings);
|
|
9681
9681
|
return {
|
|
@@ -9841,7 +9841,7 @@ const jsxNoCommentTextnodes = defineRule({
|
|
|
9841
9841
|
id: "jsx-no-comment-textnodes",
|
|
9842
9842
|
title: "Comment rendered as JSX text",
|
|
9843
9843
|
severity: "warn",
|
|
9844
|
-
recommendation: "Wrap JSX comments in `{/* … */}` so
|
|
9844
|
+
recommendation: "Wrap JSX comments in `{/* … */}` so users do not see comment text rendered as children.",
|
|
9845
9845
|
create: (context) => ({ JSXText(node) {
|
|
9846
9846
|
if (!hasCommentLikePattern(node.value)) return;
|
|
9847
9847
|
if (isInsideLiteralTextTag(node)) return;
|
|
@@ -9948,7 +9948,7 @@ const jsxNoConstructedContextValues = defineRule({
|
|
|
9948
9948
|
tags: ["react-jsx-only"],
|
|
9949
9949
|
severity: "warn",
|
|
9950
9950
|
disabledBy: ["react-compiler"],
|
|
9951
|
-
recommendation: "Wrap the context value in `useMemo
|
|
9951
|
+
recommendation: "Wrap the context value in `useMemo` or move it outside the component so consumers do not redraw every render.",
|
|
9952
9952
|
category: "Performance",
|
|
9953
9953
|
create: (context) => {
|
|
9954
9954
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -9989,7 +9989,7 @@ const jsxNoDuplicateProps = defineRule({
|
|
|
9989
9989
|
id: "jsx-no-duplicate-props",
|
|
9990
9990
|
title: "Duplicate props on element",
|
|
9991
9991
|
severity: "error",
|
|
9992
|
-
recommendation: "Remove or rename one of the duplicate props.",
|
|
9992
|
+
recommendation: "Remove or rename one of the duplicate props so the later value does not silently override the earlier one.",
|
|
9993
9993
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
9994
9994
|
const seenPropNames = /* @__PURE__ */ new Set();
|
|
9995
9995
|
for (const attribute of node.attributes) {
|
|
@@ -10306,7 +10306,7 @@ const jsxNoJsxAsProp = defineRule({
|
|
|
10306
10306
|
tags: ["react-jsx-only"],
|
|
10307
10307
|
severity: "warn",
|
|
10308
10308
|
disabledBy: ["react-compiler"],
|
|
10309
|
-
recommendation: "Move the JSX outside the component
|
|
10309
|
+
recommendation: "Move the JSX outside the component or wrap it in `useMemo` so memoized children do not redraw every render.",
|
|
10310
10310
|
category: "Performance",
|
|
10311
10311
|
create: (context) => {
|
|
10312
10312
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -10678,7 +10678,7 @@ const jsxNoNewArrayAsProp = defineRule({
|
|
|
10678
10678
|
tags: ["react-jsx-only"],
|
|
10679
10679
|
severity: "warn",
|
|
10680
10680
|
disabledBy: ["react-compiler"],
|
|
10681
|
-
recommendation: "Wrap the array in `useMemo
|
|
10681
|
+
recommendation: "Wrap the array in `useMemo` or move it outside the component so memoized children do not redraw every render.",
|
|
10682
10682
|
category: "Performance",
|
|
10683
10683
|
create: (context) => {
|
|
10684
10684
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -11141,7 +11141,7 @@ const jsxNoNewFunctionAsProp = defineRule({
|
|
|
11141
11141
|
tags: ["react-jsx-only"],
|
|
11142
11142
|
severity: "warn",
|
|
11143
11143
|
disabledBy: ["react-compiler"],
|
|
11144
|
-
recommendation: "Wrap the callback in `useCallback
|
|
11144
|
+
recommendation: "Wrap the callback in `useCallback` or move it outside the component so memoized children do not redraw every render.",
|
|
11145
11145
|
category: "Performance",
|
|
11146
11146
|
create: (context) => {
|
|
11147
11147
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -11448,7 +11448,7 @@ const jsxNoNewObjectAsProp = defineRule({
|
|
|
11448
11448
|
tags: ["react-jsx-only"],
|
|
11449
11449
|
severity: "warn",
|
|
11450
11450
|
disabledBy: ["react-compiler"],
|
|
11451
|
-
recommendation: "Wrap the object in `useMemo
|
|
11451
|
+
recommendation: "Wrap the object in `useMemo` or move it outside the component so memoized children do not redraw every render.",
|
|
11452
11452
|
category: "Performance",
|
|
11453
11453
|
create: (context) => {
|
|
11454
11454
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -11508,7 +11508,7 @@ const jsxNoScriptUrl = defineRule({
|
|
|
11508
11508
|
id: "jsx-no-script-url",
|
|
11509
11509
|
title: "javascript: URL in JSX",
|
|
11510
11510
|
severity: "error",
|
|
11511
|
-
recommendation: "
|
|
11511
|
+
recommendation: "Use real event handlers instead of `javascript:` URLs so injected URL text cannot execute as code.",
|
|
11512
11512
|
category: "Security",
|
|
11513
11513
|
create: (context) => {
|
|
11514
11514
|
const options = resolveSettings$28(context.settings);
|
|
@@ -11559,7 +11559,7 @@ const jsxNoUndef = defineRule({
|
|
|
11559
11559
|
id: "jsx-no-undef",
|
|
11560
11560
|
title: "Undefined JSX component",
|
|
11561
11561
|
severity: "error",
|
|
11562
|
-
recommendation: "Import the component or
|
|
11562
|
+
recommendation: "Import the component or fix the typo so React can resolve the JSX identifier at runtime.",
|
|
11563
11563
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
11564
11564
|
const rootIdentifier = getRootIdentifier(node.name);
|
|
11565
11565
|
if (!rootIdentifier) return;
|
|
@@ -11751,7 +11751,7 @@ const jsxPascalCase = defineRule({
|
|
|
11751
11751
|
severity: "warn",
|
|
11752
11752
|
defaultEnabled: false,
|
|
11753
11753
|
tags: ["test-noise"],
|
|
11754
|
-
recommendation: "Rename custom JSX components to PascalCase.",
|
|
11754
|
+
recommendation: "Rename custom JSX components to PascalCase so React treats them as components, not intrinsic DOM tags.",
|
|
11755
11755
|
category: "Architecture",
|
|
11756
11756
|
create: (context) => {
|
|
11757
11757
|
const settings = resolveSettings$26(context.settings);
|
|
@@ -11815,7 +11815,7 @@ const jsxPropsNoSpreadMulti = defineRule({
|
|
|
11815
11815
|
id: "jsx-props-no-spread-multi",
|
|
11816
11816
|
title: "Same prop spread multiple times",
|
|
11817
11817
|
severity: "warn",
|
|
11818
|
-
recommendation: "Spread
|
|
11818
|
+
recommendation: "Spread each value at most once so later props cannot silently override earlier props from the same object.",
|
|
11819
11819
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
11820
11820
|
const seenNames = /* @__PURE__ */ new Map();
|
|
11821
11821
|
const reportedNames = /* @__PURE__ */ new Set();
|
|
@@ -11855,7 +11855,7 @@ const jsxPropsNoSpreading = defineRule({
|
|
|
11855
11855
|
title: "Props spread onto element",
|
|
11856
11856
|
severity: "warn",
|
|
11857
11857
|
defaultEnabled: false,
|
|
11858
|
-
recommendation: "List each prop explicitly so consumers can see
|
|
11858
|
+
recommendation: "List each prop explicitly so consumers can see the component API instead of receiving hidden spread props.",
|
|
11859
11859
|
category: "Architecture",
|
|
11860
11860
|
create: (context) => {
|
|
11861
11861
|
const settings = resolveSettings$25(context.settings);
|
|
@@ -12236,7 +12236,7 @@ const lang = defineRule({
|
|
|
12236
12236
|
title: "Invalid lang attribute value",
|
|
12237
12237
|
tags: ["react-jsx-only"],
|
|
12238
12238
|
severity: "warn",
|
|
12239
|
-
recommendation: "Use a valid language code
|
|
12239
|
+
recommendation: "Use a valid language code like `en` or `en-US` so screen readers choose the right pronunciation rules.",
|
|
12240
12240
|
category: "Accessibility",
|
|
12241
12241
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
12242
12242
|
if (getElementType(node, context.settings) !== "html") return;
|
|
@@ -12263,7 +12263,7 @@ const lang = defineRule({
|
|
|
12263
12263
|
});
|
|
12264
12264
|
//#endregion
|
|
12265
12265
|
//#region src/plugin/rules/a11y/media-has-caption.ts
|
|
12266
|
-
const MESSAGE$32 = "Deaf
|
|
12266
|
+
const MESSAGE$32 = "Deaf and hard-of-hearing users need captions for this media. Add a `<track kind=\"captions\">` inside the `<audio>` or `<video>`.";
|
|
12267
12267
|
const DEFAULT_AUDIO = ["audio"];
|
|
12268
12268
|
const DEFAULT_VIDEO = ["video"];
|
|
12269
12269
|
const DEFAULT_TRACK = ["track"];
|
|
@@ -12505,11 +12505,11 @@ const hasJsxAttribute = (attributes, attributeName) => Boolean(findJsxAttribute(
|
|
|
12505
12505
|
//#region src/plugin/rules/nextjs/nextjs-image-missing-sizes.ts
|
|
12506
12506
|
const nextjsImageMissingSizes = defineRule({
|
|
12507
12507
|
id: "nextjs-image-missing-sizes",
|
|
12508
|
-
title: "
|
|
12508
|
+
title: "next/image fill image is missing sizes",
|
|
12509
12509
|
tags: ["test-noise"],
|
|
12510
12510
|
requires: ["nextjs"],
|
|
12511
12511
|
severity: "warn",
|
|
12512
|
-
recommendation: "Add sizes
|
|
12512
|
+
recommendation: "Add `sizes` matching your layout so `next/image` does not assume the largest candidate and make users download oversized images.",
|
|
12513
12513
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
12514
12514
|
if (!isNodeOfType(node.name, "JSXIdentifier") || node.name.name !== "Image") return;
|
|
12515
12515
|
const attributes = node.attributes ?? [];
|
|
@@ -12545,11 +12545,11 @@ const nextjsInlineScriptMissingId = defineRule({
|
|
|
12545
12545
|
//#region src/plugin/rules/nextjs/nextjs-missing-metadata.ts
|
|
12546
12546
|
const nextjsMissingMetadata = defineRule({
|
|
12547
12547
|
id: "nextjs-missing-metadata",
|
|
12548
|
-
title: "Page missing metadata",
|
|
12548
|
+
title: "Page missing metadata for search previews",
|
|
12549
12549
|
tags: ["test-noise"],
|
|
12550
12550
|
requires: ["nextjs"],
|
|
12551
12551
|
severity: "warn",
|
|
12552
|
-
recommendation: "Add
|
|
12552
|
+
recommendation: "Add metadata or `generateMetadata()` so search engines and social previews get a title and description.",
|
|
12553
12553
|
create: (context) => ({ Program(programNode) {
|
|
12554
12554
|
const filename = normalizeFilename$1(context.filename ?? "");
|
|
12555
12555
|
if (!PAGE_FILE_PATTERN.test(filename)) return;
|
|
@@ -12562,7 +12562,7 @@ const nextjsMissingMetadata = defineRule({
|
|
|
12562
12562
|
return false;
|
|
12563
12563
|
})) context.report({
|
|
12564
12564
|
node: programNode,
|
|
12565
|
-
message: "This page has no metadata, so search engines
|
|
12565
|
+
message: "This page has no metadata, so search engines and social previews get no title or description."
|
|
12566
12566
|
});
|
|
12567
12567
|
} })
|
|
12568
12568
|
});
|
|
@@ -12570,7 +12570,7 @@ const nextjsMissingMetadata = defineRule({
|
|
|
12570
12570
|
//#region src/plugin/rules/nextjs/nextjs-no-a-element.ts
|
|
12571
12571
|
const nextjsNoAElement = defineRule({
|
|
12572
12572
|
id: "nextjs-no-a-element",
|
|
12573
|
-
title: "Plain anchor
|
|
12573
|
+
title: "Plain anchor reloads internal Next.js links",
|
|
12574
12574
|
tags: ["test-noise"],
|
|
12575
12575
|
requires: ["nextjs"],
|
|
12576
12576
|
severity: "warn",
|
|
@@ -12584,7 +12584,7 @@ const nextjsNoAElement = defineRule({
|
|
|
12584
12584
|
else if (isNodeOfType(hrefAttribute.value, "JSXExpressionContainer") && isNodeOfType(hrefAttribute.value.expression, "Literal")) hrefValue = hrefAttribute.value.expression.value;
|
|
12585
12585
|
if (typeof hrefValue === "string" && hrefValue.startsWith("/")) context.report({
|
|
12586
12586
|
node,
|
|
12587
|
-
message: "Plain <a> reloads the whole page
|
|
12587
|
+
message: "Plain <a> reloads the whole page for internal links, so Next.js loses client-side navigation and prefetching."
|
|
12588
12588
|
});
|
|
12589
12589
|
} })
|
|
12590
12590
|
});
|
|
@@ -12669,11 +12669,11 @@ const nextjsNoClientSideRedirect = defineRule({
|
|
|
12669
12669
|
//#region src/plugin/rules/nextjs/nextjs-no-css-link.ts
|
|
12670
12670
|
const nextjsNoCssLink = defineRule({
|
|
12671
12671
|
id: "nextjs-no-css-link",
|
|
12672
|
-
title: "
|
|
12672
|
+
title: "Linked stylesheet bypasses Next.js CSS optimization",
|
|
12673
12673
|
tags: ["test-noise"],
|
|
12674
12674
|
requires: ["nextjs"],
|
|
12675
12675
|
severity: "warn",
|
|
12676
|
-
recommendation: "Import CSS directly
|
|
12676
|
+
recommendation: "Import CSS directly or use CSS Modules so Next.js can bundle, order, and optimize the stylesheet.",
|
|
12677
12677
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
12678
12678
|
if (!isNodeOfType(node.name, "JSXIdentifier") || node.name.name !== "link") return;
|
|
12679
12679
|
const attributes = node.attributes ?? [];
|
|
@@ -12686,7 +12686,7 @@ const nextjsNoCssLink = defineRule({
|
|
|
12686
12686
|
if (typeof hrefValue === "string" && GOOGLE_FONTS_PATTERN.test(hrefValue)) return;
|
|
12687
12687
|
context.report({
|
|
12688
12688
|
node,
|
|
12689
|
-
message: "This <link rel=\"stylesheet\"> loads unbundled
|
|
12689
|
+
message: "This <link rel=\"stylesheet\"> bypasses Next.js CSS handling, so the CSS loads unbundled and unoptimized."
|
|
12690
12690
|
});
|
|
12691
12691
|
} })
|
|
12692
12692
|
});
|
|
@@ -12710,7 +12710,7 @@ const nextjsNoDefaultExportInRouteHandler = defineRule({
|
|
|
12710
12710
|
tags: ["test-noise"],
|
|
12711
12711
|
requires: ["nextjs"],
|
|
12712
12712
|
severity: "error",
|
|
12713
|
-
recommendation: "Replace `export default` with named HTTP method exports
|
|
12713
|
+
recommendation: "Replace `export default` with named HTTP method exports because Next.js ignores default exports in `route.ts`.",
|
|
12714
12714
|
create: (context) => {
|
|
12715
12715
|
let isAppRouteHandler = false;
|
|
12716
12716
|
let programNode = null;
|
|
@@ -12797,11 +12797,11 @@ const nextjsNoFontLink = defineRule({
|
|
|
12797
12797
|
//#region src/plugin/rules/nextjs/nextjs-no-google-analytics-script.ts
|
|
12798
12798
|
const nextjsNoGoogleAnalyticsScript = defineRule({
|
|
12799
12799
|
id: "nextjs-no-google-analytics-script",
|
|
12800
|
-
title: "Manual Google Analytics script",
|
|
12800
|
+
title: "Manual Google Analytics script blocks optimized loading",
|
|
12801
12801
|
tags: ["test-noise"],
|
|
12802
12802
|
requires: ["nextjs"],
|
|
12803
12803
|
severity: "warn",
|
|
12804
|
-
recommendation: "Use `import { GoogleAnalytics } from '@next/third-parties/google'` for automatic optimization
|
|
12804
|
+
recommendation: "Use `import { GoogleAnalytics } from '@next/third-parties/google'` for automatic optimization and smaller bundles.",
|
|
12805
12805
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
12806
12806
|
if (!isNodeOfType(node.name, "JSXIdentifier")) return;
|
|
12807
12807
|
if (node.name.name !== "script" && node.name.name !== "Script") return;
|
|
@@ -12810,7 +12810,7 @@ const nextjsNoGoogleAnalyticsScript = defineRule({
|
|
|
12810
12810
|
const srcValue = isNodeOfType(srcAttribute.value, "Literal") ? srcAttribute.value.value : null;
|
|
12811
12811
|
if (typeof srcValue === "string" && GOOGLE_ANALYTICS_SCRIPT_PATTERN.test(srcValue)) context.report({
|
|
12812
12812
|
node,
|
|
12813
|
-
message: "Manual Google Analytics
|
|
12813
|
+
message: "Manual Google Analytics scripts block rendering without Next.js' optimized loading strategy."
|
|
12814
12814
|
});
|
|
12815
12815
|
} })
|
|
12816
12816
|
});
|
|
@@ -12822,7 +12822,7 @@ const nextjsNoHeadImport = defineRule({
|
|
|
12822
12822
|
tags: ["test-noise"],
|
|
12823
12823
|
requires: ["nextjs"],
|
|
12824
12824
|
severity: "error",
|
|
12825
|
-
recommendation: "Use the Metadata API
|
|
12825
|
+
recommendation: "Use the Metadata API because `next/head` is ignored in the App Router and meta tags will not render.",
|
|
12826
12826
|
create: (context) => ({ ImportDeclaration(node) {
|
|
12827
12827
|
if (node.source?.value !== "next/head") return;
|
|
12828
12828
|
const filename = normalizeFilename$1(context.filename ?? "");
|
|
@@ -12837,18 +12837,18 @@ const nextjsNoHeadImport = defineRule({
|
|
|
12837
12837
|
//#region src/plugin/rules/nextjs/nextjs-no-img-element.ts
|
|
12838
12838
|
const nextjsNoImgElement = defineRule({
|
|
12839
12839
|
id: "nextjs-no-img-element",
|
|
12840
|
-
title: "Plain img
|
|
12840
|
+
title: "Plain img ships unoptimized images",
|
|
12841
12841
|
tags: ["test-noise"],
|
|
12842
12842
|
requires: ["nextjs"],
|
|
12843
12843
|
severity: "warn",
|
|
12844
|
-
recommendation: "`
|
|
12844
|
+
recommendation: "Use `next/image` so users get optimized formats, responsive srcsets, and lazy loading instead of oversized image downloads.",
|
|
12845
12845
|
create: (context) => {
|
|
12846
12846
|
if (isGeneratedImageRenderContext(context)) return {};
|
|
12847
12847
|
return { JSXOpeningElement(node) {
|
|
12848
12848
|
if (isGeneratedImageRenderContext(context, node)) return;
|
|
12849
12849
|
if (isNodeOfType(node.name, "JSXIdentifier") && node.name.name === "img") context.report({
|
|
12850
12850
|
node,
|
|
12851
|
-
message: "Plain <img> ships unoptimized, oversized images
|
|
12851
|
+
message: "Plain <img> ships unoptimized, oversized images."
|
|
12852
12852
|
});
|
|
12853
12853
|
} };
|
|
12854
12854
|
}
|
|
@@ -12857,11 +12857,11 @@ const nextjsNoImgElement = defineRule({
|
|
|
12857
12857
|
//#region src/plugin/rules/nextjs/nextjs-no-native-script.ts
|
|
12858
12858
|
const nextjsNoNativeScript = defineRule({
|
|
12859
12859
|
id: "nextjs-no-native-script",
|
|
12860
|
-
title: "Plain script
|
|
12860
|
+
title: "Plain script can block Next.js rendering",
|
|
12861
12861
|
tags: ["test-noise"],
|
|
12862
12862
|
requires: ["nextjs"],
|
|
12863
12863
|
severity: "warn",
|
|
12864
|
-
recommendation: "`
|
|
12864
|
+
recommendation: "Use `next/script` with `strategy=\"afterInteractive\"` or `\"lazyOnload\"` so third-party scripts do not block rendering.",
|
|
12865
12865
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
12866
12866
|
if (!isNodeOfType(node.name, "JSXIdentifier") || node.name.name !== "script") return;
|
|
12867
12867
|
const typeAttribute = findJsxAttribute(node.attributes ?? [], "type");
|
|
@@ -12869,7 +12869,7 @@ const nextjsNoNativeScript = defineRule({
|
|
|
12869
12869
|
if (typeof typeValue === "string" && !EXECUTABLE_SCRIPT_TYPES.has(typeValue)) return;
|
|
12870
12870
|
context.report({
|
|
12871
12871
|
node,
|
|
12872
|
-
message: "Plain <script>
|
|
12872
|
+
message: "Plain <script> has no Next.js loading strategy, so it can block rendering."
|
|
12873
12873
|
});
|
|
12874
12874
|
} })
|
|
12875
12875
|
});
|
|
@@ -12902,7 +12902,7 @@ const nextjsNoRedirectInTryCatch = defineRule({
|
|
|
12902
12902
|
tags: ["test-noise"],
|
|
12903
12903
|
requires: ["nextjs"],
|
|
12904
12904
|
severity: "warn",
|
|
12905
|
-
recommendation: "Move
|
|
12905
|
+
recommendation: "Move `redirect()` or `notFound()` outside the try block, or rethrow in `catch`, because these APIs throw control-flow errors that catch blocks swallow.",
|
|
12906
12906
|
create: (context) => {
|
|
12907
12907
|
let tryCatchDepth = 0;
|
|
12908
12908
|
return {
|
|
@@ -14053,7 +14053,7 @@ const nextjsNoUseSearchParamsWithoutSuspense = defineRule({
|
|
|
14053
14053
|
tags: ["test-noise"],
|
|
14054
14054
|
requires: ["nextjs"],
|
|
14055
14055
|
severity: "warn",
|
|
14056
|
-
recommendation: "Wrap the component using useSearchParams
|
|
14056
|
+
recommendation: "Wrap the component using `useSearchParams` in `<Suspense>` so the rest of the page can stay statically rendered.",
|
|
14057
14057
|
create: (context) => {
|
|
14058
14058
|
let isPageOrLayoutFile = false;
|
|
14059
14059
|
let hasAncestorLayoutSuspense = false;
|
|
@@ -14091,7 +14091,7 @@ const nextjsNoUseSearchParamsWithoutSuspense = defineRule({
|
|
|
14091
14091
|
if (!componentBody || !astContainsUseSearchParams(componentBody)) return;
|
|
14092
14092
|
context.report({
|
|
14093
14093
|
node,
|
|
14094
|
-
message: `<${node.name.name}> uses useSearchParams()
|
|
14094
|
+
message: `<${node.name.name}> uses useSearchParams() outside <Suspense>, so this page falls back to client-side rendering.`
|
|
14095
14095
|
});
|
|
14096
14096
|
}
|
|
14097
14097
|
};
|
|
@@ -14105,7 +14105,7 @@ const nextjsNoVercelOgImport = defineRule({
|
|
|
14105
14105
|
tags: ["test-noise"],
|
|
14106
14106
|
requires: ["nextjs"],
|
|
14107
14107
|
severity: "warn",
|
|
14108
|
-
recommendation: "Use `import { ImageResponse } from \"next/og\"
|
|
14108
|
+
recommendation: "Use `import { ImageResponse } from \"next/og\"`; do not import `@vercel/og` directly because Next.js already bundles it.",
|
|
14109
14109
|
create: (context) => ({ ImportDeclaration(node) {
|
|
14110
14110
|
if (node.source?.value !== "@vercel/og") return;
|
|
14111
14111
|
context.report({
|
|
@@ -14619,7 +14619,7 @@ const noAdjustStateOnPropChange = defineRule({
|
|
|
14619
14619
|
if (getArgsUpstreamRefs(analysis, ref).some((argRef) => isProp(analysis, argRef))) continue;
|
|
14620
14620
|
context.report({
|
|
14621
14621
|
node: callExpr,
|
|
14622
|
-
message: "
|
|
14622
|
+
message: "This effect adjusts state after a prop changes, so users briefly see the stale value."
|
|
14623
14623
|
});
|
|
14624
14624
|
}
|
|
14625
14625
|
} })
|
|
@@ -14632,7 +14632,7 @@ const noAriaHiddenOnFocusable = defineRule({
|
|
|
14632
14632
|
title: "aria-hidden on focusable element",
|
|
14633
14633
|
tags: ["react-jsx-only"],
|
|
14634
14634
|
severity: "warn",
|
|
14635
|
-
recommendation: "Remove `aria-hidden` from focusable elements, or stop them being focusable.",
|
|
14635
|
+
recommendation: "Remove `aria-hidden` from focusable elements, or stop them being focusable, so keyboard users do not land on content screen readers hide.",
|
|
14636
14636
|
category: "Accessibility",
|
|
14637
14637
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
14638
14638
|
const ariaHidden = hasJsxPropIgnoreCase(node.attributes, "aria-hidden");
|
|
@@ -15176,7 +15176,7 @@ const noArrayIndexKey = defineRule({
|
|
|
15176
15176
|
title: "Array index used as a key",
|
|
15177
15177
|
severity: "warn",
|
|
15178
15178
|
defaultEnabled: false,
|
|
15179
|
-
recommendation: "Use a stable `key` from your data
|
|
15179
|
+
recommendation: "Use a stable `key` from your data so reordered items keep the right state and DOM.",
|
|
15180
15180
|
category: "Performance",
|
|
15181
15181
|
create: (context) => ({
|
|
15182
15182
|
JSXOpeningElement(node) {
|
|
@@ -15253,7 +15253,7 @@ const noArrayIndexKey = defineRule({
|
|
|
15253
15253
|
});
|
|
15254
15254
|
//#endregion
|
|
15255
15255
|
//#region src/plugin/rules/a11y/no-autofocus.ts
|
|
15256
|
-
const MESSAGE$28 = "
|
|
15256
|
+
const MESSAGE$28 = "`autoFocus` moves focus on load, which can disrupt screen reader and keyboard users. Remove it and let users choose where to focus.";
|
|
15257
15257
|
const resolveSettings$21 = (settings) => {
|
|
15258
15258
|
const reactDoctor = settings?.["react-doctor"];
|
|
15259
15259
|
return { ignoreNonDOM: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noAutofocus ?? {} : {}).ignoreNonDOM ?? true };
|
|
@@ -15487,7 +15487,7 @@ const noCascadingSetState = defineRule({
|
|
|
15487
15487
|
title: "Multiple setState calls in one effect",
|
|
15488
15488
|
severity: "warn",
|
|
15489
15489
|
tags: ["test-noise"],
|
|
15490
|
-
recommendation: "Combine
|
|
15490
|
+
recommendation: "Combine related updates in `useReducer` so one effect does not redraw the screen once per `setState` call.",
|
|
15491
15491
|
create: (context) => ({ CallExpression(node) {
|
|
15492
15492
|
if (!isHookCall$1(node, EFFECT_HOOK_NAMES$1)) return;
|
|
15493
15493
|
if (isInitOnlyEffect(node)) return;
|
|
@@ -15533,12 +15533,12 @@ const noChainStateUpdates = defineRule({
|
|
|
15533
15533
|
});
|
|
15534
15534
|
//#endregion
|
|
15535
15535
|
//#region src/plugin/rules/react-builtins/no-children-prop.ts
|
|
15536
|
-
const MESSAGE$27 = "
|
|
15536
|
+
const MESSAGE$27 = "A `children` prop can override or hide nested children, so the component may render different content than the JSX shows.";
|
|
15537
15537
|
const noChildrenProp = defineRule({
|
|
15538
15538
|
id: "no-children-prop",
|
|
15539
15539
|
title: "Children passed as a prop",
|
|
15540
15540
|
severity: "warn",
|
|
15541
|
-
recommendation: "Nest children between the tags
|
|
15541
|
+
recommendation: "Nest children between the tags so the rendered content is visible in JSX and cannot be hidden inside a props object.",
|
|
15542
15542
|
create: (context) => ({
|
|
15543
15543
|
JSXAttribute(node) {
|
|
15544
15544
|
if (!isNodeOfType(node.name, "JSXIdentifier")) return;
|
|
@@ -15566,13 +15566,13 @@ const noChildrenProp = defineRule({
|
|
|
15566
15566
|
});
|
|
15567
15567
|
//#endregion
|
|
15568
15568
|
//#region src/plugin/rules/react-builtins/no-clone-element.ts
|
|
15569
|
-
const MESSAGE$26 = "`React.cloneElement`
|
|
15569
|
+
const MESSAGE$26 = "`React.cloneElement` couples the parent to the child's prop shape, so child prop changes can silently break injected behavior.";
|
|
15570
15570
|
const noCloneElement = defineRule({
|
|
15571
15571
|
id: "no-clone-element",
|
|
15572
|
-
title: "
|
|
15572
|
+
title: "cloneElement makes child props fragile",
|
|
15573
15573
|
severity: "warn",
|
|
15574
15574
|
defaultEnabled: false,
|
|
15575
|
-
recommendation: "Pass children
|
|
15575
|
+
recommendation: "Pass children or render props instead so parent code does not depend on fragile cloned child props.",
|
|
15576
15576
|
category: "Architecture",
|
|
15577
15577
|
create: (context) => ({ CallExpression(node) {
|
|
15578
15578
|
const callee = stripParenExpression(node.callee);
|
|
@@ -15804,7 +15804,7 @@ const noCreateStoreInRender = defineRule({
|
|
|
15804
15804
|
title: "Store created during render",
|
|
15805
15805
|
severity: "error",
|
|
15806
15806
|
category: "Correctness",
|
|
15807
|
-
recommendation: "Create
|
|
15807
|
+
recommendation: "Create stores at module scope so subscribers are not cut off and saved state does not reset every render.",
|
|
15808
15808
|
create: (context) => ({ CallExpression(node) {
|
|
15809
15809
|
const factory = resolveStoreFactoryForCallee(node.callee);
|
|
15810
15810
|
if (!factory) return;
|
|
@@ -15820,10 +15820,10 @@ const noCreateStoreInRender = defineRule({
|
|
|
15820
15820
|
const MESSAGE$24 = "`dangerouslySetInnerHTML` is an XSS hole that runs attacker-controlled HTML in your users' browsers.";
|
|
15821
15821
|
const noDanger = defineRule({
|
|
15822
15822
|
id: "no-danger",
|
|
15823
|
-
title: "
|
|
15823
|
+
title: "Raw HTML injection can run unsafe markup",
|
|
15824
15824
|
severity: "warn",
|
|
15825
15825
|
category: "Security",
|
|
15826
|
-
recommendation: "Render trusted content as React children
|
|
15826
|
+
recommendation: "Render trusted content as React children so attacker-controlled HTML cannot run in users' browsers.",
|
|
15827
15827
|
create: (context) => ({
|
|
15828
15828
|
JSXOpeningElement(node) {
|
|
15829
15829
|
const propAttribute = hasJsxProp(node.attributes, "dangerouslySetInnerHTML");
|
|
@@ -15909,7 +15909,7 @@ const noDangerWithChildren = defineRule({
|
|
|
15909
15909
|
id: "no-danger-with-children",
|
|
15910
15910
|
title: "dangerouslySetInnerHTML with children",
|
|
15911
15911
|
severity: "error",
|
|
15912
|
-
recommendation: "Use either `children` or `dangerouslySetInnerHTML
|
|
15912
|
+
recommendation: "Use either `children` or `dangerouslySetInnerHTML` so React does not ignore one source of content.",
|
|
15913
15913
|
category: "Correctness",
|
|
15914
15914
|
create: (context) => ({
|
|
15915
15915
|
JSXElement(node) {
|
|
@@ -16068,7 +16068,7 @@ const noDarkModeGlow = defineRule({
|
|
|
16068
16068
|
if (!hasDarkBackground || !shadowValue || !shadowProperty) return;
|
|
16069
16069
|
if (hasColoredGlowShadow(shadowValue)) context.report({
|
|
16070
16070
|
node: shadowProperty,
|
|
16071
|
-
message: "
|
|
16071
|
+
message: "A strong colored glow on a dark background can feel heavy. Use a subtle, neutral shadow instead."
|
|
16072
16072
|
});
|
|
16073
16073
|
} })
|
|
16074
16074
|
});
|
|
@@ -16444,7 +16444,7 @@ const noDerivedUseState = defineRule({
|
|
|
16444
16444
|
title: "Prop derived into useState",
|
|
16445
16445
|
tags: ["test-noise"],
|
|
16446
16446
|
severity: "warn",
|
|
16447
|
-
recommendation: "
|
|
16447
|
+
recommendation: "Compute the value inline so prop changes do not leave `useState` holding a stale copy.",
|
|
16448
16448
|
create: (context) => {
|
|
16449
16449
|
const propStackTracker = createComponentPropStackTracker();
|
|
16450
16450
|
return {
|
|
@@ -16536,7 +16536,7 @@ const noDidMountSetState = defineRule({
|
|
|
16536
16536
|
//#endregion
|
|
16537
16537
|
//#region src/plugin/rules/react-builtins/no-did-update-set-state.ts
|
|
16538
16538
|
const LIFECYCLE_NAMES$1 = new Set(["componentDidUpdate"]);
|
|
16539
|
-
const MESSAGE$21 = "
|
|
16539
|
+
const MESSAGE$21 = "Calling setState in componentDidUpdate can trigger another update immediately, loop forever, and freeze the component.";
|
|
16540
16540
|
const resolveSettings$19 = (settings) => {
|
|
16541
16541
|
const reactDoctor = settings?.["react-doctor"];
|
|
16542
16542
|
return { mode: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noDidUpdateSetState ?? {} : {}).mode ?? "allowed" };
|
|
@@ -16776,7 +16776,7 @@ const noDistractingElements = defineRule({
|
|
|
16776
16776
|
title: "Distracting marquee or blink element",
|
|
16777
16777
|
tags: ["react-jsx-only"],
|
|
16778
16778
|
severity: "error",
|
|
16779
|
-
recommendation: "Replace `<marquee>` and `<blink>` with normal
|
|
16779
|
+
recommendation: "Replace `<marquee>` and `<blink>` with normal markup so motion does not distract or disorient users.",
|
|
16780
16780
|
category: "Accessibility",
|
|
16781
16781
|
create: (context) => {
|
|
16782
16782
|
const { distractingTags } = resolveSettings$18(context.settings);
|
|
@@ -16805,7 +16805,7 @@ const noDocumentStartViewTransition = defineRule({
|
|
|
16805
16805
|
if (!isNodeOfType(callee.property, "Identifier") || callee.property.name !== "startViewTransition") return;
|
|
16806
16806
|
context.report({
|
|
16807
16807
|
node,
|
|
16808
|
-
message: "
|
|
16808
|
+
message: "Calling `document.startViewTransition()` directly can bypass React's `<ViewTransition>` animation lifecycle."
|
|
16809
16809
|
});
|
|
16810
16810
|
} })
|
|
16811
16811
|
});
|
|
@@ -16823,13 +16823,13 @@ const noDynamicImportPath = defineRule({
|
|
|
16823
16823
|
if (source && !isNodeOfType(source, "Literal") && !isNodeOfType(source, "TemplateLiteral")) {
|
|
16824
16824
|
context.report({
|
|
16825
16825
|
node,
|
|
16826
|
-
message: "This
|
|
16826
|
+
message: "This can stay in the main bundle because the bundler cannot code-split a dynamic import path. Use a plain string path instead."
|
|
16827
16827
|
});
|
|
16828
16828
|
return;
|
|
16829
16829
|
}
|
|
16830
16830
|
if (isNodeOfType(source, "TemplateLiteral") && (source.expressions?.length ?? 0) > 0) context.report({
|
|
16831
16831
|
node,
|
|
16832
|
-
message: "This
|
|
16832
|
+
message: "This can stay in the main bundle because the bundler cannot code-split a dynamic import path with `${dynamic_path}`. Use a plain string path instead."
|
|
16833
16833
|
});
|
|
16834
16834
|
},
|
|
16835
16835
|
CallExpression(node) {
|
|
@@ -17120,7 +17120,7 @@ const noEffectEventHandler = defineRule({
|
|
|
17120
17120
|
title: "Effect used as an event handler",
|
|
17121
17121
|
tags: ["test-noise"],
|
|
17122
17122
|
severity: "warn",
|
|
17123
|
-
recommendation: "Move
|
|
17123
|
+
recommendation: "Move event logic into the handler that starts it so the side effect does not run late after an extra render.",
|
|
17124
17124
|
create: (context) => {
|
|
17125
17125
|
const propStackTracker = createComponentPropStackTracker();
|
|
17126
17126
|
return {
|
|
@@ -17297,7 +17297,7 @@ const noEffectWithFreshDeps = defineRule({
|
|
|
17297
17297
|
//#region src/plugin/rules/security/no-eval.ts
|
|
17298
17298
|
const noEval = defineRule({
|
|
17299
17299
|
id: "no-eval",
|
|
17300
|
-
title: "
|
|
17300
|
+
title: "eval() runs untrusted code strings",
|
|
17301
17301
|
severity: "error",
|
|
17302
17302
|
recommendation: "Use `JSON.parse` for data, or rewrite the code so it doesn't build and run code from strings.",
|
|
17303
17303
|
create: (context) => ({
|
|
@@ -18170,14 +18170,14 @@ const noFetchInEffect = defineRule({
|
|
|
18170
18170
|
id: "no-fetch-in-effect",
|
|
18171
18171
|
title: "Data fetching inside an effect",
|
|
18172
18172
|
severity: "warn",
|
|
18173
|
-
recommendation: "Use
|
|
18173
|
+
recommendation: "Use a data-fetching layer or Server Component so fetches do not race, double-fire, or leak from `useEffect`.",
|
|
18174
18174
|
create: (context) => ({ CallExpression(node) {
|
|
18175
18175
|
if (!isHookCall$1(node, EFFECT_HOOK_NAMES$1)) return;
|
|
18176
18176
|
const callback = getEffectCallback(node);
|
|
18177
18177
|
if (!callback) return;
|
|
18178
18178
|
if (containsFetchCall(callback)) context.report({
|
|
18179
18179
|
node,
|
|
18180
|
-
message: "fetch() inside useEffect
|
|
18180
|
+
message: "fetch() inside useEffect can race, double-fire, or leak. Use a data-fetching layer or Server Component instead."
|
|
18181
18181
|
});
|
|
18182
18182
|
} })
|
|
18183
18183
|
});
|
|
@@ -18191,9 +18191,9 @@ const ALLOWED_NAMESPACES = new Set([
|
|
|
18191
18191
|
const MESSAGE$19 = "`findDOMNode` crashes your app in React 19 because it was removed.";
|
|
18192
18192
|
const noFindDomNode = defineRule({
|
|
18193
18193
|
id: "no-find-dom-node",
|
|
18194
|
-
title: "
|
|
18194
|
+
title: "findDOMNode breaks component encapsulation",
|
|
18195
18195
|
severity: "warn",
|
|
18196
|
-
recommendation: "Use a ref
|
|
18196
|
+
recommendation: "Use a ref to reach DOM nodes because `findDOMNode` was removed in React 19 and can crash the app.",
|
|
18197
18197
|
create: (context) => ({ CallExpression(node) {
|
|
18198
18198
|
const callee = node.callee;
|
|
18199
18199
|
if (isNodeOfType(callee, "Identifier") && callee.name === "findDOMNode") {
|
|
@@ -18230,7 +18230,7 @@ const noFlushSync = defineRule({
|
|
|
18230
18230
|
if (!isNodeOfType(specifier, "ImportSpecifier")) continue;
|
|
18231
18231
|
if (getImportedName$1(specifier) === "flushSync") context.report({
|
|
18232
18232
|
node: specifier,
|
|
18233
|
-
message: "
|
|
18233
|
+
message: "`flushSync` forces an immediate update, which skips View Transitions and concurrent rendering."
|
|
18234
18234
|
});
|
|
18235
18235
|
}
|
|
18236
18236
|
} })
|
|
@@ -18334,10 +18334,10 @@ const functionContainsReactRenderOutput = (functionNode, scopes) => containsRend
|
|
|
18334
18334
|
//#region src/plugin/rules/architecture/no-giant-component.ts
|
|
18335
18335
|
const noGiantComponent = defineRule({
|
|
18336
18336
|
id: "no-giant-component",
|
|
18337
|
-
title: "
|
|
18337
|
+
title: "Large component is hard to read and change",
|
|
18338
18338
|
severity: "warn",
|
|
18339
18339
|
tags: ["test-noise", "react-jsx-only"],
|
|
18340
|
-
recommendation: "Pull each section into its own component
|
|
18340
|
+
recommendation: "Pull each section into its own component so the parent is easier to read, test, and change.",
|
|
18341
18341
|
create: (context) => {
|
|
18342
18342
|
const getOversizedComponentLineCount = (bodyNode) => {
|
|
18343
18343
|
if (!bodyNode.loc) return null;
|
|
@@ -18575,11 +18575,11 @@ const noInlineBounceEasing = defineRule({
|
|
|
18575
18575
|
if (!value) continue;
|
|
18576
18576
|
if ((key === "transition" || key === "transitionTimingFunction" || key === "animation" || key === "animationTimingFunction") && isOvershootCubicBezier(value)) context.report({
|
|
18577
18577
|
node: property,
|
|
18578
|
-
message: "
|
|
18578
|
+
message: "This bouncy easing can feel distracting. Use ease-out or cubic-bezier(0.16, 1, 0.3, 1) for a smoother finish."
|
|
18579
18579
|
});
|
|
18580
18580
|
if ((key === "animation" || key === "animationName") && hasBounceAnimationName(value)) context.report({
|
|
18581
18581
|
node: property,
|
|
18582
|
-
message: "
|
|
18582
|
+
message: "This bounce animation can feel distracting. Use a smooth ease-out, like ease-out-quart or expo, for a natural finish."
|
|
18583
18583
|
});
|
|
18584
18584
|
}
|
|
18585
18585
|
},
|
|
@@ -18597,7 +18597,7 @@ const noInlineBounceEasing = defineRule({
|
|
|
18597
18597
|
//#region src/plugin/rules/design/no-inline-exhaustive-style.ts
|
|
18598
18598
|
const noInlineExhaustiveStyle = defineRule({
|
|
18599
18599
|
id: "no-inline-exhaustive-style",
|
|
18600
|
-
title: "
|
|
18600
|
+
title: "Large inline style object rebuilds every render",
|
|
18601
18601
|
severity: "warn",
|
|
18602
18602
|
tags: ["test-noise", "react-jsx-only"],
|
|
18603
18603
|
recommendation: "Move the styles to a CSS class, CSS module, Tailwind utilities, or a styled component. Big inline objects are hard to read and rebuild on every update.",
|
|
@@ -18717,7 +18717,7 @@ const noInteractiveElementToNoninteractiveRole = defineRule({
|
|
|
18717
18717
|
//#region src/plugin/rules/react-builtins/no-is-mounted.ts
|
|
18718
18718
|
const noIsMounted = defineRule({
|
|
18719
18719
|
id: "no-is-mounted",
|
|
18720
|
-
title: "
|
|
18720
|
+
title: "isMounted lets async callbacks update after unmount",
|
|
18721
18721
|
severity: "warn",
|
|
18722
18722
|
recommendation: "`isMounted` doesn't work in modern React. Track mount state with a ref, or cancel the async work instead.",
|
|
18723
18723
|
create: (context) => ({ CallExpression(node) {
|
|
@@ -18729,7 +18729,7 @@ const noIsMounted = defineRule({
|
|
|
18729
18729
|
if (ancestor.type === "MethodDefinition" || ancestor.type === "Property") {
|
|
18730
18730
|
context.report({
|
|
18731
18731
|
node,
|
|
18732
|
-
message: "`isMounted` is unreliable in modern React
|
|
18732
|
+
message: "`isMounted` is unreliable in modern React, so async callbacks can update state after unmount."
|
|
18733
18733
|
});
|
|
18734
18734
|
return;
|
|
18735
18735
|
}
|
|
@@ -18834,7 +18834,7 @@ const noLargeAnimatedBlur = defineRule({
|
|
|
18834
18834
|
const blurRadius = Number.parseFloat(match[1]);
|
|
18835
18835
|
if (blurRadius > 10) context.report({
|
|
18836
18836
|
node: property,
|
|
18837
|
-
message: `
|
|
18837
|
+
message: `Large animated blurs can use significant GPU memory on phones because blur(${blurRadius}px) gets heavier as the blur and element grow. Use a smaller blur or a smaller element.`
|
|
18838
18838
|
});
|
|
18839
18839
|
}
|
|
18840
18840
|
} })
|
|
@@ -18928,6 +18928,7 @@ const noLegacyClassLifecycles = defineRule({
|
|
|
18928
18928
|
title: "Legacy class lifecycle methods",
|
|
18929
18929
|
severity: "error",
|
|
18930
18930
|
category: "Correctness",
|
|
18931
|
+
requires: ["react"],
|
|
18931
18932
|
tags: ["migration-hint"],
|
|
18932
18933
|
recommendation: "Move `componentWillMount` work to `componentDidMount`, `componentWillReceiveProps` to `componentDidUpdate` or the static `getDerivedStateFromProps`, and `componentWillUpdate` to `getSnapshotBeforeUpdate` plus `componentDidUpdate`. The `UNSAFE_` prefix only hides the warning. React 19 removes both.",
|
|
18933
18934
|
create: (context) => {
|
|
@@ -18971,6 +18972,7 @@ const noLegacyContextApi = defineRule({
|
|
|
18971
18972
|
title: "Legacy context API",
|
|
18972
18973
|
severity: "error",
|
|
18973
18974
|
category: "Correctness",
|
|
18975
|
+
requires: ["react"],
|
|
18974
18976
|
tags: ["migration-hint"],
|
|
18975
18977
|
recommendation: "Swap `childContextTypes` + `getChildContext` for `const MyContext = createContext(...)` and `<MyContext.Provider value={...}>`. Swap `contextTypes` for `static contextType = MyContext` or `useContext()` in a function component. Move the provider and every consumer together, or some consumers read the wrong context.",
|
|
18976
18978
|
create: (context) => {
|
|
@@ -19078,10 +19080,10 @@ const collectBooleanLikePropsFromBody = (componentBody, propsParamName) => {
|
|
|
19078
19080
|
};
|
|
19079
19081
|
const noManyBooleanProps = defineRule({
|
|
19080
19082
|
id: "no-many-boolean-props",
|
|
19081
|
-
title: "
|
|
19083
|
+
title: "Boolean prop combinations are hard to test",
|
|
19082
19084
|
severity: "warn",
|
|
19083
19085
|
tags: ["test-noise", "react-jsx-only"],
|
|
19084
|
-
recommendation: "Split into smaller components or named variants
|
|
19086
|
+
recommendation: "Split boolean-heavy APIs into smaller components or named variants so combinations stay testable.",
|
|
19085
19087
|
create: (context) => {
|
|
19086
19088
|
const reportIfMany = (booleanLikePropNames, componentName, reportNode) => {
|
|
19087
19089
|
if (booleanLikePropNames.length >= 4) context.report({
|
|
@@ -19212,7 +19214,7 @@ const noMoment = defineRule({
|
|
|
19212
19214
|
});
|
|
19213
19215
|
//#endregion
|
|
19214
19216
|
//#region src/plugin/rules/react-builtins/no-multi-comp.ts
|
|
19215
|
-
const MESSAGE$17 = "This file is harder to
|
|
19217
|
+
const MESSAGE$17 = "This file declares several components, so each component is harder to find, test, and change.";
|
|
19216
19218
|
const resolveSettings$16 = (settings) => {
|
|
19217
19219
|
const reactDoctor = settings?.["react-doctor"];
|
|
19218
19220
|
return { ignoreStateless: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noMultiComp ?? {} : {}).ignoreStateless ?? false };
|
|
@@ -19509,7 +19511,7 @@ const noMultiComp = defineRule({
|
|
|
19509
19511
|
id: "no-multi-comp",
|
|
19510
19512
|
title: "Multiple components in one file",
|
|
19511
19513
|
severity: "warn",
|
|
19512
|
-
recommendation: "Move secondary components into their own files.",
|
|
19514
|
+
recommendation: "Move secondary components into their own files so each component stays easier to find, test, and change.",
|
|
19513
19515
|
category: "Architecture",
|
|
19514
19516
|
create: (context) => {
|
|
19515
19517
|
const settings = resolveSettings$16(context.settings);
|
|
@@ -19589,11 +19591,11 @@ const noMutableInDeps = defineRule({
|
|
|
19589
19591
|
if (!issue) continue;
|
|
19590
19592
|
if (issue.kind === "ref-current") context.report({
|
|
19591
19593
|
node: element,
|
|
19592
|
-
message: `
|
|
19594
|
+
message: `Changing "${issue.rootName}.current" does not re-render the component, so this dependency will not make the effect run again.`
|
|
19593
19595
|
});
|
|
19594
19596
|
else context.report({
|
|
19595
19597
|
node: element,
|
|
19596
|
-
message: `
|
|
19598
|
+
message: `Values like "${issue.rootName}.*" can change without re-rendering the component, so this dependency will not make the effect run again.`
|
|
19597
19599
|
});
|
|
19598
19600
|
}
|
|
19599
19601
|
});
|
|
@@ -20024,7 +20026,7 @@ const noNamespace = defineRule({
|
|
|
20024
20026
|
id: "no-namespace",
|
|
20025
20027
|
title: "Namespaced JSX element",
|
|
20026
20028
|
severity: "warn",
|
|
20027
|
-
recommendation: "
|
|
20029
|
+
recommendation: "Use a plain component or DOM tag because React cannot render JSX namespaced names like `ns:Foo`.",
|
|
20028
20030
|
create: (context) => ({
|
|
20029
20031
|
JSXOpeningElement(node) {
|
|
20030
20032
|
if (!isNodeOfType(node.name, "JSXNamespacedName")) return;
|
|
@@ -20056,7 +20058,7 @@ const noNestedComponentDefinition = defineRule({
|
|
|
20056
20058
|
tags: ["test-noise", "react-jsx-only"],
|
|
20057
20059
|
severity: "error",
|
|
20058
20060
|
category: "Correctness",
|
|
20059
|
-
recommendation: "Move to a separate file
|
|
20061
|
+
recommendation: "Move it to module scope or a separate file so React does not recreate the component and erase its state on every parent render.",
|
|
20060
20062
|
create: (context) => {
|
|
20061
20063
|
const componentStack = [];
|
|
20062
20064
|
return {
|
|
@@ -20121,7 +20123,7 @@ const noNoninteractiveElementInteractions = defineRule({
|
|
|
20121
20123
|
});
|
|
20122
20124
|
//#endregion
|
|
20123
20125
|
//#region src/plugin/rules/a11y/no-noninteractive-element-to-interactive-role.ts
|
|
20124
|
-
const buildMessage$11 = (tag, role) => `
|
|
20126
|
+
const buildMessage$11 = (tag, role) => `Role \`${role}\` gives \`<${tag}>\` interactive semantics even though the element is noninteractive, so screen reader users get the wrong controls.`;
|
|
20125
20127
|
const DEFAULT_ALLOWED_ROLES = {
|
|
20126
20128
|
ul: [
|
|
20127
20129
|
"menu",
|
|
@@ -20960,13 +20962,13 @@ const noRandomKey = defineRule({
|
|
|
20960
20962
|
if (!freshDescription) return;
|
|
20961
20963
|
context.report({
|
|
20962
20964
|
node: node.value,
|
|
20963
|
-
message: `
|
|
20965
|
+
message: `A changing key makes React rebuild each item, which can reset typed input, focus, and scroll position. Use a stable id from the item instead of \`key={${freshDescription}}\`.`
|
|
20964
20966
|
});
|
|
20965
20967
|
} })
|
|
20966
20968
|
});
|
|
20967
20969
|
//#endregion
|
|
20968
20970
|
//#region src/plugin/rules/react-builtins/no-react-children.ts
|
|
20969
|
-
const MESSAGE$14 = "`React.Children`
|
|
20971
|
+
const MESSAGE$14 = "`React.Children` traversal depends on the runtime child shape, so wrapping or unwrapping a child can silently change what gets visited.";
|
|
20970
20972
|
const isChildrenIdentifier = (node, contextNode) => {
|
|
20971
20973
|
if (!isNodeOfType(node, "Identifier") || node.name !== "Children") return false;
|
|
20972
20974
|
return isImportedFromModule(contextNode, "Children", "react");
|
|
@@ -20980,10 +20982,10 @@ const isReactNamespaceMember = (node, contextNode) => {
|
|
|
20980
20982
|
};
|
|
20981
20983
|
const noReactChildren = defineRule({
|
|
20982
20984
|
id: "no-react-children",
|
|
20983
|
-
title: "
|
|
20985
|
+
title: "React.Children is fragile when child shape changes",
|
|
20984
20986
|
severity: "warn",
|
|
20985
20987
|
defaultEnabled: false,
|
|
20986
|
-
recommendation: "Pass children as props or render them directly
|
|
20988
|
+
recommendation: "Pass children as explicit props or render them directly so child shape changes do not break traversal logic.",
|
|
20987
20989
|
category: "Architecture",
|
|
20988
20990
|
create: (context) => ({ CallExpression(node) {
|
|
20989
20991
|
const calleeOuter = stripParenExpression(node.callee);
|
|
@@ -21081,7 +21083,7 @@ const reportTestUtilsImports = (node, context) => {
|
|
|
21081
21083
|
};
|
|
21082
21084
|
const noReactDomDeprecatedApis = defineRule({
|
|
21083
21085
|
id: "no-react-dom-deprecated-apis",
|
|
21084
|
-
title: "Deprecated react-dom APIs",
|
|
21086
|
+
title: "Deprecated react-dom APIs break in React 19",
|
|
21085
21087
|
requires: ["react:18"],
|
|
21086
21088
|
tags: ["test-noise", "migration-hint"],
|
|
21087
21089
|
severity: "warn",
|
|
@@ -21098,7 +21100,7 @@ const noReactDomDeprecatedApis = defineRule({
|
|
|
21098
21100
|
});
|
|
21099
21101
|
const noReact19DeprecatedApis = defineRule({
|
|
21100
21102
|
id: "no-react19-deprecated-apis",
|
|
21101
|
-
title: "
|
|
21103
|
+
title: "React 19 API migration can break callers",
|
|
21102
21104
|
requires: ["react:19"],
|
|
21103
21105
|
tags: ["test-noise", "migration-hint"],
|
|
21104
21106
|
severity: "warn",
|
|
@@ -21206,7 +21208,7 @@ const noRedundantRoles = defineRule({
|
|
|
21206
21208
|
title: "Redundant ARIA role",
|
|
21207
21209
|
tags: ["react-jsx-only"],
|
|
21208
21210
|
severity: "warn",
|
|
21209
|
-
recommendation: "Remove `role` attributes
|
|
21211
|
+
recommendation: "Remove redundant `role` attributes so assistive tech reads the element's native semantics without extra noise.",
|
|
21210
21212
|
category: "Accessibility",
|
|
21211
21213
|
create: (context) => {
|
|
21212
21214
|
const settings = resolveSettings$13(context.settings);
|
|
@@ -21276,7 +21278,7 @@ const noRenderInRender = defineRule({
|
|
|
21276
21278
|
title: "Component rendered by inline function call",
|
|
21277
21279
|
severity: "warn",
|
|
21278
21280
|
tags: ["test-noise"],
|
|
21279
|
-
recommendation: "Make it a named component
|
|
21281
|
+
recommendation: "Make it a named component so React preserves its identity and does not remount its state.",
|
|
21280
21282
|
create: (context) => ({ JSXExpressionContainer(node) {
|
|
21281
21283
|
const expression = node.expression;
|
|
21282
21284
|
if (!isNodeOfType(expression, "CallExpression")) return;
|
|
@@ -21295,7 +21297,7 @@ const noRenderInRender = defineRule({
|
|
|
21295
21297
|
const RENDER_PROP_PATTERN = /^render[A-Z]/;
|
|
21296
21298
|
const noRenderPropChildren = defineRule({
|
|
21297
21299
|
id: "no-render-prop-children",
|
|
21298
|
-
title: "
|
|
21300
|
+
title: "Render-prop slots make this component hard to extend",
|
|
21299
21301
|
tags: ["test-noise"],
|
|
21300
21302
|
severity: "warn",
|
|
21301
21303
|
recommendation: "Swap `renderXxx` props for child components like `<Modal.Header>` or plain `children`, so the parent doesn't control every slot.",
|
|
@@ -22171,7 +22173,7 @@ const noSelfUpdatingEffect = defineRule({
|
|
|
22171
22173
|
reportedStateNames.add(stateName);
|
|
22172
22174
|
context.report({
|
|
22173
22175
|
node: setterCall,
|
|
22174
|
-
message: `${setterCall.callee.name}()
|
|
22176
|
+
message: `${setterCall.callee.name}() updates \`${stateName}\`, which is also in this effect's dependency list. Guard the update or move the derivation out of the effect.`
|
|
22175
22177
|
});
|
|
22176
22178
|
}
|
|
22177
22179
|
}
|
|
@@ -22203,13 +22205,13 @@ const getParentComponent = (node) => {
|
|
|
22203
22205
|
};
|
|
22204
22206
|
//#endregion
|
|
22205
22207
|
//#region src/plugin/rules/react-builtins/no-set-state.ts
|
|
22206
|
-
const MESSAGE$12 = "
|
|
22208
|
+
const MESSAGE$12 = "`this.setState` keeps local class state in a project that forbids it, so state ownership becomes harder to reason about.";
|
|
22207
22209
|
const noSetState = defineRule({
|
|
22208
22210
|
id: "no-set-state",
|
|
22209
|
-
title: "
|
|
22211
|
+
title: "Local class state forbidden",
|
|
22210
22212
|
severity: "warn",
|
|
22211
22213
|
defaultEnabled: false,
|
|
22212
|
-
recommendation: "Lift state up or use an external store
|
|
22214
|
+
recommendation: "Lift state up or use an external store so class-local state does not hide ownership.",
|
|
22213
22215
|
category: "Architecture",
|
|
22214
22216
|
create: (context) => ({ CallExpression(node) {
|
|
22215
22217
|
if (!isNodeOfType(node.callee, "MemberExpression")) return;
|
|
@@ -22251,7 +22253,7 @@ const noSetStateInRender = defineRule({
|
|
|
22251
22253
|
const setterIdentifierName = setterCall.callee.name;
|
|
22252
22254
|
context.report({
|
|
22253
22255
|
node: setterCall,
|
|
22254
|
-
message: `${setterIdentifierName}()
|
|
22256
|
+
message: `${setterIdentifierName}() triggers another render while rendering. Move it to an effect or event handler, or compute the value during render.`
|
|
22255
22257
|
});
|
|
22256
22258
|
}
|
|
22257
22259
|
};
|
|
@@ -22485,9 +22487,9 @@ const resolveSettings$11 = (settings) => {
|
|
|
22485
22487
|
};
|
|
22486
22488
|
const noStringRefs = defineRule({
|
|
22487
22489
|
id: "no-string-refs",
|
|
22488
|
-
title: "
|
|
22490
|
+
title: "String refs are legacy and fragile",
|
|
22489
22491
|
severity: "warn",
|
|
22490
|
-
recommendation: "Use a callback ref
|
|
22492
|
+
recommendation: "Use a callback ref or `useRef` so ref ownership is explicit and not tied to legacy string lookup.",
|
|
22491
22493
|
create: (context) => {
|
|
22492
22494
|
const { noTemplateLiterals = false } = resolveSettings$11(context.settings);
|
|
22493
22495
|
const isTestlikeFile = isTestlikeFilename(context.filename);
|
|
@@ -22566,7 +22568,7 @@ const noThisInSfc = defineRule({
|
|
|
22566
22568
|
id: "no-this-in-sfc",
|
|
22567
22569
|
title: "this used in function component",
|
|
22568
22570
|
severity: "warn",
|
|
22569
|
-
recommendation: "Read from the `props` argument
|
|
22571
|
+
recommendation: "Read from the `props` argument because function components do not have a React instance `this`.",
|
|
22570
22572
|
create: (context) => {
|
|
22571
22573
|
const configured = (context.settings?.react)?.createClass;
|
|
22572
22574
|
const customClassFactoryNames = /* @__PURE__ */ new Set();
|
|
@@ -22710,10 +22712,10 @@ const noUncontrolledInput = defineRule({
|
|
|
22710
22712
|
const hasAllowedPartner = VALUE_PARTNER_ATTRIBUTES.some((partnerAttributeName) => findJsxAttribute(attributes, partnerAttributeName));
|
|
22711
22713
|
if (isNodeOfType(valueAttribute.value, "JSXExpressionContainer") && isNodeOfType(valueAttribute.value.expression, "Identifier") && undefinedInitialStateNames.has(valueAttribute.value.expression.name)) {
|
|
22712
22714
|
const stateName = valueAttribute.value.expression.name;
|
|
22713
|
-
const partnerHint = hasAllowedPartner ? "Give useState a starting value" : "Give useState a starting value
|
|
22715
|
+
const partnerHint = hasAllowedPartner ? "Give useState a starting value" : "Give useState a starting value and add onChange (or readOnly)";
|
|
22714
22716
|
context.report({
|
|
22715
22717
|
node: child,
|
|
22716
|
-
message: `
|
|
22718
|
+
message: `This can trigger a console warning and reset the field because "${stateName}" starts undefined, so <${tagName} value={${stateName}}> flips from uncontrolled to controlled. ${partnerHint} (e.g. \`useState("")\`).`
|
|
22717
22719
|
});
|
|
22718
22720
|
return;
|
|
22719
22721
|
}
|
|
@@ -22775,7 +22777,7 @@ const noUnescapedEntities = defineRule({
|
|
|
22775
22777
|
title: "Unescaped entities in JSX",
|
|
22776
22778
|
severity: "warn",
|
|
22777
22779
|
defaultEnabled: false,
|
|
22778
|
-
recommendation: "Replace bare `'` / `\"` / `>` / `}` characters
|
|
22780
|
+
recommendation: "Replace bare `'` / `\"` / `>` / `}` characters with HTML entities so literal UI text is encoded consistently.",
|
|
22779
22781
|
create: (context) => ({ JSXText(node) {
|
|
22780
22782
|
const value = node.value;
|
|
22781
22783
|
for (const character of value) if (character in ESCAPED_VERSIONS) {
|
|
@@ -23710,7 +23712,7 @@ const noUnknownProperty = defineRule({
|
|
|
23710
23712
|
id: "no-unknown-property",
|
|
23711
23713
|
title: "Unknown DOM property",
|
|
23712
23714
|
severity: "warn",
|
|
23713
|
-
recommendation: "Use the prop name React expects, like `className`, `htmlFor`, or `tabIndex
|
|
23715
|
+
recommendation: "Use the prop name React expects, like `className`, `htmlFor`, or `tabIndex`, so the attribute is applied correctly.",
|
|
23714
23716
|
create: (context) => {
|
|
23715
23717
|
const { ignore = [], requireDataLowercase = false } = resolveSettings$10(context.settings);
|
|
23716
23718
|
const ignoreSet = new Set(ignore);
|
|
@@ -23796,7 +23798,7 @@ const UNSAFE_ALIASES = new Set([
|
|
|
23796
23798
|
"componentWillReceiveProps",
|
|
23797
23799
|
"componentWillUpdate"
|
|
23798
23800
|
]);
|
|
23799
|
-
const buildMessage$6 = (methodName) => `\`${methodName}\`
|
|
23801
|
+
const buildMessage$6 = (methodName) => `\`${methodName}\` runs during unsafe legacy render timing and is deprecated, so React may double-invoke or remove it.`;
|
|
23800
23802
|
const resolveSettings$9 = (settings) => {
|
|
23801
23803
|
const reactDoctor = settings?.["react-doctor"];
|
|
23802
23804
|
return { checkAliases: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noUnsafe ?? {} : {}).checkAliases ?? false };
|
|
@@ -23829,7 +23831,7 @@ const noUnsafe = defineRule({
|
|
|
23829
23831
|
id: "no-unsafe",
|
|
23830
23832
|
title: "Unsafe legacy lifecycle method",
|
|
23831
23833
|
severity: "warn",
|
|
23832
|
-
recommendation: "
|
|
23834
|
+
recommendation: "Move setup to `constructor` or `componentDidMount`, prop-derived state to `getDerivedStateFromProps`, and update side effects to `componentDidUpdate` so React does not rely on deprecated unsafe lifecycles.",
|
|
23833
23835
|
create: (context) => {
|
|
23834
23836
|
const { checkAliases } = resolveSettings$9(context.settings);
|
|
23835
23837
|
const flagsUnsafePrefix = isReactVersionAtLeast(getConfiguredReactMajorMinor(context.settings), 16, 3);
|
|
@@ -24085,7 +24087,7 @@ const noUnstableNestedComponents = defineRule({
|
|
|
24085
24087
|
id: "no-unstable-nested-components",
|
|
24086
24088
|
title: "Component defined inside a component",
|
|
24087
24089
|
severity: "warn",
|
|
24088
|
-
recommendation: "Move nested components to
|
|
24090
|
+
recommendation: "Move nested components to module scope so React does not remount them and lose state on every render.",
|
|
24089
24091
|
category: "Performance",
|
|
24090
24092
|
create: (context) => {
|
|
24091
24093
|
const settings = resolveSettings$8(context.settings);
|
|
@@ -24259,7 +24261,7 @@ const noWideLetterSpacing = defineRule({
|
|
|
24259
24261
|
//#endregion
|
|
24260
24262
|
//#region src/plugin/rules/react-builtins/no-will-update-set-state.ts
|
|
24261
24263
|
const LIFECYCLE_NAMES = new Set(["componentWillUpdate", "UNSAFE_componentWillUpdate"]);
|
|
24262
|
-
const MESSAGE$9 = "
|
|
24264
|
+
const MESSAGE$9 = "Calling setState in componentWillUpdate can trigger another update immediately, loop forever, and freeze the component.";
|
|
24263
24265
|
const resolveSettings$7 = (settings) => {
|
|
24264
24266
|
const reactDoctor = settings?.["react-doctor"];
|
|
24265
24267
|
return { mode: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.noWillUpdateSetState ?? {} : {}).mode ?? "allowed" };
|
|
@@ -24282,7 +24284,7 @@ const noWillUpdateSetState = defineRule({
|
|
|
24282
24284
|
id: "no-will-update-set-state",
|
|
24283
24285
|
title: "setState in componentWillUpdate",
|
|
24284
24286
|
severity: "warn",
|
|
24285
|
-
recommendation: "
|
|
24287
|
+
recommendation: "Avoid setState in componentWillUpdate because it can loop forever; derive state before render or move guarded updates to componentDidUpdate.",
|
|
24286
24288
|
create: (context) => {
|
|
24287
24289
|
const { mode } = resolveSettings$7(context.settings);
|
|
24288
24290
|
const activeLifecycleNames = isReactBelow16_3(context.settings) ? new Set(["componentWillUpdate"]) : LIFECYCLE_NAMES;
|
|
@@ -24316,7 +24318,7 @@ const noZIndex9999 = defineRule({
|
|
|
24316
24318
|
const zValue = getStylePropertyNumberValue(property);
|
|
24317
24319
|
if (zValue !== null && Math.abs(zValue) >= 1e3) context.report({
|
|
24318
24320
|
node: property,
|
|
24319
|
-
message: `z-index ${zValue} is
|
|
24321
|
+
message: `z-index ${zValue} is unusually high and can hide a layering bug instead of fixing it. Use a small set scale, like 1 to 50.`
|
|
24320
24322
|
});
|
|
24321
24323
|
}
|
|
24322
24324
|
},
|
|
@@ -24499,12 +24501,12 @@ const UTILITY_FILE_BASENAMES = new Set([
|
|
|
24499
24501
|
]);
|
|
24500
24502
|
//#endregion
|
|
24501
24503
|
//#region src/plugin/rules/react-builtins/only-export-components.ts
|
|
24502
|
-
const NAMED_EXPORT_MESSAGE = "Fast Refresh
|
|
24503
|
-
const ANONYMOUS_MESSAGE = "Fast Refresh can't track
|
|
24504
|
-
const EXPORT_ALL_MESSAGE = "`export *` hides what's exported, so Fast Refresh
|
|
24505
|
-
const REACT_CONTEXT_MESSAGE = "
|
|
24506
|
-
const LOCAL_COMPONENT_MESSAGE = "Fast Refresh skips
|
|
24507
|
-
const NO_EXPORT_MESSAGE = "Fast Refresh can't track
|
|
24504
|
+
const NAMED_EXPORT_MESSAGE = "This file exports non-components, so Fast Refresh can't safely preserve component state.";
|
|
24505
|
+
const ANONYMOUS_MESSAGE = "This component is unnamed, so Fast Refresh can't track it and falls back to a full reload.";
|
|
24506
|
+
const EXPORT_ALL_MESSAGE = "`export *` hides what's exported, so Fast Refresh can't safely preserve component state.";
|
|
24507
|
+
const REACT_CONTEXT_MESSAGE = "This file exports a context with components, so Fast Refresh can't safely preserve component state.";
|
|
24508
|
+
const LOCAL_COMPONENT_MESSAGE = "This component is not exported, so Fast Refresh skips it and local edits can full-reload.";
|
|
24509
|
+
const NO_EXPORT_MESSAGE = "This file exports nothing, so Fast Refresh can't track the component and local edits can full-reload.";
|
|
24508
24510
|
const DEFAULT_REACT_HOCS = [
|
|
24509
24511
|
"memo",
|
|
24510
24512
|
"forwardRef",
|
|
@@ -24657,7 +24659,7 @@ const onlyExportComponents = defineRule({
|
|
|
24657
24659
|
id: "only-export-components",
|
|
24658
24660
|
title: "Non-component export in component file",
|
|
24659
24661
|
severity: "warn",
|
|
24660
|
-
recommendation: "Move non-component exports out of files
|
|
24662
|
+
recommendation: "Move non-component exports out of component files so Fast Refresh can preserve component state instead of full-reloading.",
|
|
24661
24663
|
category: "Architecture",
|
|
24662
24664
|
create: (context) => {
|
|
24663
24665
|
const settings = resolveSettings$6(context.settings);
|
|
@@ -24878,10 +24880,10 @@ const isChildrenMemberExpression = (node) => {
|
|
|
24878
24880
|
};
|
|
24879
24881
|
const preactNoChildrenLength = defineRule({
|
|
24880
24882
|
id: "preact-no-children-length",
|
|
24881
|
-
title: "Array methods on
|
|
24883
|
+
title: "Array methods on Preact children can crash",
|
|
24882
24884
|
requires: ["preact"],
|
|
24883
24885
|
severity: "warn",
|
|
24884
|
-
recommendation: "Wrap with `toChildArray(children)`
|
|
24886
|
+
recommendation: "Wrap with `toChildArray(children)` because Preact's `props.children` is not always an array and array methods can crash.",
|
|
24885
24887
|
create: (context) => ({ MemberExpression(node) {
|
|
24886
24888
|
if (node.computed) return;
|
|
24887
24889
|
if (!isNodeOfType(node.property, "Identifier")) return;
|
|
@@ -24915,10 +24917,10 @@ const REACT_HOOK_NAMES = new Set([
|
|
|
24915
24917
|
const buildMessage$4 = (importedNames) => `Your users hit \`__H\` undefined errors because importing ${importedNames.map((innerName) => `\`${innerName}\``).join(", ")} from \`react\` in a pure-Preact project loads a second copy of the hook state, so import from \`preact/hooks\` (or \`preact/compat\`) instead.`;
|
|
24916
24918
|
const preactNoReactHooksImport = defineRule({
|
|
24917
24919
|
id: "preact-no-react-hooks-import",
|
|
24918
|
-
title: "
|
|
24920
|
+
title: "React hook imports break pure Preact hook state",
|
|
24919
24921
|
requires: ["pure-preact"],
|
|
24920
24922
|
severity: "warn",
|
|
24921
|
-
recommendation: "
|
|
24923
|
+
recommendation: "Import hooks from `preact/hooks` so they share Preact's renderer state instead of loading a second hook implementation.",
|
|
24922
24924
|
create: (context) => ({ ImportDeclaration(node) {
|
|
24923
24925
|
const source = node.source;
|
|
24924
24926
|
if (!isNodeOfType(source, "Literal") || source.value !== "react") return;
|
|
@@ -24978,7 +24980,7 @@ const preactNoRenderArguments = defineRule({
|
|
|
24978
24980
|
title: "render() reads props from arguments",
|
|
24979
24981
|
requires: ["preact"],
|
|
24980
24982
|
severity: "warn",
|
|
24981
|
-
recommendation: "Read
|
|
24983
|
+
recommendation: "Read from `this.props` and `this.state` because `preact/compat` uses React's parameterless `render()` and positional props/state become undefined.",
|
|
24982
24984
|
create: (context) => ({ MethodDefinition(node) {
|
|
24983
24985
|
if (!isInstanceMethodNamedRender(node)) return;
|
|
24984
24986
|
if (!isInsideEs6Component$1(node)) return;
|
|
@@ -25000,7 +25002,7 @@ const preactPreferOndblclick = defineRule({
|
|
|
25000
25002
|
title: "onDoubleClick instead of onDblClick",
|
|
25001
25003
|
requires: ["pure-preact"],
|
|
25002
25004
|
severity: "warn",
|
|
25003
|
-
recommendation: "Rename
|
|
25005
|
+
recommendation: "Rename `onDoubleClick` to `onDblClick` because Preact core listens for the DOM `dblclick` event name and `onDoubleClick` never fires.",
|
|
25004
25006
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
25005
25007
|
if (!isNodeOfType(node.name, "JSXIdentifier")) return;
|
|
25006
25008
|
const tagName = node.name.name;
|
|
@@ -25072,8 +25074,8 @@ const preferDynamicImport = defineRule({
|
|
|
25072
25074
|
});
|
|
25073
25075
|
//#endregion
|
|
25074
25076
|
//#region src/plugin/rules/react-builtins/prefer-es6-class.ts
|
|
25075
|
-
const ALWAYS_MESSAGE$1 = "`createReactClass` is legacy
|
|
25076
|
-
const NEVER_MESSAGE$1 = "This component is
|
|
25077
|
+
const ALWAYS_MESSAGE$1 = "`createReactClass` is legacy and adds a dependency, so this component diverges from modern React class syntax.";
|
|
25078
|
+
const NEVER_MESSAGE$1 = "This component uses an ES6 class where `createReactClass` is configured, so component style is inconsistent across the codebase.";
|
|
25077
25079
|
const resolveSettings$5 = (settings) => {
|
|
25078
25080
|
const reactDoctor = settings?.["react-doctor"];
|
|
25079
25081
|
if (typeof reactDoctor !== "object" || reactDoctor === null) return {};
|
|
@@ -25084,7 +25086,7 @@ const preferEs6Class = defineRule({
|
|
|
25084
25086
|
title: "createClass instead of ES6 class",
|
|
25085
25087
|
severity: "warn",
|
|
25086
25088
|
defaultEnabled: false,
|
|
25087
|
-
recommendation: "Pick one component style
|
|
25089
|
+
recommendation: "Pick one component style so readers do not have to switch between legacy `createReactClass` patterns and modern class components.",
|
|
25088
25090
|
category: "Architecture",
|
|
25089
25091
|
create: (context) => {
|
|
25090
25092
|
const { mode = "always" } = resolveSettings$5(context.settings);
|
|
@@ -25243,7 +25245,7 @@ const preferExplicitVariants = defineRule({
|
|
|
25243
25245
|
});
|
|
25244
25246
|
//#endregion
|
|
25245
25247
|
//#region src/plugin/rules/react-builtins/prefer-function-component.ts
|
|
25246
|
-
const MESSAGE$7 = "This class component
|
|
25248
|
+
const MESSAGE$7 = "This class component keeps behavior in lifecycle methods, so state and effects are harder to follow than in a hook-based function component.";
|
|
25247
25249
|
const resolveSettings$4 = (settings) => {
|
|
25248
25250
|
const reactDoctor = settings?.["react-doctor"];
|
|
25249
25251
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.preferFunctionComponent ?? {} : {};
|
|
@@ -25269,7 +25271,7 @@ const preferFunctionComponent = defineRule({
|
|
|
25269
25271
|
title: "Class component instead of function",
|
|
25270
25272
|
severity: "warn",
|
|
25271
25273
|
defaultEnabled: false,
|
|
25272
|
-
recommendation: "
|
|
25274
|
+
recommendation: "Rewrite the class component as a function component so state and effects use modern hook patterns instead of class lifecycles.",
|
|
25273
25275
|
category: "Architecture",
|
|
25274
25276
|
create: (context) => {
|
|
25275
25277
|
const settings = resolveSettings$4(context.settings);
|
|
@@ -25621,7 +25623,7 @@ const preferTagOverRole = defineRule({
|
|
|
25621
25623
|
title: "Role used instead of HTML tag",
|
|
25622
25624
|
tags: ["react-jsx-only"],
|
|
25623
25625
|
severity: "warn",
|
|
25624
|
-
recommendation: "
|
|
25626
|
+
recommendation: "Use the matching HTML element when one exists so browsers and assistive tech get native semantics.",
|
|
25625
25627
|
category: "Accessibility",
|
|
25626
25628
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
25627
25629
|
const tag = getElementType(node, context.settings);
|
|
@@ -25927,7 +25929,7 @@ const preferUseReducer = defineRule({
|
|
|
25927
25929
|
title: "Many related useState calls",
|
|
25928
25930
|
tags: ["test-noise"],
|
|
25929
25931
|
severity: "warn",
|
|
25930
|
-
recommendation: "Group related state
|
|
25932
|
+
recommendation: "Group related state in `useReducer` so one logical update does not fan out into separate renders.",
|
|
25931
25933
|
create: (context) => {
|
|
25932
25934
|
const reportExcessiveUseState = (body, componentName) => {
|
|
25933
25935
|
if (!isNodeOfType(body, "BlockStatement")) return;
|
|
@@ -25959,7 +25961,7 @@ const preferUseReducer = defineRule({
|
|
|
25959
25961
|
//#region src/plugin/rules/tanstack-query/query-destructure-result.ts
|
|
25960
25962
|
const queryDestructureResult = defineRule({
|
|
25961
25963
|
id: "query-destructure-result",
|
|
25962
|
-
title: "
|
|
25964
|
+
title: "Whole query result subscribes to every field",
|
|
25963
25965
|
tags: ["test-noise"],
|
|
25964
25966
|
requires: ["tanstack-query"],
|
|
25965
25967
|
severity: "error",
|
|
@@ -26012,7 +26014,7 @@ const queryNoQueryInEffect = defineRule({
|
|
|
26012
26014
|
tags: ["test-noise"],
|
|
26013
26015
|
requires: ["tanstack-query"],
|
|
26014
26016
|
severity: "warn",
|
|
26015
|
-
recommendation: "
|
|
26017
|
+
recommendation: "Use `queryKey` changes or `enabled` so React Query schedules the fetch once instead of refetching again from `useEffect`.",
|
|
26016
26018
|
create: (context) => ({ CallExpression(node) {
|
|
26017
26019
|
if (!isHookCall$1(node, EFFECT_HOOK_NAMES$1)) return;
|
|
26018
26020
|
const callback = getEffectCallback(node);
|
|
@@ -26335,7 +26337,7 @@ const reduxUseselectorInlineDerivation = defineRule({
|
|
|
26335
26337
|
severity: "warn",
|
|
26336
26338
|
category: "Performance",
|
|
26337
26339
|
disabledBy: ["react-compiler"],
|
|
26338
|
-
recommendation: "Select the raw slice and
|
|
26340
|
+
recommendation: "Select the raw slice and memoize derivation so Redux actions do not rebuild a collection and redraw this component.",
|
|
26339
26341
|
create: (context) => {
|
|
26340
26342
|
let aliases = /* @__PURE__ */ new Set();
|
|
26341
26343
|
return {
|
|
@@ -26395,7 +26397,7 @@ const reduxUseselectorReturnsNewCollection = defineRule({
|
|
|
26395
26397
|
severity: "warn",
|
|
26396
26398
|
category: "Performance",
|
|
26397
26399
|
disabledBy: ["react-compiler"],
|
|
26398
|
-
recommendation: "Return a
|
|
26400
|
+
recommendation: "Return a stable selected value, split selectors, or pass `shallowEqual` so every Redux action does not redraw this component.",
|
|
26399
26401
|
create: (context) => {
|
|
26400
26402
|
let aliases = /* @__PURE__ */ new Set();
|
|
26401
26403
|
return {
|
|
@@ -26421,7 +26423,7 @@ const renderingAnimateSvgWrapper = defineRule({
|
|
|
26421
26423
|
title: "Animating an SVG directly",
|
|
26422
26424
|
tags: ["test-noise"],
|
|
26423
26425
|
severity: "warn",
|
|
26424
|
-
recommendation: "Wrap the SVG
|
|
26426
|
+
recommendation: "Wrap the SVG in a motion element so animation props apply to a stable wrapper instead of the SVG node itself.",
|
|
26425
26427
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
26426
26428
|
if (!isNodeOfType(node.name, "JSXIdentifier") || node.name.name !== "svg") return;
|
|
26427
26429
|
if (node.attributes?.some((attribute) => isNodeOfType(attribute, "JSXAttribute") && isNodeOfType(attribute.name, "JSXIdentifier") && MOTION_ANIMATE_PROPS.has(attribute.name.name))) context.report({
|
|
@@ -26571,7 +26573,7 @@ const renderingHydrationMismatchTime = defineRule({
|
|
|
26571
26573
|
if (hasSuppressHydrationWarningAttribute(findOpeningElementOfChild(node))) return;
|
|
26572
26574
|
context.report({
|
|
26573
26575
|
node,
|
|
26574
|
-
message: `This
|
|
26576
|
+
message: `This can cause a hydration mismatch because ${matched.display} in JSX gives a different value on the server than in the browser. Move it into useEffect+useState to run only in the browser, or add suppressHydrationWarning to the parent if it's on purpose.`
|
|
26575
26577
|
});
|
|
26576
26578
|
return;
|
|
26577
26579
|
}
|
|
@@ -26580,7 +26582,7 @@ const renderingHydrationMismatchTime = defineRule({
|
|
|
26580
26582
|
if (hasSuppressHydrationWarningAttribute(findOpeningElementOfChild(node))) return;
|
|
26581
26583
|
context.report({
|
|
26582
26584
|
node: child,
|
|
26583
|
-
message: `This
|
|
26585
|
+
message: `This can cause a hydration mismatch because ${pattern.display} reached from JSX gives a different value on the server than in the browser. Move it into useEffect+useState to run only in the browser, or add suppressHydrationWarning to the parent if it's on purpose.`
|
|
26584
26586
|
});
|
|
26585
26587
|
return;
|
|
26586
26588
|
}
|
|
@@ -26859,7 +26861,7 @@ const requireRenderReturn = defineRule({
|
|
|
26859
26861
|
id: "require-render-return",
|
|
26860
26862
|
title: "Render method does not return",
|
|
26861
26863
|
severity: "error",
|
|
26862
|
-
recommendation: "Return JSX
|
|
26864
|
+
recommendation: "Return JSX or `null` from `render` so the component intentionally shows something or nothing.",
|
|
26863
26865
|
create: (context) => {
|
|
26864
26866
|
const checkFunction = (functionNode) => {
|
|
26865
26867
|
const host = resolveRenderHost(functionNode);
|
|
@@ -27181,7 +27183,7 @@ const rerenderLazyRefInit = defineRule({
|
|
|
27181
27183
|
tags: ["test-noise"],
|
|
27182
27184
|
severity: "warn",
|
|
27183
27185
|
category: "Performance",
|
|
27184
|
-
recommendation: "
|
|
27186
|
+
recommendation: "Initialize the ref lazily so expensive values are not rebuilt and discarded on every render.",
|
|
27185
27187
|
create: (context) => ({ CallExpression(node) {
|
|
27186
27188
|
if (!isHookCall$1(node, "useRef") || !node.arguments?.length) return;
|
|
27187
27189
|
const initializer = node.arguments[0];
|
|
@@ -27208,7 +27210,7 @@ const rerenderLazyStateInit = defineRule({
|
|
|
27208
27210
|
tags: ["test-noise"],
|
|
27209
27211
|
severity: "warn",
|
|
27210
27212
|
category: "Performance",
|
|
27211
|
-
recommendation: "Wrap in an arrow function so
|
|
27213
|
+
recommendation: "Wrap expensive initial state in an arrow function so the initializer does not rerun and get thrown away on every render.",
|
|
27212
27214
|
create: (context) => ({ CallExpression(node) {
|
|
27213
27215
|
if (!isHookCall$1(node, "useState") || !node.arguments?.length) return;
|
|
27214
27216
|
const initializer = node.arguments[0];
|
|
@@ -27491,7 +27493,7 @@ const rerenderTransitionsScroll = defineRule({
|
|
|
27491
27493
|
}
|
|
27492
27494
|
context.report({
|
|
27493
27495
|
node: setStateCall,
|
|
27494
|
-
message: `This
|
|
27496
|
+
message: `This can make scrolling stutter because setState in a "${eventName}" handler redraws on every event. Wrap it in startTransition, use useDeferredValue, or keep the value in a ref and throttle with requestAnimationFrame.`
|
|
27495
27497
|
});
|
|
27496
27498
|
} })
|
|
27497
27499
|
});
|
|
@@ -27511,7 +27513,7 @@ const rnAnimateLayoutProperty = defineRetiredRule({
|
|
|
27511
27513
|
tags: ["test-noise"],
|
|
27512
27514
|
requires: ["react-native"],
|
|
27513
27515
|
severity: "warn",
|
|
27514
|
-
recommendation: "Reanimated useAnimatedStyle
|
|
27516
|
+
recommendation: "Retired: Reanimated `useAnimatedStyle` can safely drive layout-affecting properties on the UI thread, so this pattern should not be flagged."
|
|
27515
27517
|
});
|
|
27516
27518
|
//#endregion
|
|
27517
27519
|
//#region src/plugin/rules/react-native/rn-animation-reaction-as-derived.ts
|
|
@@ -27542,7 +27544,7 @@ const rnAnimationReactionAsDerived = defineRule({
|
|
|
27542
27544
|
if (!isValueAssignment && !isSetCall) return;
|
|
27543
27545
|
context.report({
|
|
27544
27546
|
node,
|
|
27545
|
-
message: "
|
|
27547
|
+
message: "This useAnimatedReaction only copies one shared value into another, so it can miss Reanimated's derived-value dependency tracking."
|
|
27546
27548
|
});
|
|
27547
27549
|
} })
|
|
27548
27550
|
});
|
|
@@ -27559,17 +27561,17 @@ const JS_BOTTOM_SHEET_PACKAGES = new Set([
|
|
|
27559
27561
|
]);
|
|
27560
27562
|
const rnBottomSheetPreferNative = defineRule({
|
|
27561
27563
|
id: "rn-bottom-sheet-prefer-native",
|
|
27562
|
-
title: "JS bottom sheet
|
|
27564
|
+
title: "JS bottom sheet misses native sheet behavior",
|
|
27563
27565
|
tags: ["test-noise"],
|
|
27564
27566
|
requires: ["react-native"],
|
|
27565
27567
|
severity: "warn",
|
|
27566
|
-
recommendation: "On RN v7+, use `<Modal presentationStyle=\"formSheet\">`
|
|
27568
|
+
recommendation: "On RN v7+, use `<Modal presentationStyle=\"formSheet\">` so the sheet uses platform-native gestures, detents, accessibility, and presentation behavior.",
|
|
27567
27569
|
create: (context) => ({ ImportDeclaration(node) {
|
|
27568
27570
|
const source = node.source?.value;
|
|
27569
27571
|
if (typeof source !== "string" || !JS_BOTTOM_SHEET_PACKAGES.has(source)) return;
|
|
27570
27572
|
context.report({
|
|
27571
27573
|
node,
|
|
27572
|
-
message: `
|
|
27574
|
+
message: `Users get JS-driven sheet gestures and presentation with ${source}, instead of the platform-native formSheet behavior.`
|
|
27573
27575
|
});
|
|
27574
27576
|
} })
|
|
27575
27577
|
});
|
|
@@ -27655,13 +27657,13 @@ const rnDetoxMissingAwait = defineRule({
|
|
|
27655
27657
|
if (root.calleeName === "waitFor") {
|
|
27656
27658
|
context.report({
|
|
27657
27659
|
node,
|
|
27658
|
-
message: "This Detox `waitFor
|
|
27660
|
+
message: "This Detox `waitFor` chain isn't awaited, so the test can continue before the condition settles. Prepend `await`."
|
|
27659
27661
|
});
|
|
27660
27662
|
return;
|
|
27661
27663
|
}
|
|
27662
27664
|
if (root.calleeName === "expect" && isDetoxExpectSubject(root.rootCall)) context.report({
|
|
27663
27665
|
node,
|
|
27664
|
-
message: "This Detox `expect(element
|
|
27666
|
+
message: "This Detox `expect(element)` assertion isn't awaited, so the test can pass or fail before the assertion settles. Prepend `await`."
|
|
27665
27667
|
});
|
|
27666
27668
|
} };
|
|
27667
27669
|
}
|
|
@@ -28292,7 +28294,7 @@ const rnNoLegacyExpoPackages = defineRule({
|
|
|
28292
28294
|
tags: ["test-noise"],
|
|
28293
28295
|
requires: ["react-native"],
|
|
28294
28296
|
severity: "warn",
|
|
28295
|
-
recommendation: "
|
|
28297
|
+
recommendation: "Switch to the maintained replacement package so users are not stuck with unfixed bugs in deprecated Expo packages.",
|
|
28296
28298
|
create: (context) => ({ ImportDeclaration(node) {
|
|
28297
28299
|
const source = node.source?.value;
|
|
28298
28300
|
if (typeof source !== "string") return;
|
|
@@ -28374,7 +28376,7 @@ const rnNoNonNativeNavigator = defineRule({
|
|
|
28374
28376
|
if (!NON_NATIVE_NAVIGATOR_PACKAGES.get(source)) return;
|
|
28375
28377
|
context.report({
|
|
28376
28378
|
node,
|
|
28377
|
-
message: `
|
|
28379
|
+
message: `Users get JS-driven transitions and gestures from ${source}, instead of platform-native navigation behavior.`
|
|
28378
28380
|
});
|
|
28379
28381
|
} })
|
|
28380
28382
|
});
|
|
@@ -28680,7 +28682,7 @@ const collectReturnedJsxElements = (expression) => {
|
|
|
28680
28682
|
};
|
|
28681
28683
|
const rnNoRenderitemKey = defineRule({
|
|
28682
28684
|
id: "rn-no-renderitem-key",
|
|
28683
|
-
title: "
|
|
28685
|
+
title: "renderItem key is ignored by React Native lists",
|
|
28684
28686
|
tags: ["test-noise"],
|
|
28685
28687
|
requires: ["react-native"],
|
|
28686
28688
|
severity: "warn",
|
|
@@ -28821,7 +28823,7 @@ const rnNoSetNativeProps = defineRule({
|
|
|
28821
28823
|
//#region src/plugin/rules/react-native/rn-no-single-element-style-array.ts
|
|
28822
28824
|
const rnNoSingleElementStyleArray = defineRule({
|
|
28823
28825
|
id: "rn-no-single-element-style-array",
|
|
28824
|
-
title: "Single-element style array",
|
|
28826
|
+
title: "Single-element style array adds wasted allocation",
|
|
28825
28827
|
tags: ["test-noise"],
|
|
28826
28828
|
requires: ["react-native"],
|
|
28827
28829
|
severity: "warn",
|
|
@@ -28844,11 +28846,11 @@ const rnNoSingleElementStyleArray = defineRule({
|
|
|
28844
28846
|
//#region src/plugin/rules/react-native/rn-prefer-content-inset-adjustment.ts
|
|
28845
28847
|
const rnPreferContentInsetAdjustment = defineRetiredRule({
|
|
28846
28848
|
id: "rn-prefer-content-inset-adjustment",
|
|
28847
|
-
title: "Manual safe-area
|
|
28849
|
+
title: "Manual safe-area insets can duplicate offsets",
|
|
28848
28850
|
tags: ["test-noise"],
|
|
28849
28851
|
requires: ["react-native"],
|
|
28850
28852
|
severity: "warn",
|
|
28851
|
-
recommendation: "
|
|
28853
|
+
recommendation: "Retired: SafeAreaView wrappers are valid; prefer native content inset adjustment only when manual inset plumbing causes scroll jumps or duplicated safe-area offsets."
|
|
28852
28854
|
});
|
|
28853
28855
|
//#endregion
|
|
28854
28856
|
//#region src/react-native-dependency-names.ts
|
|
@@ -29033,7 +29035,7 @@ const rnPreferPressable = defineRule({
|
|
|
29033
29035
|
tags: ["test-noise"],
|
|
29034
29036
|
requires: ["react-native"],
|
|
29035
29037
|
severity: "warn",
|
|
29036
|
-
recommendation: "Use `<Pressable>`
|
|
29038
|
+
recommendation: "Use `<Pressable>` because Touchable* components are frozen and lack Pressable's state-based feedback and accessibility behavior.",
|
|
29037
29039
|
create: (context) => ({ ImportDeclaration(node) {
|
|
29038
29040
|
const source = node.source?.value;
|
|
29039
29041
|
if (typeof source !== "string" || !TOUCHABLE_SOURCES.has(source)) return;
|
|
@@ -29469,7 +29471,7 @@ const roleHasRequiredAriaProps = defineRule({
|
|
|
29469
29471
|
title: "Role missing required ARIA props",
|
|
29470
29472
|
tags: ["react-jsx-only"],
|
|
29471
29473
|
severity: "error",
|
|
29472
|
-
recommendation: "Add every required `aria-*` attribute
|
|
29474
|
+
recommendation: "Add every required `aria-*` attribute so assistive tech can expose the role's state correctly.",
|
|
29473
29475
|
category: "Accessibility",
|
|
29474
29476
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
29475
29477
|
const roleAttribute = hasJsxPropIgnoreCase(node.attributes, "role");
|
|
@@ -32715,16 +32717,16 @@ const roleSupportsAriaProps = defineRule({
|
|
|
32715
32717
|
});
|
|
32716
32718
|
//#endregion
|
|
32717
32719
|
//#region src/plugin/rules/react-builtins/rules-of-hooks.ts
|
|
32718
|
-
const buildTopLevelMessage = (hookName) => `\`${hookName}\`
|
|
32719
|
-
const buildNonComponentMessage = (hookName, functionName) => `\`${hookName}\`
|
|
32720
|
-
const buildConditionalMessage = (hookName) => `\`${hookName}\`
|
|
32721
|
-
const buildLoopMessage = (hookName) => `\`${hookName}\`
|
|
32722
|
-
const buildAsyncMessage = (hookName) => `\`${hookName}\`
|
|
32723
|
-
const buildClassComponentMessage = (hookName) => `\`${hookName}\`
|
|
32724
|
-
const buildTryMessage = (hookName) => `\`${hookName}\`
|
|
32720
|
+
const buildTopLevelMessage = (hookName) => `\`${hookName}\` can only run inside a React component or custom Hook because React needs that render scope to track Hook state.`;
|
|
32721
|
+
const buildNonComponentMessage = (hookName, functionName) => `\`${hookName}\` runs inside \`${functionName}\`, which is not a component or Hook, so React cannot attach Hook state to a render.`;
|
|
32722
|
+
const buildConditionalMessage = (hookName) => `\`${hookName}\` changes Hook order between renders when called conditionally, so React can attach state to the wrong Hook.`;
|
|
32723
|
+
const buildLoopMessage = (hookName) => `\`${hookName}\` can run a different number of times inside a loop, so React can attach state to the wrong Hook.`;
|
|
32724
|
+
const buildAsyncMessage = (hookName) => `\`${hookName}\` runs inside an async function, so React cannot guarantee the same Hook order during render.`;
|
|
32725
|
+
const buildClassComponentMessage = (hookName) => `\`${hookName}\` cannot run in a class component because Hooks require a function component or custom Hook render scope.`;
|
|
32726
|
+
const buildTryMessage = (hookName) => `\`${hookName}\` can be skipped by try/catch/finally control flow, so React can attach state to the wrong Hook.`;
|
|
32725
32727
|
const buildEffectEventCallMessage = (bindingName) => `\`${bindingName}\` comes from useEffectEvent, so it only works when called from Effects in the same component.`;
|
|
32726
32728
|
const buildEffectEventAssignmentMessage = (bindingName) => `${buildEffectEventCallMessage(bindingName)} It also breaks if saved in a variable or passed around.`;
|
|
32727
|
-
const buildEffectEventPassedDownMessage = () => `A function from useEffectEvent breaks
|
|
32729
|
+
const buildEffectEventPassedDownMessage = () => `A function from useEffectEvent only works inside Effects in the same component, so passing it around breaks the event/dependency split.`;
|
|
32728
32730
|
const ASCII_UPPERCASE_A = 65;
|
|
32729
32731
|
const ASCII_UPPERCASE_Z = 90;
|
|
32730
32732
|
const EFFECT_HOOK_NAMES = new Set([
|
|
@@ -32977,7 +32979,7 @@ const rulesOfHooks = defineRule({
|
|
|
32977
32979
|
title: "Hook called conditionally",
|
|
32978
32980
|
severity: "error",
|
|
32979
32981
|
tags: ["test-noise"],
|
|
32980
|
-
recommendation: "Call hooks at the top level of a React function component or
|
|
32982
|
+
recommendation: "Call hooks at the top level of a React function component or custom Hook so React sees the same hook order on every render.",
|
|
32981
32983
|
category: "Correctness",
|
|
32982
32984
|
create: (context) => {
|
|
32983
32985
|
const settings = resolveSettings$3(context.settings);
|
|
@@ -33105,13 +33107,13 @@ const rulesOfHooks = defineRule({
|
|
|
33105
33107
|
});
|
|
33106
33108
|
//#endregion
|
|
33107
33109
|
//#region src/plugin/rules/a11y/scope.ts
|
|
33108
|
-
const MESSAGE$3 = "
|
|
33110
|
+
const MESSAGE$3 = "The `scope` attribute only works on `<th>` cells, so screen readers get no table-header help from it here.";
|
|
33109
33111
|
const scope = defineRule({
|
|
33110
33112
|
id: "scope",
|
|
33111
33113
|
title: "scope attribute on non-th element",
|
|
33112
33114
|
tags: ["react-jsx-only"],
|
|
33113
33115
|
severity: "warn",
|
|
33114
|
-
recommendation: "
|
|
33116
|
+
recommendation: "Remove `scope` from this element or move it to the related `<th>` cell.",
|
|
33115
33117
|
category: "Accessibility",
|
|
33116
33118
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
33117
33119
|
const scopeAttribute = hasJsxProp(node.attributes, "scope");
|
|
@@ -33126,7 +33128,7 @@ const scope = defineRule({
|
|
|
33126
33128
|
});
|
|
33127
33129
|
//#endregion
|
|
33128
33130
|
//#region src/plugin/rules/react-builtins/self-closing-comp.ts
|
|
33129
|
-
const MESSAGE$2 = "This tag has no children.";
|
|
33131
|
+
const MESSAGE$2 = "This tag has no children, so the closing tag adds noise without changing output.";
|
|
33130
33132
|
const resolveSettings$2 = (settings) => {
|
|
33131
33133
|
const reactDoctor = settings?.["react-doctor"];
|
|
33132
33134
|
const ruleSettings = typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.selfClosingComp ?? {} : {};
|
|
@@ -33145,7 +33147,7 @@ const selfClosingComp = defineRule({
|
|
|
33145
33147
|
title: "Element not self-closing",
|
|
33146
33148
|
severity: "warn",
|
|
33147
33149
|
defaultEnabled: false,
|
|
33148
|
-
recommendation: "Use
|
|
33150
|
+
recommendation: "Use `<X />` for childless elements so empty closing tags do not add noise.",
|
|
33149
33151
|
category: "Architecture",
|
|
33150
33152
|
create: (context) => {
|
|
33151
33153
|
const settings = resolveSettings$2(context.settings);
|
|
@@ -33342,9 +33344,9 @@ const getCandidateFromDefaultDeclaration = (node) => {
|
|
|
33342
33344
|
};
|
|
33343
33345
|
const serverAuthActions = defineRule({
|
|
33344
33346
|
id: "server-auth-actions",
|
|
33345
|
-
title: "
|
|
33347
|
+
title: "Unauthenticated server action can be called directly",
|
|
33346
33348
|
severity: "error",
|
|
33347
|
-
recommendation: "
|
|
33349
|
+
recommendation: "Check auth before touching data because exported server actions can be called directly by unauthenticated clients.",
|
|
33348
33350
|
create: (context) => {
|
|
33349
33351
|
let fileHasUseServerDirective = false;
|
|
33350
33352
|
const customAuthFunctionNames = getReactDoctorStringArraySetting(context.settings, "serverAuthFunctionNames");
|
|
@@ -33725,8 +33727,8 @@ const serverSequentialIndependentAwait = defineRule({
|
|
|
33725
33727
|
});
|
|
33726
33728
|
//#endregion
|
|
33727
33729
|
//#region src/plugin/rules/react-builtins/state-in-constructor.ts
|
|
33728
|
-
const ALWAYS_MESSAGE = "This
|
|
33729
|
-
const NEVER_MESSAGE = "This
|
|
33730
|
+
const ALWAYS_MESSAGE = "This class uses a state field instead of the configured constructor pattern, so state setup is inconsistent across the codebase.";
|
|
33731
|
+
const NEVER_MESSAGE = "This class sets state in the constructor instead of the configured class-field pattern, so state setup is inconsistent across the codebase.";
|
|
33730
33732
|
const resolveSettings$1 = (settings) => {
|
|
33731
33733
|
const reactDoctor = settings?.["react-doctor"];
|
|
33732
33734
|
return { mode: (typeof reactDoctor === "object" && reactDoctor !== null ? reactDoctor.stateInConstructor ?? {} : {}).mode ?? "always" };
|
|
@@ -33758,7 +33760,7 @@ const stateInConstructor = defineRule({
|
|
|
33758
33760
|
title: "State initialized in constructor",
|
|
33759
33761
|
severity: "warn",
|
|
33760
33762
|
defaultEnabled: false,
|
|
33761
|
-
recommendation: "
|
|
33763
|
+
recommendation: "Use one class-state setup pattern so readers know where initial state lives.",
|
|
33762
33764
|
category: "Architecture",
|
|
33763
33765
|
create: (context) => {
|
|
33764
33766
|
const { mode } = resolveSettings$1(context.settings);
|
|
@@ -33861,7 +33863,7 @@ const stylePropObject = defineRule({
|
|
|
33861
33863
|
id: "style-prop-object",
|
|
33862
33864
|
title: "Style prop is not an object",
|
|
33863
33865
|
severity: "warn",
|
|
33864
|
-
recommendation: "Pass
|
|
33866
|
+
recommendation: "Pass `style` as an object so React can apply CSS properties instead of ignoring a string style value.",
|
|
33865
33867
|
category: "Correctness",
|
|
33866
33868
|
create: (context) => {
|
|
33867
33869
|
const { allow } = resolveSettings(context.settings);
|
|
@@ -34207,11 +34209,11 @@ const tanstackStartMissingHeadContent = defineRule({
|
|
|
34207
34209
|
//#region src/plugin/rules/tanstack-start/tanstack-start-no-anchor-element.ts
|
|
34208
34210
|
const tanstackStartNoAnchorElement = defineRule({
|
|
34209
34211
|
id: "tanstack-start-no-anchor-element",
|
|
34210
|
-
title: "Plain anchor
|
|
34212
|
+
title: "Plain anchor reloads TanStack Router navigation",
|
|
34211
34213
|
tags: ["test-noise"],
|
|
34212
34214
|
requires: ["tanstack-start"],
|
|
34213
34215
|
severity: "warn",
|
|
34214
|
-
recommendation: "`
|
|
34216
|
+
recommendation: "Use `Link` from `@tanstack/react-router` so internal navigation keeps client state, preloading, and typed routes.",
|
|
34215
34217
|
create: (context) => ({ JSXOpeningElement(node) {
|
|
34216
34218
|
const filename = normalizeFilename$1(context.filename ?? "");
|
|
34217
34219
|
if (!TANSTACK_ROUTE_FILE_PATTERN.test(filename)) return;
|
|
@@ -34224,7 +34226,7 @@ const tanstackStartNoAnchorElement = defineRule({
|
|
|
34224
34226
|
else if (isNodeOfType(hrefAttribute.value, "JSXExpressionContainer") && isNodeOfType(hrefAttribute.value.expression, "Literal")) hrefValue = hrefAttribute.value.expression.value;
|
|
34225
34227
|
if (typeof hrefValue === "string" && hrefValue.startsWith("/")) context.report({
|
|
34226
34228
|
node,
|
|
34227
|
-
message: "Plain <a> reloads the whole page
|
|
34229
|
+
message: "Plain <a> reloads the whole page for internal navigation, so TanStack Router loses client state and preloading."
|
|
34228
34230
|
});
|
|
34229
34231
|
} })
|
|
34230
34232
|
});
|
|
@@ -34296,7 +34298,7 @@ const tanstackStartNoNavigateInRender = defineRule({
|
|
|
34296
34298
|
if (deferredCallbackDepth > 0 || eventHandlerDepth > 0) return;
|
|
34297
34299
|
if (isNodeOfType(node.callee, "Identifier") && node.callee.name === "navigate" && (node.arguments?.length ?? 0) > 0) context.report({
|
|
34298
34300
|
node,
|
|
34299
|
-
message: "navigate() during render
|
|
34301
|
+
message: "navigate() runs during render here, so server and browser output can diverge during hydration."
|
|
34300
34302
|
});
|
|
34301
34303
|
},
|
|
34302
34304
|
"CallExpression:exit"(node) {
|
|
@@ -34380,7 +34382,7 @@ const tanstackStartNoUseServerInHandler = defineRule({
|
|
|
34380
34382
|
if (!isNodeOfType(body, "BlockStatement")) return;
|
|
34381
34383
|
if (body.body?.some((statement) => isNodeOfType(statement, "ExpressionStatement") && (statement.directive === "use server" || isNodeOfType(statement.expression, "Literal") && statement.expression.value === "use server"))) context.report({
|
|
34382
34384
|
node: handlerFunction,
|
|
34383
|
-
message: "\"use server\" inside a createServerFn handler
|
|
34385
|
+
message: "\"use server\" inside a createServerFn handler duplicates TanStack Start's server boundary, so the route can fail to compile."
|
|
34384
34386
|
});
|
|
34385
34387
|
} })
|
|
34386
34388
|
});
|
|
@@ -34454,11 +34456,11 @@ const tanstackStartRedirectInTryCatch = defineRule({
|
|
|
34454
34456
|
//#region src/plugin/rules/tanstack-start/tanstack-start-route-property-order.ts
|
|
34455
34457
|
const tanstackStartRoutePropertyOrder = defineRule({
|
|
34456
34458
|
id: "tanstack-start-route-property-order",
|
|
34457
|
-
title: "
|
|
34459
|
+
title: "Route property order breaks type inference",
|
|
34458
34460
|
tags: ["test-noise"],
|
|
34459
34461
|
requires: ["tanstack-start"],
|
|
34460
34462
|
severity: "error",
|
|
34461
|
-
recommendation: "Follow the order
|
|
34463
|
+
recommendation: "Follow the route property order because TanStack Router's type inference depends on earlier properties feeding later ones.",
|
|
34462
34464
|
create: (context) => ({ CallExpression(node) {
|
|
34463
34465
|
const optionsObject = getRouteOptionsObject(node);
|
|
34464
34466
|
if (!optionsObject) return;
|
|
@@ -34488,7 +34490,7 @@ const tanstackStartRoutePropertyOrder = defineRule({
|
|
|
34488
34490
|
//#region src/plugin/rules/tanstack-start/tanstack-start-server-fn-method-order.ts
|
|
34489
34491
|
const tanstackStartServerFnMethodOrder = defineRule({
|
|
34490
34492
|
id: "tanstack-start-server-fn-method-order",
|
|
34491
|
-
title: "
|
|
34493
|
+
title: "Server function method order breaks type inference",
|
|
34492
34494
|
tags: ["test-noise"],
|
|
34493
34495
|
requires: ["tanstack-start"],
|
|
34494
34496
|
severity: "error",
|
|
@@ -34569,7 +34571,7 @@ const useLazyMotion = defineRule({
|
|
|
34569
34571
|
return getImportedName$1(specifier) === "motion";
|
|
34570
34572
|
})) context.report({
|
|
34571
34573
|
node,
|
|
34572
|
-
message: "Importing \"motion\" ships about 30 kb of extra code
|
|
34574
|
+
message: "Importing \"motion\" ships about 30 kb of extra code and slows page load. Use \"m\" with LazyMotion instead."
|
|
34573
34575
|
});
|
|
34574
34576
|
} })
|
|
34575
34577
|
});
|
|
@@ -34606,7 +34608,7 @@ const voidDomElementsNoChildren = defineRule({
|
|
|
34606
34608
|
id: "void-dom-elements-no-children",
|
|
34607
34609
|
title: "Children on a void element",
|
|
34608
34610
|
severity: "warn",
|
|
34609
|
-
recommendation: "Remove the children
|
|
34611
|
+
recommendation: "Remove the children or use a non-void tag so React does not drop content the element cannot render.",
|
|
34610
34612
|
create: (context) => ({
|
|
34611
34613
|
JSXElement(node) {
|
|
34612
34614
|
const openingElement = node.openingElement;
|
|
@@ -34754,7 +34756,7 @@ const DEPRECATED_ZOD_ERROR_MEMBERS = new Set([
|
|
|
34754
34756
|
"formErrors",
|
|
34755
34757
|
"format"
|
|
34756
34758
|
]);
|
|
34757
|
-
const ZOD_ERROR_API_MESSAGE = "
|
|
34759
|
+
const ZOD_ERROR_API_MESSAGE = "This ZodError API was removed in Zod 4, so error handling can break during the upgrade.";
|
|
34758
34760
|
const isZodErrorReference = (node) => {
|
|
34759
34761
|
const inner = stripParenExpression(node);
|
|
34760
34762
|
if (isNodeOfType(inner, "Identifier")) return getZodNamedImport(inner) === "ZodError";
|
|
@@ -34786,7 +34788,7 @@ const isReceiverOfDeprecatedZodErrorMember = (callExpression) => {
|
|
|
34786
34788
|
};
|
|
34787
34789
|
const zodV4NoDeprecatedErrorApis = defineRule({
|
|
34788
34790
|
id: "zod-v4-no-deprecated-error-apis",
|
|
34789
|
-
title: "
|
|
34791
|
+
title: "Zod 3 error API breaks in Zod 4",
|
|
34790
34792
|
requires: ["zod:4"],
|
|
34791
34793
|
tags: ["migration-hint"],
|
|
34792
34794
|
severity: "warn",
|
|
@@ -34875,7 +34877,7 @@ const parseCallUsesErrorMap = (callExpression) => {
|
|
|
34875
34877
|
};
|
|
34876
34878
|
const zodV4NoDeprecatedErrorCustomization = defineRule({
|
|
34877
34879
|
id: "zod-v4-no-deprecated-error-customization",
|
|
34878
|
-
title: "
|
|
34880
|
+
title: "Zod 3 error customization breaks in Zod 4",
|
|
34879
34881
|
requires: ["zod:4"],
|
|
34880
34882
|
tags: ["migration-hint"],
|
|
34881
34883
|
severity: "warn",
|
|
@@ -34884,7 +34886,7 @@ const zodV4NoDeprecatedErrorCustomization = defineRule({
|
|
|
34884
34886
|
if (!factoryUsesDeprecatedErrorParameter(node) && !parseCallUsesErrorMap(node)) return;
|
|
34885
34887
|
context.report({
|
|
34886
34888
|
node,
|
|
34887
|
-
message: "Zod
|
|
34889
|
+
message: "This Zod 3 error-customization form is not compatible with Zod 4, so custom messages can stop applying during the upgrade."
|
|
34888
34890
|
});
|
|
34889
34891
|
} })
|
|
34890
34892
|
});
|
|
@@ -34944,7 +34946,7 @@ const LITERAL_FACTORY = new Set(["literal"]);
|
|
|
34944
34946
|
const reportSchemaMigration = (context, node) => {
|
|
34945
34947
|
context.report({
|
|
34946
34948
|
node,
|
|
34947
|
-
message: "Zod
|
|
34949
|
+
message: "This Zod 3 schema API changed in Zod 4, so this schema can fail after the upgrade."
|
|
34948
34950
|
});
|
|
34949
34951
|
};
|
|
34950
34952
|
const isCallToDeprecatedTopLevelFactory = (callExpression) => isZodFactoryCall(callExpression, DEPRECATED_TOP_LEVEL_FACTORIES);
|
|
@@ -34996,7 +34998,7 @@ const isZodNamespaceImportMemberCreate = (memberExpression) => {
|
|
|
34996
34998
|
};
|
|
34997
34999
|
const zodV4NoDeprecatedSchemaApis = defineRule({
|
|
34998
35000
|
id: "zod-v4-no-deprecated-schema-apis",
|
|
34999
|
-
title: "
|
|
35001
|
+
title: "Zod 3 schema API breaks in Zod 4",
|
|
35000
35002
|
requires: ["zod:4"],
|
|
35001
35003
|
tags: ["migration-hint"],
|
|
35002
35004
|
severity: "warn",
|
|
@@ -35049,7 +35051,7 @@ const zodV4PreferTopLevelStringFormats = defineRule({
|
|
|
35049
35051
|
if (!isDirectMethodCallOnZodFactory(node, ZOD_STRING_FACTORY, STRING_FORMAT_METHODS)) return;
|
|
35050
35052
|
context.report({
|
|
35051
35053
|
node,
|
|
35052
|
-
message: "
|
|
35054
|
+
message: "This `z.string().<format>()` check is deprecated in Zod 4, so it can break during the upgrade."
|
|
35053
35055
|
});
|
|
35054
35056
|
} })
|
|
35055
35057
|
});
|
|
@@ -35064,7 +35066,8 @@ const reactDoctorRules = [
|
|
|
35064
35066
|
rule: {
|
|
35065
35067
|
...activityWrapsEffectHeavySubtree,
|
|
35066
35068
|
framework: "global",
|
|
35067
|
-
category: "Bugs"
|
|
35069
|
+
category: "Bugs",
|
|
35070
|
+
requires: [...new Set(["react", ...activityWrapsEffectHeavySubtree.requires ?? []])]
|
|
35068
35071
|
}
|
|
35069
35072
|
},
|
|
35070
35073
|
{
|
|
@@ -35075,7 +35078,8 @@ const reactDoctorRules = [
|
|
|
35075
35078
|
rule: {
|
|
35076
35079
|
...advancedEventHandlerRefs,
|
|
35077
35080
|
framework: "global",
|
|
35078
|
-
category: "Performance"
|
|
35081
|
+
category: "Performance",
|
|
35082
|
+
requires: [...new Set(["react", ...advancedEventHandlerRefs.requires ?? []])]
|
|
35079
35083
|
}
|
|
35080
35084
|
},
|
|
35081
35085
|
{
|
|
@@ -35086,7 +35090,8 @@ const reactDoctorRules = [
|
|
|
35086
35090
|
rule: {
|
|
35087
35091
|
...altText,
|
|
35088
35092
|
framework: "global",
|
|
35089
|
-
category: "Accessibility"
|
|
35093
|
+
category: "Accessibility",
|
|
35094
|
+
requires: [...new Set(["react", ...altText.requires ?? []])]
|
|
35090
35095
|
}
|
|
35091
35096
|
},
|
|
35092
35097
|
{
|
|
@@ -35097,7 +35102,8 @@ const reactDoctorRules = [
|
|
|
35097
35102
|
rule: {
|
|
35098
35103
|
...anchorAmbiguousText,
|
|
35099
35104
|
framework: "global",
|
|
35100
|
-
category: "Accessibility"
|
|
35105
|
+
category: "Accessibility",
|
|
35106
|
+
requires: [...new Set(["react", ...anchorAmbiguousText.requires ?? []])]
|
|
35101
35107
|
}
|
|
35102
35108
|
},
|
|
35103
35109
|
{
|
|
@@ -35108,7 +35114,8 @@ const reactDoctorRules = [
|
|
|
35108
35114
|
rule: {
|
|
35109
35115
|
...anchorHasContent,
|
|
35110
35116
|
framework: "global",
|
|
35111
|
-
category: "Accessibility"
|
|
35117
|
+
category: "Accessibility",
|
|
35118
|
+
requires: [...new Set(["react", ...anchorHasContent.requires ?? []])]
|
|
35112
35119
|
}
|
|
35113
35120
|
},
|
|
35114
35121
|
{
|
|
@@ -35119,7 +35126,8 @@ const reactDoctorRules = [
|
|
|
35119
35126
|
rule: {
|
|
35120
35127
|
...anchorIsValid,
|
|
35121
35128
|
framework: "global",
|
|
35122
|
-
category: "Accessibility"
|
|
35129
|
+
category: "Accessibility",
|
|
35130
|
+
requires: [...new Set(["react", ...anchorIsValid.requires ?? []])]
|
|
35123
35131
|
}
|
|
35124
35132
|
},
|
|
35125
35133
|
{
|
|
@@ -35130,7 +35138,8 @@ const reactDoctorRules = [
|
|
|
35130
35138
|
rule: {
|
|
35131
35139
|
...ariaActivedescendantHasTabindex,
|
|
35132
35140
|
framework: "global",
|
|
35133
|
-
category: "Accessibility"
|
|
35141
|
+
category: "Accessibility",
|
|
35142
|
+
requires: [...new Set(["react", ...ariaActivedescendantHasTabindex.requires ?? []])]
|
|
35134
35143
|
}
|
|
35135
35144
|
},
|
|
35136
35145
|
{
|
|
@@ -35141,7 +35150,8 @@ const reactDoctorRules = [
|
|
|
35141
35150
|
rule: {
|
|
35142
35151
|
...ariaProps,
|
|
35143
35152
|
framework: "global",
|
|
35144
|
-
category: "Accessibility"
|
|
35153
|
+
category: "Accessibility",
|
|
35154
|
+
requires: [...new Set(["react", ...ariaProps.requires ?? []])]
|
|
35145
35155
|
}
|
|
35146
35156
|
},
|
|
35147
35157
|
{
|
|
@@ -35152,7 +35162,8 @@ const reactDoctorRules = [
|
|
|
35152
35162
|
rule: {
|
|
35153
35163
|
...ariaProptypes,
|
|
35154
35164
|
framework: "global",
|
|
35155
|
-
category: "Accessibility"
|
|
35165
|
+
category: "Accessibility",
|
|
35166
|
+
requires: [...new Set(["react", ...ariaProptypes.requires ?? []])]
|
|
35156
35167
|
}
|
|
35157
35168
|
},
|
|
35158
35169
|
{
|
|
@@ -35163,7 +35174,8 @@ const reactDoctorRules = [
|
|
|
35163
35174
|
rule: {
|
|
35164
35175
|
...ariaRole,
|
|
35165
35176
|
framework: "global",
|
|
35166
|
-
category: "Accessibility"
|
|
35177
|
+
category: "Accessibility",
|
|
35178
|
+
requires: [...new Set(["react", ...ariaRole.requires ?? []])]
|
|
35167
35179
|
}
|
|
35168
35180
|
},
|
|
35169
35181
|
{
|
|
@@ -35174,7 +35186,8 @@ const reactDoctorRules = [
|
|
|
35174
35186
|
rule: {
|
|
35175
35187
|
...ariaUnsupportedElements,
|
|
35176
35188
|
framework: "global",
|
|
35177
|
-
category: "Accessibility"
|
|
35189
|
+
category: "Accessibility",
|
|
35190
|
+
requires: [...new Set(["react", ...ariaUnsupportedElements.requires ?? []])]
|
|
35178
35191
|
}
|
|
35179
35192
|
},
|
|
35180
35193
|
{
|
|
@@ -35196,7 +35209,8 @@ const reactDoctorRules = [
|
|
|
35196
35209
|
rule: {
|
|
35197
35210
|
...asyncDeferAwait,
|
|
35198
35211
|
framework: "global",
|
|
35199
|
-
category: "Performance"
|
|
35212
|
+
category: "Performance",
|
|
35213
|
+
requires: [...new Set(["react", ...asyncDeferAwait.requires ?? []])]
|
|
35200
35214
|
}
|
|
35201
35215
|
},
|
|
35202
35216
|
{
|
|
@@ -35218,7 +35232,8 @@ const reactDoctorRules = [
|
|
|
35218
35232
|
rule: {
|
|
35219
35233
|
...autocompleteValid,
|
|
35220
35234
|
framework: "global",
|
|
35221
|
-
category: "Accessibility"
|
|
35235
|
+
category: "Accessibility",
|
|
35236
|
+
requires: [...new Set(["react", ...autocompleteValid.requires ?? []])]
|
|
35222
35237
|
}
|
|
35223
35238
|
},
|
|
35224
35239
|
{
|
|
@@ -35229,7 +35244,8 @@ const reactDoctorRules = [
|
|
|
35229
35244
|
rule: {
|
|
35230
35245
|
...buttonHasType,
|
|
35231
35246
|
framework: "global",
|
|
35232
|
-
category: "Bugs"
|
|
35247
|
+
category: "Bugs",
|
|
35248
|
+
requires: [...new Set(["react", ...buttonHasType.requires ?? []])]
|
|
35233
35249
|
}
|
|
35234
35250
|
},
|
|
35235
35251
|
{
|
|
@@ -35240,7 +35256,8 @@ const reactDoctorRules = [
|
|
|
35240
35256
|
rule: {
|
|
35241
35257
|
...checkedRequiresOnchangeOrReadonly,
|
|
35242
35258
|
framework: "global",
|
|
35243
|
-
category: "Bugs"
|
|
35259
|
+
category: "Bugs",
|
|
35260
|
+
requires: [...new Set(["react", ...checkedRequiresOnchangeOrReadonly.requires ?? []])]
|
|
35244
35261
|
}
|
|
35245
35262
|
},
|
|
35246
35263
|
{
|
|
@@ -35251,7 +35268,8 @@ const reactDoctorRules = [
|
|
|
35251
35268
|
rule: {
|
|
35252
35269
|
...clickEventsHaveKeyEvents,
|
|
35253
35270
|
framework: "global",
|
|
35254
|
-
category: "Accessibility"
|
|
35271
|
+
category: "Accessibility",
|
|
35272
|
+
requires: [...new Set(["react", ...clickEventsHaveKeyEvents.requires ?? []])]
|
|
35255
35273
|
}
|
|
35256
35274
|
},
|
|
35257
35275
|
{
|
|
@@ -35262,7 +35280,8 @@ const reactDoctorRules = [
|
|
|
35262
35280
|
rule: {
|
|
35263
35281
|
...clientLocalstorageNoVersion,
|
|
35264
35282
|
framework: "global",
|
|
35265
|
-
category: "Bugs"
|
|
35283
|
+
category: "Bugs",
|
|
35284
|
+
requires: [...new Set(["react", ...clientLocalstorageNoVersion.requires ?? []])]
|
|
35266
35285
|
}
|
|
35267
35286
|
},
|
|
35268
35287
|
{
|
|
@@ -35273,7 +35292,8 @@ const reactDoctorRules = [
|
|
|
35273
35292
|
rule: {
|
|
35274
35293
|
...clientPassiveEventListeners,
|
|
35275
35294
|
framework: "global",
|
|
35276
|
-
category: "Performance"
|
|
35295
|
+
category: "Performance",
|
|
35296
|
+
requires: [...new Set(["react", ...clientPassiveEventListeners.requires ?? []])]
|
|
35277
35297
|
}
|
|
35278
35298
|
},
|
|
35279
35299
|
{
|
|
@@ -35284,7 +35304,8 @@ const reactDoctorRules = [
|
|
|
35284
35304
|
rule: {
|
|
35285
35305
|
...controlHasAssociatedLabel,
|
|
35286
35306
|
framework: "global",
|
|
35287
|
-
category: "Accessibility"
|
|
35307
|
+
category: "Accessibility",
|
|
35308
|
+
requires: [...new Set(["react", ...controlHasAssociatedLabel.requires ?? []])]
|
|
35288
35309
|
}
|
|
35289
35310
|
},
|
|
35290
35311
|
{
|
|
@@ -35295,7 +35316,8 @@ const reactDoctorRules = [
|
|
|
35295
35316
|
rule: {
|
|
35296
35317
|
...noEmDashInJsxText,
|
|
35297
35318
|
framework: "global",
|
|
35298
|
-
category: "Maintainability"
|
|
35319
|
+
category: "Maintainability",
|
|
35320
|
+
requires: [...new Set(["react", ...noEmDashInJsxText.requires ?? []])]
|
|
35299
35321
|
}
|
|
35300
35322
|
},
|
|
35301
35323
|
{
|
|
@@ -35306,7 +35328,8 @@ const reactDoctorRules = [
|
|
|
35306
35328
|
rule: {
|
|
35307
35329
|
...noRedundantPaddingAxes,
|
|
35308
35330
|
framework: "global",
|
|
35309
|
-
category: "Maintainability"
|
|
35331
|
+
category: "Maintainability",
|
|
35332
|
+
requires: [...new Set(["react", ...noRedundantPaddingAxes.requires ?? []])]
|
|
35310
35333
|
}
|
|
35311
35334
|
},
|
|
35312
35335
|
{
|
|
@@ -35317,7 +35340,8 @@ const reactDoctorRules = [
|
|
|
35317
35340
|
rule: {
|
|
35318
35341
|
...noRedundantSizeAxes,
|
|
35319
35342
|
framework: "global",
|
|
35320
|
-
category: "Maintainability"
|
|
35343
|
+
category: "Maintainability",
|
|
35344
|
+
requires: [...new Set(["react", ...noRedundantSizeAxes.requires ?? []])]
|
|
35321
35345
|
}
|
|
35322
35346
|
},
|
|
35323
35347
|
{
|
|
@@ -35328,7 +35352,8 @@ const reactDoctorRules = [
|
|
|
35328
35352
|
rule: {
|
|
35329
35353
|
...noSpaceOnFlexChildren,
|
|
35330
35354
|
framework: "global",
|
|
35331
|
-
category: "Maintainability"
|
|
35355
|
+
category: "Maintainability",
|
|
35356
|
+
requires: [...new Set(["react", ...noSpaceOnFlexChildren.requires ?? []])]
|
|
35332
35357
|
}
|
|
35333
35358
|
},
|
|
35334
35359
|
{
|
|
@@ -35339,7 +35364,8 @@ const reactDoctorRules = [
|
|
|
35339
35364
|
rule: {
|
|
35340
35365
|
...noThreePeriodEllipsis,
|
|
35341
35366
|
framework: "global",
|
|
35342
|
-
category: "Maintainability"
|
|
35367
|
+
category: "Maintainability",
|
|
35368
|
+
requires: [...new Set(["react", ...noThreePeriodEllipsis.requires ?? []])]
|
|
35343
35369
|
}
|
|
35344
35370
|
},
|
|
35345
35371
|
{
|
|
@@ -35350,7 +35376,8 @@ const reactDoctorRules = [
|
|
|
35350
35376
|
rule: {
|
|
35351
35377
|
...noVagueButtonLabel,
|
|
35352
35378
|
framework: "global",
|
|
35353
|
-
category: "Accessibility"
|
|
35379
|
+
category: "Accessibility",
|
|
35380
|
+
requires: [...new Set(["react", ...noVagueButtonLabel.requires ?? []])]
|
|
35354
35381
|
}
|
|
35355
35382
|
},
|
|
35356
35383
|
{
|
|
@@ -35361,7 +35388,8 @@ const reactDoctorRules = [
|
|
|
35361
35388
|
rule: {
|
|
35362
35389
|
...displayName,
|
|
35363
35390
|
framework: "global",
|
|
35364
|
-
category: "Maintainability"
|
|
35391
|
+
category: "Maintainability",
|
|
35392
|
+
requires: [...new Set(["react", ...displayName.requires ?? []])]
|
|
35365
35393
|
}
|
|
35366
35394
|
},
|
|
35367
35395
|
{
|
|
@@ -35372,7 +35400,8 @@ const reactDoctorRules = [
|
|
|
35372
35400
|
rule: {
|
|
35373
35401
|
...effectNeedsCleanup,
|
|
35374
35402
|
framework: "global",
|
|
35375
|
-
category: "Bugs"
|
|
35403
|
+
category: "Bugs",
|
|
35404
|
+
requires: [...new Set(["react", ...effectNeedsCleanup.requires ?? []])]
|
|
35376
35405
|
}
|
|
35377
35406
|
},
|
|
35378
35407
|
{
|
|
@@ -35383,7 +35412,8 @@ const reactDoctorRules = [
|
|
|
35383
35412
|
rule: {
|
|
35384
35413
|
...exhaustiveDeps,
|
|
35385
35414
|
framework: "global",
|
|
35386
|
-
category: "Bugs"
|
|
35415
|
+
category: "Bugs",
|
|
35416
|
+
requires: [...new Set(["react", ...exhaustiveDeps.requires ?? []])]
|
|
35387
35417
|
}
|
|
35388
35418
|
},
|
|
35389
35419
|
{
|
|
@@ -35406,7 +35436,8 @@ const reactDoctorRules = [
|
|
|
35406
35436
|
rule: {
|
|
35407
35437
|
...forbidComponentProps,
|
|
35408
35438
|
framework: "global",
|
|
35409
|
-
category: "Maintainability"
|
|
35439
|
+
category: "Maintainability",
|
|
35440
|
+
requires: [...new Set(["react", ...forbidComponentProps.requires ?? []])]
|
|
35410
35441
|
}
|
|
35411
35442
|
},
|
|
35412
35443
|
{
|
|
@@ -35417,7 +35448,8 @@ const reactDoctorRules = [
|
|
|
35417
35448
|
rule: {
|
|
35418
35449
|
...forbidDomProps,
|
|
35419
35450
|
framework: "global",
|
|
35420
|
-
category: "Maintainability"
|
|
35451
|
+
category: "Maintainability",
|
|
35452
|
+
requires: [...new Set(["react", ...forbidDomProps.requires ?? []])]
|
|
35421
35453
|
}
|
|
35422
35454
|
},
|
|
35423
35455
|
{
|
|
@@ -35428,7 +35460,8 @@ const reactDoctorRules = [
|
|
|
35428
35460
|
rule: {
|
|
35429
35461
|
...forbidElements,
|
|
35430
35462
|
framework: "global",
|
|
35431
|
-
category: "Maintainability"
|
|
35463
|
+
category: "Maintainability",
|
|
35464
|
+
requires: [...new Set(["react", ...forbidElements.requires ?? []])]
|
|
35432
35465
|
}
|
|
35433
35466
|
},
|
|
35434
35467
|
{
|
|
@@ -35439,7 +35472,8 @@ const reactDoctorRules = [
|
|
|
35439
35472
|
rule: {
|
|
35440
35473
|
...forwardRefUsesRef,
|
|
35441
35474
|
framework: "global",
|
|
35442
|
-
category: "Maintainability"
|
|
35475
|
+
category: "Maintainability",
|
|
35476
|
+
requires: [...new Set(["react", ...forwardRefUsesRef.requires ?? []])]
|
|
35443
35477
|
}
|
|
35444
35478
|
},
|
|
35445
35479
|
{
|
|
@@ -35450,7 +35484,8 @@ const reactDoctorRules = [
|
|
|
35450
35484
|
rule: {
|
|
35451
35485
|
...headingHasContent,
|
|
35452
35486
|
framework: "global",
|
|
35453
|
-
category: "Accessibility"
|
|
35487
|
+
category: "Accessibility",
|
|
35488
|
+
requires: [...new Set(["react", ...headingHasContent.requires ?? []])]
|
|
35454
35489
|
}
|
|
35455
35490
|
},
|
|
35456
35491
|
{
|
|
@@ -35461,7 +35496,8 @@ const reactDoctorRules = [
|
|
|
35461
35496
|
rule: {
|
|
35462
35497
|
...hookUseState,
|
|
35463
35498
|
framework: "global",
|
|
35464
|
-
category: "Maintainability"
|
|
35499
|
+
category: "Maintainability",
|
|
35500
|
+
requires: [...new Set(["react", ...hookUseState.requires ?? []])]
|
|
35465
35501
|
}
|
|
35466
35502
|
},
|
|
35467
35503
|
{
|
|
@@ -35472,7 +35508,8 @@ const reactDoctorRules = [
|
|
|
35472
35508
|
rule: {
|
|
35473
35509
|
...hooksNoNanInDeps,
|
|
35474
35510
|
framework: "global",
|
|
35475
|
-
category: "Bugs"
|
|
35511
|
+
category: "Bugs",
|
|
35512
|
+
requires: [...new Set(["react", ...hooksNoNanInDeps.requires ?? []])]
|
|
35476
35513
|
}
|
|
35477
35514
|
},
|
|
35478
35515
|
{
|
|
@@ -35483,7 +35520,8 @@ const reactDoctorRules = [
|
|
|
35483
35520
|
rule: {
|
|
35484
35521
|
...htmlHasLang,
|
|
35485
35522
|
framework: "global",
|
|
35486
|
-
category: "Accessibility"
|
|
35523
|
+
category: "Accessibility",
|
|
35524
|
+
requires: [...new Set(["react", ...htmlHasLang.requires ?? []])]
|
|
35487
35525
|
}
|
|
35488
35526
|
},
|
|
35489
35527
|
{
|
|
@@ -35527,7 +35565,8 @@ const reactDoctorRules = [
|
|
|
35527
35565
|
rule: {
|
|
35528
35566
|
...iframeHasTitle,
|
|
35529
35567
|
framework: "global",
|
|
35530
|
-
category: "Accessibility"
|
|
35568
|
+
category: "Accessibility",
|
|
35569
|
+
requires: [...new Set(["react", ...iframeHasTitle.requires ?? []])]
|
|
35531
35570
|
}
|
|
35532
35571
|
},
|
|
35533
35572
|
{
|
|
@@ -35538,7 +35577,8 @@ const reactDoctorRules = [
|
|
|
35538
35577
|
rule: {
|
|
35539
35578
|
...iframeMissingSandbox,
|
|
35540
35579
|
framework: "global",
|
|
35541
|
-
category: "Security"
|
|
35580
|
+
category: "Security",
|
|
35581
|
+
requires: [...new Set(["react", ...iframeMissingSandbox.requires ?? []])]
|
|
35542
35582
|
}
|
|
35543
35583
|
},
|
|
35544
35584
|
{
|
|
@@ -35549,7 +35589,8 @@ const reactDoctorRules = [
|
|
|
35549
35589
|
rule: {
|
|
35550
35590
|
...imgRedundantAlt,
|
|
35551
35591
|
framework: "global",
|
|
35552
|
-
category: "Accessibility"
|
|
35592
|
+
category: "Accessibility",
|
|
35593
|
+
requires: [...new Set(["react", ...imgRedundantAlt.requires ?? []])]
|
|
35553
35594
|
}
|
|
35554
35595
|
},
|
|
35555
35596
|
{
|
|
@@ -35560,7 +35601,8 @@ const reactDoctorRules = [
|
|
|
35560
35601
|
rule: {
|
|
35561
35602
|
...interactiveSupportsFocus,
|
|
35562
35603
|
framework: "global",
|
|
35563
|
-
category: "Accessibility"
|
|
35604
|
+
category: "Accessibility",
|
|
35605
|
+
requires: [...new Set(["react", ...interactiveSupportsFocus.requires ?? []])]
|
|
35564
35606
|
}
|
|
35565
35607
|
},
|
|
35566
35608
|
{
|
|
@@ -35571,7 +35613,8 @@ const reactDoctorRules = [
|
|
|
35571
35613
|
rule: {
|
|
35572
35614
|
...jotaiDerivedAtomReturnsFreshObject,
|
|
35573
35615
|
framework: "global",
|
|
35574
|
-
category: "Bugs"
|
|
35616
|
+
category: "Bugs",
|
|
35617
|
+
requires: [...new Set(["react", ...jotaiDerivedAtomReturnsFreshObject.requires ?? []])]
|
|
35575
35618
|
}
|
|
35576
35619
|
},
|
|
35577
35620
|
{
|
|
@@ -35582,7 +35625,8 @@ const reactDoctorRules = [
|
|
|
35582
35625
|
rule: {
|
|
35583
35626
|
...jotaiSelectAtomInRenderBody,
|
|
35584
35627
|
framework: "global",
|
|
35585
|
-
category: "Bugs"
|
|
35628
|
+
category: "Bugs",
|
|
35629
|
+
requires: [...new Set(["react", ...jotaiSelectAtomInRenderBody.requires ?? []])]
|
|
35586
35630
|
}
|
|
35587
35631
|
},
|
|
35588
35632
|
{
|
|
@@ -35593,7 +35637,8 @@ const reactDoctorRules = [
|
|
|
35593
35637
|
rule: {
|
|
35594
35638
|
...jotaiTqUseRawQueryAtom,
|
|
35595
35639
|
framework: "global",
|
|
35596
|
-
category: "Bugs"
|
|
35640
|
+
category: "Bugs",
|
|
35641
|
+
requires: [...new Set(["react", ...jotaiTqUseRawQueryAtom.requires ?? []])]
|
|
35597
35642
|
}
|
|
35598
35643
|
},
|
|
35599
35644
|
{
|
|
@@ -35758,7 +35803,8 @@ const reactDoctorRules = [
|
|
|
35758
35803
|
rule: {
|
|
35759
35804
|
...jsxBooleanValue,
|
|
35760
35805
|
framework: "global",
|
|
35761
|
-
category: "Maintainability"
|
|
35806
|
+
category: "Maintainability",
|
|
35807
|
+
requires: [...new Set(["react", ...jsxBooleanValue.requires ?? []])]
|
|
35762
35808
|
}
|
|
35763
35809
|
},
|
|
35764
35810
|
{
|
|
@@ -35769,7 +35815,8 @@ const reactDoctorRules = [
|
|
|
35769
35815
|
rule: {
|
|
35770
35816
|
...jsxCurlyBracePresence,
|
|
35771
35817
|
framework: "global",
|
|
35772
|
-
category: "Maintainability"
|
|
35818
|
+
category: "Maintainability",
|
|
35819
|
+
requires: [...new Set(["react", ...jsxCurlyBracePresence.requires ?? []])]
|
|
35773
35820
|
}
|
|
35774
35821
|
},
|
|
35775
35822
|
{
|
|
@@ -35780,7 +35827,8 @@ const reactDoctorRules = [
|
|
|
35780
35827
|
rule: {
|
|
35781
35828
|
...jsxFilenameExtension,
|
|
35782
35829
|
framework: "global",
|
|
35783
|
-
category: "Maintainability"
|
|
35830
|
+
category: "Maintainability",
|
|
35831
|
+
requires: [...new Set(["react", ...jsxFilenameExtension.requires ?? []])]
|
|
35784
35832
|
}
|
|
35785
35833
|
},
|
|
35786
35834
|
{
|
|
@@ -35791,7 +35839,8 @@ const reactDoctorRules = [
|
|
|
35791
35839
|
rule: {
|
|
35792
35840
|
...jsxFragments,
|
|
35793
35841
|
framework: "global",
|
|
35794
|
-
category: "Maintainability"
|
|
35842
|
+
category: "Maintainability",
|
|
35843
|
+
requires: [...new Set(["react", ...jsxFragments.requires ?? []])]
|
|
35795
35844
|
}
|
|
35796
35845
|
},
|
|
35797
35846
|
{
|
|
@@ -35802,7 +35851,8 @@ const reactDoctorRules = [
|
|
|
35802
35851
|
rule: {
|
|
35803
35852
|
...jsxHandlerNames,
|
|
35804
35853
|
framework: "global",
|
|
35805
|
-
category: "Maintainability"
|
|
35854
|
+
category: "Maintainability",
|
|
35855
|
+
requires: [...new Set(["react", ...jsxHandlerNames.requires ?? []])]
|
|
35806
35856
|
}
|
|
35807
35857
|
},
|
|
35808
35858
|
{
|
|
@@ -35813,7 +35863,8 @@ const reactDoctorRules = [
|
|
|
35813
35863
|
rule: {
|
|
35814
35864
|
...jsxKey,
|
|
35815
35865
|
framework: "global",
|
|
35816
|
-
category: "Bugs"
|
|
35866
|
+
category: "Bugs",
|
|
35867
|
+
requires: [...new Set(["react", ...jsxKey.requires ?? []])]
|
|
35817
35868
|
}
|
|
35818
35869
|
},
|
|
35819
35870
|
{
|
|
@@ -35824,7 +35875,8 @@ const reactDoctorRules = [
|
|
|
35824
35875
|
rule: {
|
|
35825
35876
|
...jsxMaxDepth,
|
|
35826
35877
|
framework: "global",
|
|
35827
|
-
category: "Maintainability"
|
|
35878
|
+
category: "Maintainability",
|
|
35879
|
+
requires: [...new Set(["react", ...jsxMaxDepth.requires ?? []])]
|
|
35828
35880
|
}
|
|
35829
35881
|
},
|
|
35830
35882
|
{
|
|
@@ -35835,7 +35887,8 @@ const reactDoctorRules = [
|
|
|
35835
35887
|
rule: {
|
|
35836
35888
|
...jsxNoCommentTextnodes,
|
|
35837
35889
|
framework: "global",
|
|
35838
|
-
category: "Bugs"
|
|
35890
|
+
category: "Bugs",
|
|
35891
|
+
requires: [...new Set(["react", ...jsxNoCommentTextnodes.requires ?? []])]
|
|
35839
35892
|
}
|
|
35840
35893
|
},
|
|
35841
35894
|
{
|
|
@@ -35846,7 +35899,8 @@ const reactDoctorRules = [
|
|
|
35846
35899
|
rule: {
|
|
35847
35900
|
...jsxNoConstructedContextValues,
|
|
35848
35901
|
framework: "global",
|
|
35849
|
-
category: "Performance"
|
|
35902
|
+
category: "Performance",
|
|
35903
|
+
requires: [...new Set(["react", ...jsxNoConstructedContextValues.requires ?? []])]
|
|
35850
35904
|
}
|
|
35851
35905
|
},
|
|
35852
35906
|
{
|
|
@@ -35857,7 +35911,8 @@ const reactDoctorRules = [
|
|
|
35857
35911
|
rule: {
|
|
35858
35912
|
...jsxNoDuplicateProps,
|
|
35859
35913
|
framework: "global",
|
|
35860
|
-
category: "Bugs"
|
|
35914
|
+
category: "Bugs",
|
|
35915
|
+
requires: [...new Set(["react", ...jsxNoDuplicateProps.requires ?? []])]
|
|
35861
35916
|
}
|
|
35862
35917
|
},
|
|
35863
35918
|
{
|
|
@@ -35868,7 +35923,8 @@ const reactDoctorRules = [
|
|
|
35868
35923
|
rule: {
|
|
35869
35924
|
...jsxNoJsxAsProp,
|
|
35870
35925
|
framework: "global",
|
|
35871
|
-
category: "Performance"
|
|
35926
|
+
category: "Performance",
|
|
35927
|
+
requires: [...new Set(["react", ...jsxNoJsxAsProp.requires ?? []])]
|
|
35872
35928
|
}
|
|
35873
35929
|
},
|
|
35874
35930
|
{
|
|
@@ -35879,7 +35935,8 @@ const reactDoctorRules = [
|
|
|
35879
35935
|
rule: {
|
|
35880
35936
|
...jsxNoNewArrayAsProp,
|
|
35881
35937
|
framework: "global",
|
|
35882
|
-
category: "Performance"
|
|
35938
|
+
category: "Performance",
|
|
35939
|
+
requires: [...new Set(["react", ...jsxNoNewArrayAsProp.requires ?? []])]
|
|
35883
35940
|
}
|
|
35884
35941
|
},
|
|
35885
35942
|
{
|
|
@@ -35890,7 +35947,8 @@ const reactDoctorRules = [
|
|
|
35890
35947
|
rule: {
|
|
35891
35948
|
...jsxNoNewFunctionAsProp,
|
|
35892
35949
|
framework: "global",
|
|
35893
|
-
category: "Performance"
|
|
35950
|
+
category: "Performance",
|
|
35951
|
+
requires: [...new Set(["react", ...jsxNoNewFunctionAsProp.requires ?? []])]
|
|
35894
35952
|
}
|
|
35895
35953
|
},
|
|
35896
35954
|
{
|
|
@@ -35901,7 +35959,8 @@ const reactDoctorRules = [
|
|
|
35901
35959
|
rule: {
|
|
35902
35960
|
...jsxNoNewObjectAsProp,
|
|
35903
35961
|
framework: "global",
|
|
35904
|
-
category: "Performance"
|
|
35962
|
+
category: "Performance",
|
|
35963
|
+
requires: [...new Set(["react", ...jsxNoNewObjectAsProp.requires ?? []])]
|
|
35905
35964
|
}
|
|
35906
35965
|
},
|
|
35907
35966
|
{
|
|
@@ -35912,7 +35971,8 @@ const reactDoctorRules = [
|
|
|
35912
35971
|
rule: {
|
|
35913
35972
|
...jsxNoScriptUrl,
|
|
35914
35973
|
framework: "global",
|
|
35915
|
-
category: "Security"
|
|
35974
|
+
category: "Security",
|
|
35975
|
+
requires: [...new Set(["react", ...jsxNoScriptUrl.requires ?? []])]
|
|
35916
35976
|
}
|
|
35917
35977
|
},
|
|
35918
35978
|
{
|
|
@@ -35923,7 +35983,8 @@ const reactDoctorRules = [
|
|
|
35923
35983
|
rule: {
|
|
35924
35984
|
...jsxNoUndef,
|
|
35925
35985
|
framework: "global",
|
|
35926
|
-
category: "Bugs"
|
|
35986
|
+
category: "Bugs",
|
|
35987
|
+
requires: [...new Set(["react", ...jsxNoUndef.requires ?? []])]
|
|
35927
35988
|
}
|
|
35928
35989
|
},
|
|
35929
35990
|
{
|
|
@@ -35934,7 +35995,8 @@ const reactDoctorRules = [
|
|
|
35934
35995
|
rule: {
|
|
35935
35996
|
...jsxNoUselessFragment,
|
|
35936
35997
|
framework: "global",
|
|
35937
|
-
category: "Maintainability"
|
|
35998
|
+
category: "Maintainability",
|
|
35999
|
+
requires: [...new Set(["react", ...jsxNoUselessFragment.requires ?? []])]
|
|
35938
36000
|
}
|
|
35939
36001
|
},
|
|
35940
36002
|
{
|
|
@@ -35945,7 +36007,8 @@ const reactDoctorRules = [
|
|
|
35945
36007
|
rule: {
|
|
35946
36008
|
...jsxPascalCase,
|
|
35947
36009
|
framework: "global",
|
|
35948
|
-
category: "Maintainability"
|
|
36010
|
+
category: "Maintainability",
|
|
36011
|
+
requires: [...new Set(["react", ...jsxPascalCase.requires ?? []])]
|
|
35949
36012
|
}
|
|
35950
36013
|
},
|
|
35951
36014
|
{
|
|
@@ -35956,7 +36019,8 @@ const reactDoctorRules = [
|
|
|
35956
36019
|
rule: {
|
|
35957
36020
|
...jsxPropsNoSpreadMulti,
|
|
35958
36021
|
framework: "global",
|
|
35959
|
-
category: "Bugs"
|
|
36022
|
+
category: "Bugs",
|
|
36023
|
+
requires: [...new Set(["react", ...jsxPropsNoSpreadMulti.requires ?? []])]
|
|
35960
36024
|
}
|
|
35961
36025
|
},
|
|
35962
36026
|
{
|
|
@@ -35967,7 +36031,8 @@ const reactDoctorRules = [
|
|
|
35967
36031
|
rule: {
|
|
35968
36032
|
...jsxPropsNoSpreading,
|
|
35969
36033
|
framework: "global",
|
|
35970
|
-
category: "Maintainability"
|
|
36034
|
+
category: "Maintainability",
|
|
36035
|
+
requires: [...new Set(["react", ...jsxPropsNoSpreading.requires ?? []])]
|
|
35971
36036
|
}
|
|
35972
36037
|
},
|
|
35973
36038
|
{
|
|
@@ -35978,7 +36043,8 @@ const reactDoctorRules = [
|
|
|
35978
36043
|
rule: {
|
|
35979
36044
|
...labelHasAssociatedControl,
|
|
35980
36045
|
framework: "global",
|
|
35981
|
-
category: "Accessibility"
|
|
36046
|
+
category: "Accessibility",
|
|
36047
|
+
requires: [...new Set(["react", ...labelHasAssociatedControl.requires ?? []])]
|
|
35982
36048
|
}
|
|
35983
36049
|
},
|
|
35984
36050
|
{
|
|
@@ -35989,7 +36055,8 @@ const reactDoctorRules = [
|
|
|
35989
36055
|
rule: {
|
|
35990
36056
|
...lang,
|
|
35991
36057
|
framework: "global",
|
|
35992
|
-
category: "Accessibility"
|
|
36058
|
+
category: "Accessibility",
|
|
36059
|
+
requires: [...new Set(["react", ...lang.requires ?? []])]
|
|
35993
36060
|
}
|
|
35994
36061
|
},
|
|
35995
36062
|
{
|
|
@@ -36000,7 +36067,8 @@ const reactDoctorRules = [
|
|
|
36000
36067
|
rule: {
|
|
36001
36068
|
...mediaHasCaption,
|
|
36002
36069
|
framework: "global",
|
|
36003
|
-
category: "Accessibility"
|
|
36070
|
+
category: "Accessibility",
|
|
36071
|
+
requires: [...new Set(["react", ...mediaHasCaption.requires ?? []])]
|
|
36004
36072
|
}
|
|
36005
36073
|
},
|
|
36006
36074
|
{
|
|
@@ -36011,7 +36079,8 @@ const reactDoctorRules = [
|
|
|
36011
36079
|
rule: {
|
|
36012
36080
|
...mouseEventsHaveKeyEvents,
|
|
36013
36081
|
framework: "global",
|
|
36014
|
-
category: "Accessibility"
|
|
36082
|
+
category: "Accessibility",
|
|
36083
|
+
requires: [...new Set(["react", ...mouseEventsHaveKeyEvents.requires ?? []])]
|
|
36015
36084
|
}
|
|
36016
36085
|
},
|
|
36017
36086
|
{
|
|
@@ -36275,7 +36344,8 @@ const reactDoctorRules = [
|
|
|
36275
36344
|
rule: {
|
|
36276
36345
|
...noAccessKey,
|
|
36277
36346
|
framework: "global",
|
|
36278
|
-
category: "Accessibility"
|
|
36347
|
+
category: "Accessibility",
|
|
36348
|
+
requires: [...new Set(["react", ...noAccessKey.requires ?? []])]
|
|
36279
36349
|
}
|
|
36280
36350
|
},
|
|
36281
36351
|
{
|
|
@@ -36286,7 +36356,8 @@ const reactDoctorRules = [
|
|
|
36286
36356
|
rule: {
|
|
36287
36357
|
...noAdjustStateOnPropChange,
|
|
36288
36358
|
framework: "global",
|
|
36289
|
-
category: "Bugs"
|
|
36359
|
+
category: "Bugs",
|
|
36360
|
+
requires: [...new Set(["react", ...noAdjustStateOnPropChange.requires ?? []])]
|
|
36290
36361
|
}
|
|
36291
36362
|
},
|
|
36292
36363
|
{
|
|
@@ -36297,7 +36368,8 @@ const reactDoctorRules = [
|
|
|
36297
36368
|
rule: {
|
|
36298
36369
|
...noAriaHiddenOnFocusable,
|
|
36299
36370
|
framework: "global",
|
|
36300
|
-
category: "Accessibility"
|
|
36371
|
+
category: "Accessibility",
|
|
36372
|
+
requires: [...new Set(["react", ...noAriaHiddenOnFocusable.requires ?? []])]
|
|
36301
36373
|
}
|
|
36302
36374
|
},
|
|
36303
36375
|
{
|
|
@@ -36319,7 +36391,8 @@ const reactDoctorRules = [
|
|
|
36319
36391
|
rule: {
|
|
36320
36392
|
...noArrayIndexKey,
|
|
36321
36393
|
framework: "global",
|
|
36322
|
-
category: "Performance"
|
|
36394
|
+
category: "Performance",
|
|
36395
|
+
requires: [...new Set(["react", ...noArrayIndexKey.requires ?? []])]
|
|
36323
36396
|
}
|
|
36324
36397
|
},
|
|
36325
36398
|
{
|
|
@@ -36330,7 +36403,8 @@ const reactDoctorRules = [
|
|
|
36330
36403
|
rule: {
|
|
36331
36404
|
...noAutofocus,
|
|
36332
36405
|
framework: "global",
|
|
36333
|
-
category: "Accessibility"
|
|
36406
|
+
category: "Accessibility",
|
|
36407
|
+
requires: [...new Set(["react", ...noAutofocus.requires ?? []])]
|
|
36334
36408
|
}
|
|
36335
36409
|
},
|
|
36336
36410
|
{
|
|
@@ -36352,7 +36426,8 @@ const reactDoctorRules = [
|
|
|
36352
36426
|
rule: {
|
|
36353
36427
|
...noCascadingSetState,
|
|
36354
36428
|
framework: "global",
|
|
36355
|
-
category: "Bugs"
|
|
36429
|
+
category: "Bugs",
|
|
36430
|
+
requires: [...new Set(["react", ...noCascadingSetState.requires ?? []])]
|
|
36356
36431
|
}
|
|
36357
36432
|
},
|
|
36358
36433
|
{
|
|
@@ -36363,7 +36438,8 @@ const reactDoctorRules = [
|
|
|
36363
36438
|
rule: {
|
|
36364
36439
|
...noChainStateUpdates,
|
|
36365
36440
|
framework: "global",
|
|
36366
|
-
category: "Bugs"
|
|
36441
|
+
category: "Bugs",
|
|
36442
|
+
requires: [...new Set(["react", ...noChainStateUpdates.requires ?? []])]
|
|
36367
36443
|
}
|
|
36368
36444
|
},
|
|
36369
36445
|
{
|
|
@@ -36374,7 +36450,8 @@ const reactDoctorRules = [
|
|
|
36374
36450
|
rule: {
|
|
36375
36451
|
...noChildrenProp,
|
|
36376
36452
|
framework: "global",
|
|
36377
|
-
category: "Bugs"
|
|
36453
|
+
category: "Bugs",
|
|
36454
|
+
requires: [...new Set(["react", ...noChildrenProp.requires ?? []])]
|
|
36378
36455
|
}
|
|
36379
36456
|
},
|
|
36380
36457
|
{
|
|
@@ -36385,7 +36462,8 @@ const reactDoctorRules = [
|
|
|
36385
36462
|
rule: {
|
|
36386
36463
|
...noCloneElement,
|
|
36387
36464
|
framework: "global",
|
|
36388
|
-
category: "Maintainability"
|
|
36465
|
+
category: "Maintainability",
|
|
36466
|
+
requires: [...new Set(["react", ...noCloneElement.requires ?? []])]
|
|
36389
36467
|
}
|
|
36390
36468
|
},
|
|
36391
36469
|
{
|
|
@@ -36396,7 +36474,8 @@ const reactDoctorRules = [
|
|
|
36396
36474
|
rule: {
|
|
36397
36475
|
...noCreateContextInRender,
|
|
36398
36476
|
framework: "global",
|
|
36399
|
-
category: "Bugs"
|
|
36477
|
+
category: "Bugs",
|
|
36478
|
+
requires: [...new Set(["react", ...noCreateContextInRender.requires ?? []])]
|
|
36400
36479
|
}
|
|
36401
36480
|
},
|
|
36402
36481
|
{
|
|
@@ -36407,7 +36486,8 @@ const reactDoctorRules = [
|
|
|
36407
36486
|
rule: {
|
|
36408
36487
|
...noCreateStoreInRender,
|
|
36409
36488
|
framework: "global",
|
|
36410
|
-
category: "Bugs"
|
|
36489
|
+
category: "Bugs",
|
|
36490
|
+
requires: [...new Set(["react", ...noCreateStoreInRender.requires ?? []])]
|
|
36411
36491
|
}
|
|
36412
36492
|
},
|
|
36413
36493
|
{
|
|
@@ -36418,7 +36498,8 @@ const reactDoctorRules = [
|
|
|
36418
36498
|
rule: {
|
|
36419
36499
|
...noDanger,
|
|
36420
36500
|
framework: "global",
|
|
36421
|
-
category: "Security"
|
|
36501
|
+
category: "Security",
|
|
36502
|
+
requires: [...new Set(["react", ...noDanger.requires ?? []])]
|
|
36422
36503
|
}
|
|
36423
36504
|
},
|
|
36424
36505
|
{
|
|
@@ -36429,7 +36510,8 @@ const reactDoctorRules = [
|
|
|
36429
36510
|
rule: {
|
|
36430
36511
|
...noDangerWithChildren,
|
|
36431
36512
|
framework: "global",
|
|
36432
|
-
category: "Bugs"
|
|
36513
|
+
category: "Bugs",
|
|
36514
|
+
requires: [...new Set(["react", ...noDangerWithChildren.requires ?? []])]
|
|
36433
36515
|
}
|
|
36434
36516
|
},
|
|
36435
36517
|
{
|
|
@@ -36462,7 +36544,8 @@ const reactDoctorRules = [
|
|
|
36462
36544
|
rule: {
|
|
36463
36545
|
...noDerivedState,
|
|
36464
36546
|
framework: "global",
|
|
36465
|
-
category: "Bugs"
|
|
36547
|
+
category: "Bugs",
|
|
36548
|
+
requires: [...new Set(["react", ...noDerivedState.requires ?? []])]
|
|
36466
36549
|
}
|
|
36467
36550
|
},
|
|
36468
36551
|
{
|
|
@@ -36473,7 +36556,8 @@ const reactDoctorRules = [
|
|
|
36473
36556
|
rule: {
|
|
36474
36557
|
...noDerivedStateEffect,
|
|
36475
36558
|
framework: "global",
|
|
36476
|
-
category: "Bugs"
|
|
36559
|
+
category: "Bugs",
|
|
36560
|
+
requires: [...new Set(["react", ...noDerivedStateEffect.requires ?? []])]
|
|
36477
36561
|
}
|
|
36478
36562
|
},
|
|
36479
36563
|
{
|
|
@@ -36484,7 +36568,8 @@ const reactDoctorRules = [
|
|
|
36484
36568
|
rule: {
|
|
36485
36569
|
...noDerivedUseState,
|
|
36486
36570
|
framework: "global",
|
|
36487
|
-
category: "Bugs"
|
|
36571
|
+
category: "Bugs",
|
|
36572
|
+
requires: [...new Set(["react", ...noDerivedUseState.requires ?? []])]
|
|
36488
36573
|
}
|
|
36489
36574
|
},
|
|
36490
36575
|
{
|
|
@@ -36495,7 +36580,8 @@ const reactDoctorRules = [
|
|
|
36495
36580
|
rule: {
|
|
36496
36581
|
...noDidMountSetState,
|
|
36497
36582
|
framework: "global",
|
|
36498
|
-
category: "Bugs"
|
|
36583
|
+
category: "Bugs",
|
|
36584
|
+
requires: [...new Set(["react", ...noDidMountSetState.requires ?? []])]
|
|
36499
36585
|
}
|
|
36500
36586
|
},
|
|
36501
36587
|
{
|
|
@@ -36506,7 +36592,8 @@ const reactDoctorRules = [
|
|
|
36506
36592
|
rule: {
|
|
36507
36593
|
...noDidUpdateSetState,
|
|
36508
36594
|
framework: "global",
|
|
36509
|
-
category: "Bugs"
|
|
36595
|
+
category: "Bugs",
|
|
36596
|
+
requires: [...new Set(["react", ...noDidUpdateSetState.requires ?? []])]
|
|
36510
36597
|
}
|
|
36511
36598
|
},
|
|
36512
36599
|
{
|
|
@@ -36517,7 +36604,8 @@ const reactDoctorRules = [
|
|
|
36517
36604
|
rule: {
|
|
36518
36605
|
...noDirectMutationState,
|
|
36519
36606
|
framework: "global",
|
|
36520
|
-
category: "Bugs"
|
|
36607
|
+
category: "Bugs",
|
|
36608
|
+
requires: [...new Set(["react", ...noDirectMutationState.requires ?? []])]
|
|
36521
36609
|
}
|
|
36522
36610
|
},
|
|
36523
36611
|
{
|
|
@@ -36528,7 +36616,8 @@ const reactDoctorRules = [
|
|
|
36528
36616
|
rule: {
|
|
36529
36617
|
...noDirectStateMutation,
|
|
36530
36618
|
framework: "global",
|
|
36531
|
-
category: "Bugs"
|
|
36619
|
+
category: "Bugs",
|
|
36620
|
+
requires: [...new Set(["react", ...noDirectStateMutation.requires ?? []])]
|
|
36532
36621
|
}
|
|
36533
36622
|
},
|
|
36534
36623
|
{
|
|
@@ -36550,7 +36639,8 @@ const reactDoctorRules = [
|
|
|
36550
36639
|
rule: {
|
|
36551
36640
|
...noDistractingElements,
|
|
36552
36641
|
framework: "global",
|
|
36553
|
-
category: "Accessibility"
|
|
36642
|
+
category: "Accessibility",
|
|
36643
|
+
requires: [...new Set(["react", ...noDistractingElements.requires ?? []])]
|
|
36554
36644
|
}
|
|
36555
36645
|
},
|
|
36556
36646
|
{
|
|
@@ -36561,7 +36651,8 @@ const reactDoctorRules = [
|
|
|
36561
36651
|
rule: {
|
|
36562
36652
|
...noDocumentStartViewTransition,
|
|
36563
36653
|
framework: "global",
|
|
36564
|
-
category: "Bugs"
|
|
36654
|
+
category: "Bugs",
|
|
36655
|
+
requires: [...new Set(["react", ...noDocumentStartViewTransition.requires ?? []])]
|
|
36565
36656
|
}
|
|
36566
36657
|
},
|
|
36567
36658
|
{
|
|
@@ -36583,7 +36674,8 @@ const reactDoctorRules = [
|
|
|
36583
36674
|
rule: {
|
|
36584
36675
|
...noEffectChain,
|
|
36585
36676
|
framework: "global",
|
|
36586
|
-
category: "Bugs"
|
|
36677
|
+
category: "Bugs",
|
|
36678
|
+
requires: [...new Set(["react", ...noEffectChain.requires ?? []])]
|
|
36587
36679
|
}
|
|
36588
36680
|
},
|
|
36589
36681
|
{
|
|
@@ -36594,7 +36686,8 @@ const reactDoctorRules = [
|
|
|
36594
36686
|
rule: {
|
|
36595
36687
|
...noEffectEventHandler,
|
|
36596
36688
|
framework: "global",
|
|
36597
|
-
category: "Bugs"
|
|
36689
|
+
category: "Bugs",
|
|
36690
|
+
requires: [...new Set(["react", ...noEffectEventHandler.requires ?? []])]
|
|
36598
36691
|
}
|
|
36599
36692
|
},
|
|
36600
36693
|
{
|
|
@@ -36605,7 +36698,8 @@ const reactDoctorRules = [
|
|
|
36605
36698
|
rule: {
|
|
36606
36699
|
...noEffectEventInDeps,
|
|
36607
36700
|
framework: "global",
|
|
36608
|
-
category: "Bugs"
|
|
36701
|
+
category: "Bugs",
|
|
36702
|
+
requires: [...new Set(["react", ...noEffectEventInDeps.requires ?? []])]
|
|
36609
36703
|
}
|
|
36610
36704
|
},
|
|
36611
36705
|
{
|
|
@@ -36616,7 +36710,8 @@ const reactDoctorRules = [
|
|
|
36616
36710
|
rule: {
|
|
36617
36711
|
...noEffectWithFreshDeps,
|
|
36618
36712
|
framework: "global",
|
|
36619
|
-
category: "Bugs"
|
|
36713
|
+
category: "Bugs",
|
|
36714
|
+
requires: [...new Set(["react", ...noEffectWithFreshDeps.requires ?? []])]
|
|
36620
36715
|
}
|
|
36621
36716
|
},
|
|
36622
36717
|
{
|
|
@@ -36638,7 +36733,8 @@ const reactDoctorRules = [
|
|
|
36638
36733
|
rule: {
|
|
36639
36734
|
...noEventHandler,
|
|
36640
36735
|
framework: "global",
|
|
36641
|
-
category: "Bugs"
|
|
36736
|
+
category: "Bugs",
|
|
36737
|
+
requires: [...new Set(["react", ...noEventHandler.requires ?? []])]
|
|
36642
36738
|
}
|
|
36643
36739
|
},
|
|
36644
36740
|
{
|
|
@@ -36649,7 +36745,8 @@ const reactDoctorRules = [
|
|
|
36649
36745
|
rule: {
|
|
36650
36746
|
...noEventTriggerState,
|
|
36651
36747
|
framework: "global",
|
|
36652
|
-
category: "Bugs"
|
|
36748
|
+
category: "Bugs",
|
|
36749
|
+
requires: [...new Set(["react", ...noEventTriggerState.requires ?? []])]
|
|
36653
36750
|
}
|
|
36654
36751
|
},
|
|
36655
36752
|
{
|
|
@@ -36660,7 +36757,8 @@ const reactDoctorRules = [
|
|
|
36660
36757
|
rule: {
|
|
36661
36758
|
...noFetchInEffect,
|
|
36662
36759
|
framework: "global",
|
|
36663
|
-
category: "Bugs"
|
|
36760
|
+
category: "Bugs",
|
|
36761
|
+
requires: [...new Set(["react", ...noFetchInEffect.requires ?? []])]
|
|
36664
36762
|
}
|
|
36665
36763
|
},
|
|
36666
36764
|
{
|
|
@@ -36671,7 +36769,8 @@ const reactDoctorRules = [
|
|
|
36671
36769
|
rule: {
|
|
36672
36770
|
...noFindDomNode,
|
|
36673
36771
|
framework: "global",
|
|
36674
|
-
category: "Bugs"
|
|
36772
|
+
category: "Bugs",
|
|
36773
|
+
requires: [...new Set(["react", ...noFindDomNode.requires ?? []])]
|
|
36675
36774
|
}
|
|
36676
36775
|
},
|
|
36677
36776
|
{
|
|
@@ -36682,7 +36781,8 @@ const reactDoctorRules = [
|
|
|
36682
36781
|
rule: {
|
|
36683
36782
|
...noFlushSync,
|
|
36684
36783
|
framework: "global",
|
|
36685
|
-
category: "Performance"
|
|
36784
|
+
category: "Performance",
|
|
36785
|
+
requires: [...new Set(["react", ...noFlushSync.requires ?? []])]
|
|
36686
36786
|
}
|
|
36687
36787
|
},
|
|
36688
36788
|
{
|
|
@@ -36726,7 +36826,8 @@ const reactDoctorRules = [
|
|
|
36726
36826
|
rule: {
|
|
36727
36827
|
...noGlobalCssVariableAnimation,
|
|
36728
36828
|
framework: "global",
|
|
36729
|
-
category: "Performance"
|
|
36829
|
+
category: "Performance",
|
|
36830
|
+
requires: [...new Set(["react", ...noGlobalCssVariableAnimation.requires ?? []])]
|
|
36730
36831
|
}
|
|
36731
36832
|
},
|
|
36732
36833
|
{
|
|
@@ -36759,7 +36860,8 @@ const reactDoctorRules = [
|
|
|
36759
36860
|
rule: {
|
|
36760
36861
|
...noInitializeState,
|
|
36761
36862
|
framework: "global",
|
|
36762
|
-
category: "Bugs"
|
|
36863
|
+
category: "Bugs",
|
|
36864
|
+
requires: [...new Set(["react", ...noInitializeState.requires ?? []])]
|
|
36763
36865
|
}
|
|
36764
36866
|
},
|
|
36765
36867
|
{
|
|
@@ -36792,7 +36894,8 @@ const reactDoctorRules = [
|
|
|
36792
36894
|
rule: {
|
|
36793
36895
|
...noInlinePropOnMemoComponent,
|
|
36794
36896
|
framework: "global",
|
|
36795
|
-
category: "Performance"
|
|
36897
|
+
category: "Performance",
|
|
36898
|
+
requires: [...new Set(["react", ...noInlinePropOnMemoComponent.requires ?? []])]
|
|
36796
36899
|
}
|
|
36797
36900
|
},
|
|
36798
36901
|
{
|
|
@@ -36803,7 +36906,8 @@ const reactDoctorRules = [
|
|
|
36803
36906
|
rule: {
|
|
36804
36907
|
...noInteractiveElementToNoninteractiveRole,
|
|
36805
36908
|
framework: "global",
|
|
36806
|
-
category: "Accessibility"
|
|
36909
|
+
category: "Accessibility",
|
|
36910
|
+
requires: [...new Set(["react", ...noInteractiveElementToNoninteractiveRole.requires ?? []])]
|
|
36807
36911
|
}
|
|
36808
36912
|
},
|
|
36809
36913
|
{
|
|
@@ -36814,7 +36918,8 @@ const reactDoctorRules = [
|
|
|
36814
36918
|
rule: {
|
|
36815
36919
|
...noIsMounted,
|
|
36816
36920
|
framework: "global",
|
|
36817
|
-
category: "Bugs"
|
|
36921
|
+
category: "Bugs",
|
|
36922
|
+
requires: [...new Set(["react", ...noIsMounted.requires ?? []])]
|
|
36818
36923
|
}
|
|
36819
36924
|
},
|
|
36820
36925
|
{
|
|
@@ -36847,7 +36952,8 @@ const reactDoctorRules = [
|
|
|
36847
36952
|
rule: {
|
|
36848
36953
|
...noLargeAnimatedBlur,
|
|
36849
36954
|
framework: "global",
|
|
36850
|
-
category: "Performance"
|
|
36955
|
+
category: "Performance",
|
|
36956
|
+
requires: [...new Set(["react", ...noLargeAnimatedBlur.requires ?? []])]
|
|
36851
36957
|
}
|
|
36852
36958
|
},
|
|
36853
36959
|
{
|
|
@@ -36858,7 +36964,8 @@ const reactDoctorRules = [
|
|
|
36858
36964
|
rule: {
|
|
36859
36965
|
...noLayoutPropertyAnimation,
|
|
36860
36966
|
framework: "global",
|
|
36861
|
-
category: "Performance"
|
|
36967
|
+
category: "Performance",
|
|
36968
|
+
requires: [...new Set(["react", ...noLayoutPropertyAnimation.requires ?? []])]
|
|
36862
36969
|
}
|
|
36863
36970
|
},
|
|
36864
36971
|
{
|
|
@@ -36924,7 +37031,8 @@ const reactDoctorRules = [
|
|
|
36924
37031
|
rule: {
|
|
36925
37032
|
...noMirrorPropEffect,
|
|
36926
37033
|
framework: "global",
|
|
36927
|
-
category: "Bugs"
|
|
37034
|
+
category: "Bugs",
|
|
37035
|
+
requires: [...new Set(["react", ...noMirrorPropEffect.requires ?? []])]
|
|
36928
37036
|
}
|
|
36929
37037
|
},
|
|
36930
37038
|
{
|
|
@@ -36946,7 +37054,8 @@ const reactDoctorRules = [
|
|
|
36946
37054
|
rule: {
|
|
36947
37055
|
...noMultiComp,
|
|
36948
37056
|
framework: "global",
|
|
36949
|
-
category: "Maintainability"
|
|
37057
|
+
category: "Maintainability",
|
|
37058
|
+
requires: [...new Set(["react", ...noMultiComp.requires ?? []])]
|
|
36950
37059
|
}
|
|
36951
37060
|
},
|
|
36952
37061
|
{
|
|
@@ -36957,7 +37066,8 @@ const reactDoctorRules = [
|
|
|
36957
37066
|
rule: {
|
|
36958
37067
|
...noMutableInDeps,
|
|
36959
37068
|
framework: "global",
|
|
36960
|
-
category: "Bugs"
|
|
37069
|
+
category: "Bugs",
|
|
37070
|
+
requires: [...new Set(["react", ...noMutableInDeps.requires ?? []])]
|
|
36961
37071
|
}
|
|
36962
37072
|
},
|
|
36963
37073
|
{
|
|
@@ -36968,7 +37078,8 @@ const reactDoctorRules = [
|
|
|
36968
37078
|
rule: {
|
|
36969
37079
|
...noMutatingReducerState,
|
|
36970
37080
|
framework: "global",
|
|
36971
|
-
category: "Bugs"
|
|
37081
|
+
category: "Bugs",
|
|
37082
|
+
requires: [...new Set(["react", ...noMutatingReducerState.requires ?? []])]
|
|
36972
37083
|
}
|
|
36973
37084
|
},
|
|
36974
37085
|
{
|
|
@@ -36979,7 +37090,8 @@ const reactDoctorRules = [
|
|
|
36979
37090
|
rule: {
|
|
36980
37091
|
...noNamespace,
|
|
36981
37092
|
framework: "global",
|
|
36982
|
-
category: "Bugs"
|
|
37093
|
+
category: "Bugs",
|
|
37094
|
+
requires: [...new Set(["react", ...noNamespace.requires ?? []])]
|
|
36983
37095
|
}
|
|
36984
37096
|
},
|
|
36985
37097
|
{
|
|
@@ -37001,7 +37113,8 @@ const reactDoctorRules = [
|
|
|
37001
37113
|
rule: {
|
|
37002
37114
|
...noNoninteractiveElementInteractions,
|
|
37003
37115
|
framework: "global",
|
|
37004
|
-
category: "Accessibility"
|
|
37116
|
+
category: "Accessibility",
|
|
37117
|
+
requires: [...new Set(["react", ...noNoninteractiveElementInteractions.requires ?? []])]
|
|
37005
37118
|
}
|
|
37006
37119
|
},
|
|
37007
37120
|
{
|
|
@@ -37012,7 +37125,8 @@ const reactDoctorRules = [
|
|
|
37012
37125
|
rule: {
|
|
37013
37126
|
...noNoninteractiveElementToInteractiveRole,
|
|
37014
37127
|
framework: "global",
|
|
37015
|
-
category: "Accessibility"
|
|
37128
|
+
category: "Accessibility",
|
|
37129
|
+
requires: [...new Set(["react", ...noNoninteractiveElementToInteractiveRole.requires ?? []])]
|
|
37016
37130
|
}
|
|
37017
37131
|
},
|
|
37018
37132
|
{
|
|
@@ -37023,7 +37137,8 @@ const reactDoctorRules = [
|
|
|
37023
37137
|
rule: {
|
|
37024
37138
|
...noNoninteractiveTabindex,
|
|
37025
37139
|
framework: "global",
|
|
37026
|
-
category: "Accessibility"
|
|
37140
|
+
category: "Accessibility",
|
|
37141
|
+
requires: [...new Set(["react", ...noNoninteractiveTabindex.requires ?? []])]
|
|
37027
37142
|
}
|
|
37028
37143
|
},
|
|
37029
37144
|
{
|
|
@@ -37045,7 +37160,8 @@ const reactDoctorRules = [
|
|
|
37045
37160
|
rule: {
|
|
37046
37161
|
...noPassDataToParent,
|
|
37047
37162
|
framework: "global",
|
|
37048
|
-
category: "Bugs"
|
|
37163
|
+
category: "Bugs",
|
|
37164
|
+
requires: [...new Set(["react", ...noPassDataToParent.requires ?? []])]
|
|
37049
37165
|
}
|
|
37050
37166
|
},
|
|
37051
37167
|
{
|
|
@@ -37056,7 +37172,8 @@ const reactDoctorRules = [
|
|
|
37056
37172
|
rule: {
|
|
37057
37173
|
...noPassLiveStateToParent,
|
|
37058
37174
|
framework: "global",
|
|
37059
|
-
category: "Bugs"
|
|
37175
|
+
category: "Bugs",
|
|
37176
|
+
requires: [...new Set(["react", ...noPassLiveStateToParent.requires ?? []])]
|
|
37060
37177
|
}
|
|
37061
37178
|
},
|
|
37062
37179
|
{
|
|
@@ -37067,7 +37184,8 @@ const reactDoctorRules = [
|
|
|
37067
37184
|
rule: {
|
|
37068
37185
|
...noPermanentWillChange,
|
|
37069
37186
|
framework: "global",
|
|
37070
|
-
category: "Performance"
|
|
37187
|
+
category: "Performance",
|
|
37188
|
+
requires: [...new Set(["react", ...noPermanentWillChange.requires ?? []])]
|
|
37071
37189
|
}
|
|
37072
37190
|
},
|
|
37073
37191
|
{
|
|
@@ -37100,7 +37218,8 @@ const reactDoctorRules = [
|
|
|
37100
37218
|
rule: {
|
|
37101
37219
|
...noPropCallbackInEffect,
|
|
37102
37220
|
framework: "global",
|
|
37103
|
-
category: "Bugs"
|
|
37221
|
+
category: "Bugs",
|
|
37222
|
+
requires: [...new Set(["react", ...noPropCallbackInEffect.requires ?? []])]
|
|
37104
37223
|
}
|
|
37105
37224
|
},
|
|
37106
37225
|
{
|
|
@@ -37144,7 +37263,8 @@ const reactDoctorRules = [
|
|
|
37144
37263
|
rule: {
|
|
37145
37264
|
...noReactChildren,
|
|
37146
37265
|
framework: "global",
|
|
37147
|
-
category: "Maintainability"
|
|
37266
|
+
category: "Maintainability",
|
|
37267
|
+
requires: [...new Set(["react", ...noReactChildren.requires ?? []])]
|
|
37148
37268
|
}
|
|
37149
37269
|
},
|
|
37150
37270
|
{
|
|
@@ -37177,7 +37297,8 @@ const reactDoctorRules = [
|
|
|
37177
37297
|
rule: {
|
|
37178
37298
|
...noRedundantRoles,
|
|
37179
37299
|
framework: "global",
|
|
37180
|
-
category: "Accessibility"
|
|
37300
|
+
category: "Accessibility",
|
|
37301
|
+
requires: [...new Set(["react", ...noRedundantRoles.requires ?? []])]
|
|
37181
37302
|
}
|
|
37182
37303
|
},
|
|
37183
37304
|
{
|
|
@@ -37188,7 +37309,8 @@ const reactDoctorRules = [
|
|
|
37188
37309
|
rule: {
|
|
37189
37310
|
...noRedundantShouldComponentUpdate,
|
|
37190
37311
|
framework: "global",
|
|
37191
|
-
category: "Maintainability"
|
|
37312
|
+
category: "Maintainability",
|
|
37313
|
+
requires: [...new Set(["react", ...noRedundantShouldComponentUpdate.requires ?? []])]
|
|
37192
37314
|
}
|
|
37193
37315
|
},
|
|
37194
37316
|
{
|
|
@@ -37221,7 +37343,8 @@ const reactDoctorRules = [
|
|
|
37221
37343
|
rule: {
|
|
37222
37344
|
...noRenderReturnValue,
|
|
37223
37345
|
framework: "global",
|
|
37224
|
-
category: "Bugs"
|
|
37346
|
+
category: "Bugs",
|
|
37347
|
+
requires: [...new Set(["react", ...noRenderReturnValue.requires ?? []])]
|
|
37225
37348
|
}
|
|
37226
37349
|
},
|
|
37227
37350
|
{
|
|
@@ -37232,7 +37355,8 @@ const reactDoctorRules = [
|
|
|
37232
37355
|
rule: {
|
|
37233
37356
|
...noResetAllStateOnPropChange,
|
|
37234
37357
|
framework: "global",
|
|
37235
|
-
category: "Bugs"
|
|
37358
|
+
category: "Bugs",
|
|
37359
|
+
requires: [...new Set(["react", ...noResetAllStateOnPropChange.requires ?? []])]
|
|
37236
37360
|
}
|
|
37237
37361
|
},
|
|
37238
37362
|
{
|
|
@@ -37243,7 +37367,8 @@ const reactDoctorRules = [
|
|
|
37243
37367
|
rule: {
|
|
37244
37368
|
...noScaleFromZero,
|
|
37245
37369
|
framework: "global",
|
|
37246
|
-
category: "Performance"
|
|
37370
|
+
category: "Performance",
|
|
37371
|
+
requires: [...new Set(["react", ...noScaleFromZero.requires ?? []])]
|
|
37247
37372
|
}
|
|
37248
37373
|
},
|
|
37249
37374
|
{
|
|
@@ -37265,7 +37390,8 @@ const reactDoctorRules = [
|
|
|
37265
37390
|
rule: {
|
|
37266
37391
|
...noSelfUpdatingEffect,
|
|
37267
37392
|
framework: "global",
|
|
37268
|
-
category: "Bugs"
|
|
37393
|
+
category: "Bugs",
|
|
37394
|
+
requires: [...new Set(["react", ...noSelfUpdatingEffect.requires ?? []])]
|
|
37269
37395
|
}
|
|
37270
37396
|
},
|
|
37271
37397
|
{
|
|
@@ -37276,7 +37402,8 @@ const reactDoctorRules = [
|
|
|
37276
37402
|
rule: {
|
|
37277
37403
|
...noSetState,
|
|
37278
37404
|
framework: "global",
|
|
37279
|
-
category: "Maintainability"
|
|
37405
|
+
category: "Maintainability",
|
|
37406
|
+
requires: [...new Set(["react", ...noSetState.requires ?? []])]
|
|
37280
37407
|
}
|
|
37281
37408
|
},
|
|
37282
37409
|
{
|
|
@@ -37287,7 +37414,8 @@ const reactDoctorRules = [
|
|
|
37287
37414
|
rule: {
|
|
37288
37415
|
...noSetStateInRender,
|
|
37289
37416
|
framework: "global",
|
|
37290
|
-
category: "Bugs"
|
|
37417
|
+
category: "Bugs",
|
|
37418
|
+
requires: [...new Set(["react", ...noSetStateInRender.requires ?? []])]
|
|
37291
37419
|
}
|
|
37292
37420
|
},
|
|
37293
37421
|
{
|
|
@@ -37309,7 +37437,8 @@ const reactDoctorRules = [
|
|
|
37309
37437
|
rule: {
|
|
37310
37438
|
...noStaticElementInteractions,
|
|
37311
37439
|
framework: "global",
|
|
37312
|
-
category: "Accessibility"
|
|
37440
|
+
category: "Accessibility",
|
|
37441
|
+
requires: [...new Set(["react", ...noStaticElementInteractions.requires ?? []])]
|
|
37313
37442
|
}
|
|
37314
37443
|
},
|
|
37315
37444
|
{
|
|
@@ -37320,7 +37449,8 @@ const reactDoctorRules = [
|
|
|
37320
37449
|
rule: {
|
|
37321
37450
|
...noStringRefs,
|
|
37322
37451
|
framework: "global",
|
|
37323
|
-
category: "Bugs"
|
|
37452
|
+
category: "Bugs",
|
|
37453
|
+
requires: [...new Set(["react", ...noStringRefs.requires ?? []])]
|
|
37324
37454
|
}
|
|
37325
37455
|
},
|
|
37326
37456
|
{
|
|
@@ -37331,7 +37461,8 @@ const reactDoctorRules = [
|
|
|
37331
37461
|
rule: {
|
|
37332
37462
|
...noThisInSfc,
|
|
37333
37463
|
framework: "global",
|
|
37334
|
-
category: "Bugs"
|
|
37464
|
+
category: "Bugs",
|
|
37465
|
+
requires: [...new Set(["react", ...noThisInSfc.requires ?? []])]
|
|
37335
37466
|
}
|
|
37336
37467
|
},
|
|
37337
37468
|
{
|
|
@@ -37353,7 +37484,8 @@ const reactDoctorRules = [
|
|
|
37353
37484
|
rule: {
|
|
37354
37485
|
...noTransitionAll,
|
|
37355
37486
|
framework: "global",
|
|
37356
|
-
category: "Performance"
|
|
37487
|
+
category: "Performance",
|
|
37488
|
+
requires: [...new Set(["react", ...noTransitionAll.requires ?? []])]
|
|
37357
37489
|
}
|
|
37358
37490
|
},
|
|
37359
37491
|
{
|
|
@@ -37386,7 +37518,8 @@ const reactDoctorRules = [
|
|
|
37386
37518
|
rule: {
|
|
37387
37519
|
...noUnescapedEntities,
|
|
37388
37520
|
framework: "global",
|
|
37389
|
-
category: "Bugs"
|
|
37521
|
+
category: "Bugs",
|
|
37522
|
+
requires: [...new Set(["react", ...noUnescapedEntities.requires ?? []])]
|
|
37390
37523
|
}
|
|
37391
37524
|
},
|
|
37392
37525
|
{
|
|
@@ -37397,7 +37530,8 @@ const reactDoctorRules = [
|
|
|
37397
37530
|
rule: {
|
|
37398
37531
|
...noUnknownProperty,
|
|
37399
37532
|
framework: "global",
|
|
37400
|
-
category: "Bugs"
|
|
37533
|
+
category: "Bugs",
|
|
37534
|
+
requires: [...new Set(["react", ...noUnknownProperty.requires ?? []])]
|
|
37401
37535
|
}
|
|
37402
37536
|
},
|
|
37403
37537
|
{
|
|
@@ -37408,7 +37542,8 @@ const reactDoctorRules = [
|
|
|
37408
37542
|
rule: {
|
|
37409
37543
|
...noUnsafe,
|
|
37410
37544
|
framework: "global",
|
|
37411
|
-
category: "Bugs"
|
|
37545
|
+
category: "Bugs",
|
|
37546
|
+
requires: [...new Set(["react", ...noUnsafe.requires ?? []])]
|
|
37412
37547
|
}
|
|
37413
37548
|
},
|
|
37414
37549
|
{
|
|
@@ -37419,7 +37554,8 @@ const reactDoctorRules = [
|
|
|
37419
37554
|
rule: {
|
|
37420
37555
|
...noUnstableNestedComponents,
|
|
37421
37556
|
framework: "global",
|
|
37422
|
-
category: "Performance"
|
|
37557
|
+
category: "Performance",
|
|
37558
|
+
requires: [...new Set(["react", ...noUnstableNestedComponents.requires ?? []])]
|
|
37423
37559
|
}
|
|
37424
37560
|
},
|
|
37425
37561
|
{
|
|
@@ -37430,7 +37566,8 @@ const reactDoctorRules = [
|
|
|
37430
37566
|
rule: {
|
|
37431
37567
|
...noUsememoSimpleExpression,
|
|
37432
37568
|
framework: "global",
|
|
37433
|
-
category: "Performance"
|
|
37569
|
+
category: "Performance",
|
|
37570
|
+
requires: [...new Set(["react", ...noUsememoSimpleExpression.requires ?? []])]
|
|
37434
37571
|
}
|
|
37435
37572
|
},
|
|
37436
37573
|
{
|
|
@@ -37452,7 +37589,8 @@ const reactDoctorRules = [
|
|
|
37452
37589
|
rule: {
|
|
37453
37590
|
...noWillUpdateSetState,
|
|
37454
37591
|
framework: "global",
|
|
37455
|
-
category: "Bugs"
|
|
37592
|
+
category: "Bugs",
|
|
37593
|
+
requires: [...new Set(["react", ...noWillUpdateSetState.requires ?? []])]
|
|
37456
37594
|
}
|
|
37457
37595
|
},
|
|
37458
37596
|
{
|
|
@@ -37474,7 +37612,8 @@ const reactDoctorRules = [
|
|
|
37474
37612
|
rule: {
|
|
37475
37613
|
...onlyExportComponents,
|
|
37476
37614
|
framework: "global",
|
|
37477
|
-
category: "Maintainability"
|
|
37615
|
+
category: "Maintainability",
|
|
37616
|
+
requires: [...new Set(["react", ...onlyExportComponents.requires ?? []])]
|
|
37478
37617
|
}
|
|
37479
37618
|
},
|
|
37480
37619
|
{
|
|
@@ -37551,7 +37690,8 @@ const reactDoctorRules = [
|
|
|
37551
37690
|
rule: {
|
|
37552
37691
|
...preferEs6Class,
|
|
37553
37692
|
framework: "global",
|
|
37554
|
-
category: "Maintainability"
|
|
37693
|
+
category: "Maintainability",
|
|
37694
|
+
requires: [...new Set(["react", ...preferEs6Class.requires ?? []])]
|
|
37555
37695
|
}
|
|
37556
37696
|
},
|
|
37557
37697
|
{
|
|
@@ -37573,7 +37713,8 @@ const reactDoctorRules = [
|
|
|
37573
37713
|
rule: {
|
|
37574
37714
|
...preferFunctionComponent,
|
|
37575
37715
|
framework: "global",
|
|
37576
|
-
category: "Maintainability"
|
|
37716
|
+
category: "Maintainability",
|
|
37717
|
+
requires: [...new Set(["react", ...preferFunctionComponent.requires ?? []])]
|
|
37577
37718
|
}
|
|
37578
37719
|
},
|
|
37579
37720
|
{
|
|
@@ -37584,7 +37725,8 @@ const reactDoctorRules = [
|
|
|
37584
37725
|
rule: {
|
|
37585
37726
|
...preferHtmlDialog,
|
|
37586
37727
|
framework: "global",
|
|
37587
|
-
category: "Accessibility"
|
|
37728
|
+
category: "Accessibility",
|
|
37729
|
+
requires: [...new Set(["react", ...preferHtmlDialog.requires ?? []])]
|
|
37588
37730
|
}
|
|
37589
37731
|
},
|
|
37590
37732
|
{
|
|
@@ -37617,7 +37759,8 @@ const reactDoctorRules = [
|
|
|
37617
37759
|
rule: {
|
|
37618
37760
|
...preferStableEmptyFallback,
|
|
37619
37761
|
framework: "global",
|
|
37620
|
-
category: "Performance"
|
|
37762
|
+
category: "Performance",
|
|
37763
|
+
requires: [...new Set(["react", ...preferStableEmptyFallback.requires ?? []])]
|
|
37621
37764
|
}
|
|
37622
37765
|
},
|
|
37623
37766
|
{
|
|
@@ -37628,7 +37771,8 @@ const reactDoctorRules = [
|
|
|
37628
37771
|
rule: {
|
|
37629
37772
|
...preferTagOverRole,
|
|
37630
37773
|
framework: "global",
|
|
37631
|
-
category: "Accessibility"
|
|
37774
|
+
category: "Accessibility",
|
|
37775
|
+
requires: [...new Set(["react", ...preferTagOverRole.requires ?? []])]
|
|
37632
37776
|
}
|
|
37633
37777
|
},
|
|
37634
37778
|
{
|
|
@@ -37639,7 +37783,8 @@ const reactDoctorRules = [
|
|
|
37639
37783
|
rule: {
|
|
37640
37784
|
...preferUseEffectEvent,
|
|
37641
37785
|
framework: "global",
|
|
37642
|
-
category: "Bugs"
|
|
37786
|
+
category: "Bugs",
|
|
37787
|
+
requires: [...new Set(["react", ...preferUseEffectEvent.requires ?? []])]
|
|
37643
37788
|
}
|
|
37644
37789
|
},
|
|
37645
37790
|
{
|
|
@@ -37650,7 +37795,8 @@ const reactDoctorRules = [
|
|
|
37650
37795
|
rule: {
|
|
37651
37796
|
...preferUseSyncExternalStore,
|
|
37652
37797
|
framework: "global",
|
|
37653
|
-
category: "Bugs"
|
|
37798
|
+
category: "Bugs",
|
|
37799
|
+
requires: [...new Set(["react", ...preferUseSyncExternalStore.requires ?? []])]
|
|
37654
37800
|
}
|
|
37655
37801
|
},
|
|
37656
37802
|
{
|
|
@@ -37661,7 +37807,8 @@ const reactDoctorRules = [
|
|
|
37661
37807
|
rule: {
|
|
37662
37808
|
...preferUseReducer,
|
|
37663
37809
|
framework: "global",
|
|
37664
|
-
category: "Bugs"
|
|
37810
|
+
category: "Bugs",
|
|
37811
|
+
requires: [...new Set(["react", ...preferUseReducer.requires ?? []])]
|
|
37665
37812
|
}
|
|
37666
37813
|
},
|
|
37667
37814
|
{
|
|
@@ -37760,7 +37907,8 @@ const reactDoctorRules = [
|
|
|
37760
37907
|
rule: {
|
|
37761
37908
|
...reactInJsxScope,
|
|
37762
37909
|
framework: "global",
|
|
37763
|
-
category: "Bugs"
|
|
37910
|
+
category: "Bugs",
|
|
37911
|
+
requires: [...new Set(["react", ...reactInJsxScope.requires ?? []])]
|
|
37764
37912
|
}
|
|
37765
37913
|
},
|
|
37766
37914
|
{
|
|
@@ -37771,7 +37919,8 @@ const reactDoctorRules = [
|
|
|
37771
37919
|
rule: {
|
|
37772
37920
|
...reduxUseselectorInlineDerivation,
|
|
37773
37921
|
framework: "global",
|
|
37774
|
-
category: "Performance"
|
|
37922
|
+
category: "Performance",
|
|
37923
|
+
requires: [...new Set(["react", ...reduxUseselectorInlineDerivation.requires ?? []])]
|
|
37775
37924
|
}
|
|
37776
37925
|
},
|
|
37777
37926
|
{
|
|
@@ -37782,7 +37931,8 @@ const reactDoctorRules = [
|
|
|
37782
37931
|
rule: {
|
|
37783
37932
|
...reduxUseselectorReturnsNewCollection,
|
|
37784
37933
|
framework: "global",
|
|
37785
|
-
category: "Performance"
|
|
37934
|
+
category: "Performance",
|
|
37935
|
+
requires: [...new Set(["react", ...reduxUseselectorReturnsNewCollection.requires ?? []])]
|
|
37786
37936
|
}
|
|
37787
37937
|
},
|
|
37788
37938
|
{
|
|
@@ -37793,7 +37943,8 @@ const reactDoctorRules = [
|
|
|
37793
37943
|
rule: {
|
|
37794
37944
|
...renderingAnimateSvgWrapper,
|
|
37795
37945
|
framework: "global",
|
|
37796
|
-
category: "Performance"
|
|
37946
|
+
category: "Performance",
|
|
37947
|
+
requires: [...new Set(["react", ...renderingAnimateSvgWrapper.requires ?? []])]
|
|
37797
37948
|
}
|
|
37798
37949
|
},
|
|
37799
37950
|
{
|
|
@@ -37815,7 +37966,8 @@ const reactDoctorRules = [
|
|
|
37815
37966
|
rule: {
|
|
37816
37967
|
...renderingHoistJsx,
|
|
37817
37968
|
framework: "global",
|
|
37818
|
-
category: "Performance"
|
|
37969
|
+
category: "Performance",
|
|
37970
|
+
requires: [...new Set(["react", ...renderingHoistJsx.requires ?? []])]
|
|
37819
37971
|
}
|
|
37820
37972
|
},
|
|
37821
37973
|
{
|
|
@@ -37826,7 +37978,8 @@ const reactDoctorRules = [
|
|
|
37826
37978
|
rule: {
|
|
37827
37979
|
...renderingHydrationMismatchTime,
|
|
37828
37980
|
framework: "global",
|
|
37829
|
-
category: "Bugs"
|
|
37981
|
+
category: "Bugs",
|
|
37982
|
+
requires: [...new Set(["react", ...renderingHydrationMismatchTime.requires ?? []])]
|
|
37830
37983
|
}
|
|
37831
37984
|
},
|
|
37832
37985
|
{
|
|
@@ -37837,7 +37990,8 @@ const reactDoctorRules = [
|
|
|
37837
37990
|
rule: {
|
|
37838
37991
|
...renderingHydrationNoFlicker,
|
|
37839
37992
|
framework: "global",
|
|
37840
|
-
category: "Performance"
|
|
37993
|
+
category: "Performance",
|
|
37994
|
+
requires: [...new Set(["react", ...renderingHydrationNoFlicker.requires ?? []])]
|
|
37841
37995
|
}
|
|
37842
37996
|
},
|
|
37843
37997
|
{
|
|
@@ -37848,7 +38002,8 @@ const reactDoctorRules = [
|
|
|
37848
38002
|
rule: {
|
|
37849
38003
|
...renderingScriptDeferAsync,
|
|
37850
38004
|
framework: "global",
|
|
37851
|
-
category: "Performance"
|
|
38005
|
+
category: "Performance",
|
|
38006
|
+
requires: [...new Set(["react", ...renderingScriptDeferAsync.requires ?? []])]
|
|
37852
38007
|
}
|
|
37853
38008
|
},
|
|
37854
38009
|
{
|
|
@@ -37870,7 +38025,8 @@ const reactDoctorRules = [
|
|
|
37870
38025
|
rule: {
|
|
37871
38026
|
...renderingUsetransitionLoading,
|
|
37872
38027
|
framework: "global",
|
|
37873
|
-
category: "Performance"
|
|
38028
|
+
category: "Performance",
|
|
38029
|
+
requires: [...new Set(["react", ...renderingUsetransitionLoading.requires ?? []])]
|
|
37874
38030
|
}
|
|
37875
38031
|
},
|
|
37876
38032
|
{
|
|
@@ -37881,7 +38037,8 @@ const reactDoctorRules = [
|
|
|
37881
38037
|
rule: {
|
|
37882
38038
|
...requireRenderReturn,
|
|
37883
38039
|
framework: "global",
|
|
37884
|
-
category: "Bugs"
|
|
38040
|
+
category: "Bugs",
|
|
38041
|
+
requires: [...new Set(["react", ...requireRenderReturn.requires ?? []])]
|
|
37885
38042
|
}
|
|
37886
38043
|
},
|
|
37887
38044
|
{
|
|
@@ -37892,7 +38049,8 @@ const reactDoctorRules = [
|
|
|
37892
38049
|
rule: {
|
|
37893
38050
|
...rerenderDeferReadsHook,
|
|
37894
38051
|
framework: "global",
|
|
37895
|
-
category: "Performance"
|
|
38052
|
+
category: "Performance",
|
|
38053
|
+
requires: [...new Set(["react", ...rerenderDeferReadsHook.requires ?? []])]
|
|
37896
38054
|
}
|
|
37897
38055
|
},
|
|
37898
38056
|
{
|
|
@@ -37903,7 +38061,8 @@ const reactDoctorRules = [
|
|
|
37903
38061
|
rule: {
|
|
37904
38062
|
...rerenderDependencies,
|
|
37905
38063
|
framework: "global",
|
|
37906
|
-
category: "Bugs"
|
|
38064
|
+
category: "Bugs",
|
|
38065
|
+
requires: [...new Set(["react", ...rerenderDependencies.requires ?? []])]
|
|
37907
38066
|
}
|
|
37908
38067
|
},
|
|
37909
38068
|
{
|
|
@@ -37914,7 +38073,8 @@ const reactDoctorRules = [
|
|
|
37914
38073
|
rule: {
|
|
37915
38074
|
...rerenderDerivedStateFromHook,
|
|
37916
38075
|
framework: "global",
|
|
37917
|
-
category: "Performance"
|
|
38076
|
+
category: "Performance",
|
|
38077
|
+
requires: [...new Set(["react", ...rerenderDerivedStateFromHook.requires ?? []])]
|
|
37918
38078
|
}
|
|
37919
38079
|
},
|
|
37920
38080
|
{
|
|
@@ -37925,7 +38085,8 @@ const reactDoctorRules = [
|
|
|
37925
38085
|
rule: {
|
|
37926
38086
|
...rerenderFunctionalSetstate,
|
|
37927
38087
|
framework: "global",
|
|
37928
|
-
category: "Performance"
|
|
38088
|
+
category: "Performance",
|
|
38089
|
+
requires: [...new Set(["react", ...rerenderFunctionalSetstate.requires ?? []])]
|
|
37929
38090
|
}
|
|
37930
38091
|
},
|
|
37931
38092
|
{
|
|
@@ -37936,7 +38097,8 @@ const reactDoctorRules = [
|
|
|
37936
38097
|
rule: {
|
|
37937
38098
|
...rerenderLazyRefInit,
|
|
37938
38099
|
framework: "global",
|
|
37939
|
-
category: "Performance"
|
|
38100
|
+
category: "Performance",
|
|
38101
|
+
requires: [...new Set(["react", ...rerenderLazyRefInit.requires ?? []])]
|
|
37940
38102
|
}
|
|
37941
38103
|
},
|
|
37942
38104
|
{
|
|
@@ -37947,7 +38109,8 @@ const reactDoctorRules = [
|
|
|
37947
38109
|
rule: {
|
|
37948
38110
|
...rerenderLazyStateInit,
|
|
37949
38111
|
framework: "global",
|
|
37950
|
-
category: "Performance"
|
|
38112
|
+
category: "Performance",
|
|
38113
|
+
requires: [...new Set(["react", ...rerenderLazyStateInit.requires ?? []])]
|
|
37951
38114
|
}
|
|
37952
38115
|
},
|
|
37953
38116
|
{
|
|
@@ -37958,7 +38121,8 @@ const reactDoctorRules = [
|
|
|
37958
38121
|
rule: {
|
|
37959
38122
|
...rerenderMemoBeforeEarlyReturn,
|
|
37960
38123
|
framework: "global",
|
|
37961
|
-
category: "Performance"
|
|
38124
|
+
category: "Performance",
|
|
38125
|
+
requires: [...new Set(["react", ...rerenderMemoBeforeEarlyReturn.requires ?? []])]
|
|
37962
38126
|
}
|
|
37963
38127
|
},
|
|
37964
38128
|
{
|
|
@@ -37969,7 +38133,8 @@ const reactDoctorRules = [
|
|
|
37969
38133
|
rule: {
|
|
37970
38134
|
...rerenderMemoWithDefaultValue,
|
|
37971
38135
|
framework: "global",
|
|
37972
|
-
category: "Performance"
|
|
38136
|
+
category: "Performance",
|
|
38137
|
+
requires: [...new Set(["react", ...rerenderMemoWithDefaultValue.requires ?? []])]
|
|
37973
38138
|
}
|
|
37974
38139
|
},
|
|
37975
38140
|
{
|
|
@@ -37980,7 +38145,8 @@ const reactDoctorRules = [
|
|
|
37980
38145
|
rule: {
|
|
37981
38146
|
...rerenderStateOnlyInHandlers,
|
|
37982
38147
|
framework: "global",
|
|
37983
|
-
category: "Performance"
|
|
38148
|
+
category: "Performance",
|
|
38149
|
+
requires: [...new Set(["react", ...rerenderStateOnlyInHandlers.requires ?? []])]
|
|
37984
38150
|
}
|
|
37985
38151
|
},
|
|
37986
38152
|
{
|
|
@@ -37991,7 +38157,8 @@ const reactDoctorRules = [
|
|
|
37991
38157
|
rule: {
|
|
37992
38158
|
...rerenderTransitionsScroll,
|
|
37993
38159
|
framework: "global",
|
|
37994
|
-
category: "Performance"
|
|
38160
|
+
category: "Performance",
|
|
38161
|
+
requires: [...new Set(["react", ...rerenderTransitionsScroll.requires ?? []])]
|
|
37995
38162
|
}
|
|
37996
38163
|
},
|
|
37997
38164
|
{
|
|
@@ -38410,7 +38577,8 @@ const reactDoctorRules = [
|
|
|
38410
38577
|
rule: {
|
|
38411
38578
|
...roleHasRequiredAriaProps,
|
|
38412
38579
|
framework: "global",
|
|
38413
|
-
category: "Accessibility"
|
|
38580
|
+
category: "Accessibility",
|
|
38581
|
+
requires: [...new Set(["react", ...roleHasRequiredAriaProps.requires ?? []])]
|
|
38414
38582
|
}
|
|
38415
38583
|
},
|
|
38416
38584
|
{
|
|
@@ -38421,7 +38589,8 @@ const reactDoctorRules = [
|
|
|
38421
38589
|
rule: {
|
|
38422
38590
|
...roleSupportsAriaProps,
|
|
38423
38591
|
framework: "global",
|
|
38424
|
-
category: "Accessibility"
|
|
38592
|
+
category: "Accessibility",
|
|
38593
|
+
requires: [...new Set(["react", ...roleSupportsAriaProps.requires ?? []])]
|
|
38425
38594
|
}
|
|
38426
38595
|
},
|
|
38427
38596
|
{
|
|
@@ -38432,7 +38601,8 @@ const reactDoctorRules = [
|
|
|
38432
38601
|
rule: {
|
|
38433
38602
|
...rulesOfHooks,
|
|
38434
38603
|
framework: "global",
|
|
38435
|
-
category: "Bugs"
|
|
38604
|
+
category: "Bugs",
|
|
38605
|
+
requires: [...new Set(["react", ...rulesOfHooks.requires ?? []])]
|
|
38436
38606
|
}
|
|
38437
38607
|
},
|
|
38438
38608
|
{
|
|
@@ -38443,7 +38613,8 @@ const reactDoctorRules = [
|
|
|
38443
38613
|
rule: {
|
|
38444
38614
|
...scope,
|
|
38445
38615
|
framework: "global",
|
|
38446
|
-
category: "Accessibility"
|
|
38616
|
+
category: "Accessibility",
|
|
38617
|
+
requires: [...new Set(["react", ...scope.requires ?? []])]
|
|
38447
38618
|
}
|
|
38448
38619
|
},
|
|
38449
38620
|
{
|
|
@@ -38454,7 +38625,8 @@ const reactDoctorRules = [
|
|
|
38454
38625
|
rule: {
|
|
38455
38626
|
...selfClosingComp,
|
|
38456
38627
|
framework: "global",
|
|
38457
|
-
category: "Maintainability"
|
|
38628
|
+
category: "Maintainability",
|
|
38629
|
+
requires: [...new Set(["react", ...selfClosingComp.requires ?? []])]
|
|
38458
38630
|
}
|
|
38459
38631
|
},
|
|
38460
38632
|
{
|
|
@@ -38561,7 +38733,8 @@ const reactDoctorRules = [
|
|
|
38561
38733
|
rule: {
|
|
38562
38734
|
...stateInConstructor,
|
|
38563
38735
|
framework: "global",
|
|
38564
|
-
category: "Maintainability"
|
|
38736
|
+
category: "Maintainability",
|
|
38737
|
+
requires: [...new Set(["react", ...stateInConstructor.requires ?? []])]
|
|
38565
38738
|
}
|
|
38566
38739
|
},
|
|
38567
38740
|
{
|
|
@@ -38572,7 +38745,8 @@ const reactDoctorRules = [
|
|
|
38572
38745
|
rule: {
|
|
38573
38746
|
...stylePropObject,
|
|
38574
38747
|
framework: "global",
|
|
38575
|
-
category: "Bugs"
|
|
38748
|
+
category: "Bugs",
|
|
38749
|
+
requires: [...new Set(["react", ...stylePropObject.requires ?? []])]
|
|
38576
38750
|
}
|
|
38577
38751
|
},
|
|
38578
38752
|
{
|
|
@@ -38583,7 +38757,8 @@ const reactDoctorRules = [
|
|
|
38583
38757
|
rule: {
|
|
38584
38758
|
...tabindexNoPositive,
|
|
38585
38759
|
framework: "global",
|
|
38586
|
-
category: "Accessibility"
|
|
38760
|
+
category: "Accessibility",
|
|
38761
|
+
requires: [...new Set(["react", ...tabindexNoPositive.requires ?? []])]
|
|
38587
38762
|
}
|
|
38588
38763
|
},
|
|
38589
38764
|
{
|
|
@@ -38759,7 +38934,8 @@ const reactDoctorRules = [
|
|
|
38759
38934
|
rule: {
|
|
38760
38935
|
...voidDomElementsNoChildren,
|
|
38761
38936
|
framework: "global",
|
|
38762
|
-
category: "Bugs"
|
|
38937
|
+
category: "Bugs",
|
|
38938
|
+
requires: [...new Set(["react", ...voidDomElementsNoChildren.requires ?? []])]
|
|
38763
38939
|
}
|
|
38764
38940
|
},
|
|
38765
38941
|
{
|