eslint-plugin-react-x
Version:
A set of composable ESLint rules for for libraries and frameworks that use React as a UI runtime.
1,471 lines (1,435 loc) • 138 kB
JavaScript
import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, coerceSettings, getConfigAdapters, getSettingsFromContext, report, toRegExp } from "@eslint-react/shared";
import { AST_NODE_TYPES } from "@typescript-eslint/types";
import { ESLintUtils } from "@typescript-eslint/utils";
import { isFalseLiteralType, isPropertyReadonlyInType, isTrueLiteralType, isTypeFlagSet, unionConstituents } from "ts-api-utils";
import { P, isMatching, match } from "ts-pattern";
import ts from "typescript";
import * as AST from "@eslint-react/ast";
import { findVariable, getChildScopes, getObjectType, getVariableDefinitionNode } from "@eslint-react/var";
import { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, findParentJsxAttribute, getInstanceId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isAssignmentToThisState, isCaptureOwnerStackCall, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUpdate, isCreateContextCall, isCreateElementCall, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRefCall, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInstanceIdEqual, isJsxFragmentElement, isJsxHostElement, isJsxText, isLazyCall, isReactHookCall, isReactHookName, isRenderMethodLike, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseCall, isUseCallbackCall, isUseContextCall, isUseEffectLikeCall, isUseMemoCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core";
import { constFalse, constTrue, flow, getOrElseUpdate, identity, unit } from "@eslint-react/eff";
import { compare } from "compare-versions";
import { getConstrainedTypeAtLocation, isTypeReadonly } from "@typescript-eslint/type-utils";
import { getStaticValue, isIdentifier, isVariableDeclarator } from "@typescript-eslint/utils/ast-utils";
import "@typescript-eslint/utils/ts-eslint";
import { getTypeImmutability, isImmutable, isReadonlyDeep, isReadonlyShallow, isUnknown } from "is-immutable-type";
import { camelCase } from "string-ts";
//#region rolldown:runtime
var __defProp = Object.defineProperty;
var __export = (all, symbols) => {
let target = {};
for (var name$7 in all) {
__defProp(target, name$7, {
get: all[name$7],
enumerable: true
});
}
if (symbols) {
__defProp(target, Symbol.toStringTag, { value: "Module" });
}
return target;
};
//#endregion
//#region package.json
var name$6 = "eslint-plugin-react-x";
var version = "2.3.13";
//#endregion
//#region src/utils/create-rule.ts
function getDocsUrl(ruleName) {
return `${WEBSITE_URL}/docs/rules/${ruleName}`;
}
const createRule = ESLintUtils.RuleCreator(getDocsUrl);
//#endregion
//#region src/utils/type-is.ts
/** @internal */
const isAnyType = (type) => isTypeFlagSet(type, ts.TypeFlags.TypeParameter | ts.TypeFlags.Any);
/** @internal */
const isBigIntType = (type) => isTypeFlagSet(type, ts.TypeFlags.BigIntLike);
/** @internal */
const isBooleanType = (type) => isTypeFlagSet(type, ts.TypeFlags.BooleanLike);
/** @internal */
const isEnumType = (type) => isTypeFlagSet(type, ts.TypeFlags.EnumLike);
/** @internal */
const isFalsyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: "0" } }, type);
/** @internal */
const isFalsyNumberType = (type) => type.isNumberLiteral() && type.value === 0;
/** @internal */
const isFalsyStringType = (type) => type.isStringLiteral() && type.value === "";
/** @internal */
const isNeverType = (type) => isTypeFlagSet(type, ts.TypeFlags.Never);
/** @internal */
const isNullishType = (type) => isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike);
/** @internal */
const isNumberType = (type) => isTypeFlagSet(type, ts.TypeFlags.NumberLike);
/** @internal */
const isObjectType = (type) => !isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike | ts.TypeFlags.BooleanLike | ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike | ts.TypeFlags.TypeParameter | ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never);
/** @internal */
const isStringType = (type) => isTypeFlagSet(type, ts.TypeFlags.StringLike);
/** @internal */
const isTruthyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: P.not("0") } }, type);
/** @internal */
const isTruthyNumberType = (type) => type.isNumberLiteral() && type.value !== 0;
/** @internal */
const isTruthyStringType = (type) => type.isStringLiteral() && type.value !== "";
/** @internal */
const isUnknownType = (type) => isTypeFlagSet(type, ts.TypeFlags.Unknown);
//#endregion
//#region src/utils/type-variant.ts
/**
* Ported from https://github.com/typescript-eslint/typescript-eslint/blob/eb736bbfc22554694400e6a4f97051d845d32e0b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts#L826 with some enhancements
* Get the variants of an array of types.
* @param types The types to get the variants of
* @returns The variants of the types
* @internal
*/
function getTypeVariants(types) {
const variants = /* @__PURE__ */ new Set();
if (types.some(isUnknownType)) {
variants.add("unknown");
return variants;
}
if (types.some(isNullishType)) variants.add("nullish");
const booleans = types.filter(isBooleanType);
const boolean0 = booleans[0];
if (booleans.length === 1 && boolean0 != null) {
if (isFalseLiteralType(boolean0)) variants.add("falsy boolean");
else if (isTrueLiteralType(boolean0)) variants.add("truthy boolean");
} else if (booleans.length === 2) variants.add("boolean");
const strings = types.filter(isStringType);
if (strings.length > 0) {
const evaluated = match(strings).when((types$1) => types$1.every(isTruthyStringType), () => "truthy string").when((types$1) => types$1.every(isFalsyStringType), () => "falsy string").otherwise(() => "string");
variants.add(evaluated);
}
const bigints = types.filter(isBigIntType);
if (bigints.length > 0) {
const evaluated = match(bigints).when((types$1) => types$1.every(isTruthyBigIntType), () => "truthy bigint").when((types$1) => types$1.every(isFalsyBigIntType), () => "falsy bigint").otherwise(() => "bigint");
variants.add(evaluated);
}
const numbers = types.filter(isNumberType);
if (numbers.length > 0) {
const evaluated = match(numbers).when((types$1) => types$1.every(isTruthyNumberType), () => "truthy number").when((types$1) => types$1.every(isFalsyNumberType), () => "falsy number").otherwise(() => "number");
variants.add(evaluated);
}
if (types.some(isEnumType)) variants.add("enum");
if (types.some(isObjectType)) variants.add("object");
if (types.some(isAnyType)) variants.add("any");
if (types.some(isNeverType)) variants.add("never");
return variants;
}
//#endregion
//#region src/rules/jsx-dollar.ts
const RULE_NAME$62 = "jsx-dollar";
const RULE_FEATURES$62 = [];
var jsx_dollar_default = createRule({
meta: {
type: "problem",
docs: {
description: "Prevents dollar signs from being inserted as text nodes before expressions.",
[Symbol.for("rule_features")]: RULE_FEATURES$62
},
fixable: "code",
hasSuggestions: true,
messages: {
jsxDollar: "Possible unnecessary '$' character before expression.",
removeDollarSign: "Remove the dollar sign '$' before the expression."
},
schema: []
},
name: RULE_NAME$62,
create: create$62,
defaultOptions: []
});
function create$62(context) {
/**
* Visitor function for JSXElement and JSXFragment nodes
* @param node The JSXElement or JSXFragment node to be checked
*/
const visitorFunction = (node) => {
for (const [index, child] of node.children.entries()) {
if (child.type !== AST_NODE_TYPES.JSXText || !child.value.endsWith("$")) continue;
if (node.children[index + 1]?.type !== AST_NODE_TYPES.JSXExpressionContainer) continue;
if (child.value === "$" && node.children.length === 2) continue;
const pos = child.loc.end;
context.report({
messageId: "jsxDollar",
node: child,
loc: {
end: {
column: pos.column,
line: pos.line
},
start: {
column: pos.column - 1,
line: pos.line
}
},
suggest: [{
messageId: "removeDollarSign",
fix(fixer) {
return fixer.removeRange([child.range[1] - 1, child.range[1]]);
}
}]
});
}
};
return {
JSXElement: visitorFunction,
JSXFragment: visitorFunction
};
}
//#endregion
//#region src/rules/jsx-key-before-spread.ts
const RULE_NAME$61 = "jsx-key-before-spread";
const RULE_FEATURES$61 = ["EXP"];
var jsx_key_before_spread_default = createRule({
meta: {
type: "problem",
docs: {
description: "Enforces that the 'key' prop is placed before the spread prop in JSX elements.",
[Symbol.for("rule_features")]: RULE_FEATURES$61
},
messages: { jsxKeyBeforeSpread: "The 'key' prop must be placed before any spread props." },
schema: []
},
name: RULE_NAME$61,
create: create$61,
defaultOptions: []
});
function create$61(context) {
return { JSXOpeningElement(node) {
let firstSpreadPropIndex = null;
for (const [index, prop] of node.attributes.entries()) {
if (prop.type === AST_NODE_TYPES.JSXSpreadAttribute) {
firstSpreadPropIndex ??= index;
continue;
}
if (firstSpreadPropIndex == null) continue;
if (prop.name.name === "key" && index > firstSpreadPropIndex) context.report({
messageId: "jsxKeyBeforeSpread",
node: prop
});
}
} };
}
//#endregion
//#region src/rules/jsx-no-comment-textnodes.ts
const RULE_NAME$60 = "jsx-no-comment-textnodes";
const RULE_FEATURES$60 = [];
var jsx_no_comment_textnodes_default = createRule({
meta: {
type: "problem",
docs: {
description: "Prevents comments from being inserted as text nodes.",
[Symbol.for("rule_features")]: RULE_FEATURES$60
},
messages: { jsxNoCommentTextnodes: "Possible misused comment in text node. Comments inside children section of tag should be placed inside braces." },
schema: []
},
name: RULE_NAME$60,
create: create$60,
defaultOptions: []
});
function create$60(context) {
function hasCommentLike(node) {
if (AST.isOneOf([AST_NODE_TYPES.JSXAttribute, AST_NODE_TYPES.JSXExpressionContainer])(node.parent)) return false;
return /^\s*\/(?:\/|\*)/mu.test(context.sourceCode.getText(node));
}
const visitorFunction = (node) => {
if (!AST.isOneOf([AST_NODE_TYPES.JSXElement, AST_NODE_TYPES.JSXFragment])(node.parent)) return;
if (!hasCommentLike(node)) return;
context.report({
messageId: "jsxNoCommentTextnodes",
node
});
};
return {
JSXText: visitorFunction,
Literal: visitorFunction
};
}
//#endregion
//#region src/rules/jsx-no-duplicate-props.ts
const RULE_NAME$59 = "jsx-no-duplicate-props";
const RULE_FEATURES$59 = [];
var jsx_no_duplicate_props_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow duplicate props in JSX elements.",
[Symbol.for("rule_features")]: RULE_FEATURES$59
},
messages: { jsxNoDuplicateProps: "This JSX property is assigned multiple times." },
schema: []
},
name: RULE_NAME$59,
create: create$59,
defaultOptions: []
});
function create$59(context) {
return { JSXOpeningElement(node) {
const props = [];
for (const attr of node.attributes) {
if (attr.type === AST_NODE_TYPES.JSXSpreadAttribute) continue;
const name$7 = attr.name.name;
if (typeof name$7 !== "string") continue;
if (!props.includes(name$7)) {
props.push(name$7);
continue;
}
context.report({
messageId: "jsxNoDuplicateProps",
node: attr
});
}
} };
}
//#endregion
//#region src/rules/jsx-no-iife.ts
const RULE_NAME$58 = "jsx-no-iife";
const RULE_FEATURES$58 = ["EXP"];
var jsx_no_iife_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallows 'IIFE' in JSX elements.",
[Symbol.for("rule_features")]: RULE_FEATURES$58
},
messages: { jsxNoIife: "Avoid using IIFE in JSX elements." },
schema: []
},
name: RULE_NAME$58,
create: create$58,
defaultOptions: []
});
function create$58(context) {
return {
"JSXElement :function"(node) {
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) context.report({
messageId: "jsxNoIife",
node: node.parent
});
},
"JSXFragment :function"(node) {
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) context.report({
messageId: "jsxNoIife",
node: node.parent
});
}
};
}
//#endregion
//#region src/rules/jsx-no-undef.ts
const RULE_NAME$57 = "jsx-no-undef";
const RULE_FEATURES$57 = [];
var jsx_no_undef_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow undefined variables in JSX.",
[Symbol.for("rule_features")]: RULE_FEATURES$57
},
messages: { jsxNoUndef: "JSX variable '{{name}}' is not defined." },
schema: []
},
name: RULE_NAME$57,
create: create$57,
defaultOptions: []
});
function create$57(context) {
return { JSXOpeningElement(node) {
const name$7 = match(node.name).with({ type: AST_NODE_TYPES.JSXIdentifier }, (n) => n.name).with({
type: AST_NODE_TYPES.JSXMemberExpression,
object: { type: AST_NODE_TYPES.JSXIdentifier }
}, (n) => n.object.name).otherwise(() => null);
if (name$7 == null) return;
if (name$7 === "this") return;
if (/^[a-z]/u.test(name$7)) return;
if (findVariable(name$7, context.sourceCode.getScope(node)) == null) context.report({
messageId: "jsxNoUndef",
node,
data: { name: name$7 }
});
} };
}
//#endregion
//#region src/rules/jsx-shorthand-boolean.ts
const RULE_NAME$56 = "jsx-shorthand-boolean";
const RULE_FEATURES$56 = ["CFG", "FIX"];
const defaultOptions$4 = [1];
const schema$3 = [{
type: "integer",
enum: [-1, 1]
}];
var jsx_shorthand_boolean_default = createRule({
meta: {
type: "problem",
docs: {
description: "Enforces shorthand syntax for boolean attributes.",
[Symbol.for("rule_features")]: RULE_FEATURES$56
},
fixable: "code",
messages: { jsxShorthandBoolean: "{{message}}" },
schema: schema$3
},
name: RULE_NAME$56,
create: create$56,
defaultOptions: defaultOptions$4
});
function create$56(context) {
const policy = context.options[0] ?? defaultOptions$4[0];
return { JSXAttribute(node) {
const { value } = node;
const propName = getJsxAttributeName(context, node);
switch (true) {
case policy === 1 && value?.type === AST_NODE_TYPES.JSXExpressionContainer && value.expression.type === AST_NODE_TYPES.Literal && value.expression.value === true:
context.report({
messageId: "jsxShorthandBoolean",
node,
data: { message: `Omit attribute value for '${propName}'.` },
fix: (fixer) => fixer.removeRange([node.name.range[1], value.range[1]])
});
break;
case policy === -1 && value === null:
context.report({
messageId: "jsxShorthandBoolean",
node: node.value ?? node,
data: { message: `Set attribute value for '${propName}'.` },
fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`)
});
break;
}
} };
}
//#endregion
//#region src/rules/jsx-shorthand-fragment.ts
const RULE_NAME$55 = "jsx-shorthand-fragment";
const RULE_FEATURES$55 = ["CFG", "FIX"];
const defaultOptions$3 = [1];
const schema$2 = [{
type: "integer",
enum: [-1, 1]
}];
var jsx_shorthand_fragment_default = createRule({
meta: {
type: "problem",
docs: {
description: "Enforces shorthand syntax for fragments.",
[Symbol.for("rule_features")]: RULE_FEATURES$55
},
fixable: "code",
messages: { jsxShorthandFragment: "{{message}}" },
schema: schema$2
},
name: RULE_NAME$55,
create: create$55,
defaultOptions: defaultOptions$3
});
function create$55(context) {
const policy = context.options[0] ?? defaultOptions$3[0];
const { jsxFragmentFactory } = {
...getJsxConfigFromContext(context),
...getJsxConfigFromAnnotation(context)
};
return match(policy).with(1, () => ({ JSXElement(node) {
if (!isJsxFragmentElement(context, node)) return;
if (node.openingElement.attributes.length > 0) return;
context.report({
messageId: "jsxShorthandFragment",
node,
data: { message: "Use fragment shorthand syntax instead of 'Fragment' component." },
fix: (fixer) => {
const { closingElement, openingElement } = node;
if (closingElement == null) return [];
return [fixer.replaceTextRange([openingElement.range[0], openingElement.range[1]], "<>"), fixer.replaceTextRange([closingElement.range[0], closingElement.range[1]], "</>")];
}
});
} })).with(-1, () => ({ JSXFragment(node) {
context.report({
messageId: "jsxShorthandFragment",
node,
data: { message: "Use 'Fragment' component instead of fragment shorthand syntax." },
fix: (fixer) => {
const { closingFragment, openingFragment } = node;
return [fixer.replaceTextRange([openingFragment.range[0], openingFragment.range[1]], `<${jsxFragmentFactory}>`), fixer.replaceTextRange([closingFragment.range[0], closingFragment.range[1]], `</${jsxFragmentFactory}>`)];
}
});
} })).otherwise(() => ({}));
}
//#endregion
//#region src/rules/jsx-uses-react.ts
const RULE_NAME$54 = "jsx-uses-react";
const RULE_FEATURES$54 = [];
var jsx_uses_react_default = createRule({
meta: {
type: "problem",
docs: {
description: "Marks React variables as used when JSX is used.",
[Symbol.for("rule_features")]: RULE_FEATURES$54
},
messages: { jsxUsesReact: "Marked {{name}} as used." },
schema: []
},
name: RULE_NAME$54,
create: create$54,
defaultOptions: []
});
function create$54(context) {
const { jsx, jsxFactory, jsxFragmentFactory } = {
...getJsxConfigFromContext(context),
...getJsxConfigFromAnnotation(context)
};
if (jsx === JsxEmit.ReactJSX || jsx === JsxEmit.ReactJSXDev) return {};
function handleJsxElement(node) {
context.sourceCode.markVariableAsUsed(jsxFactory, node);
debugReport(context, node, jsxFactory);
}
function handleJsxFragment(node) {
context.sourceCode.markVariableAsUsed(jsxFragmentFactory, node);
debugReport(context, node, jsxFragmentFactory);
}
return {
JSXFragment: handleJsxFragment,
JSXOpeningElement: handleJsxElement,
JSXOpeningFragment: handleJsxElement
};
}
function debugReport(context, node, name$7) {
if (process.env["ESLINT_REACT_DEBUG"] !== "1") return;
context.report({
messageId: "jsxUsesReact",
node,
data: { name: name$7 }
});
}
//#endregion
//#region src/rules/jsx-uses-vars.ts
const RULE_NAME$53 = "jsx-uses-vars";
const RULE_FEATURES$53 = [];
var jsx_uses_vars_default = createRule({
meta: {
type: "problem",
docs: {
description: "Marks variables used in JSX elements as used.",
[Symbol.for("rule_features")]: RULE_FEATURES$53
},
messages: { jsxUsesVars: "An identifier in JSX is marked as used." },
schema: []
},
name: RULE_NAME$53,
create: create$53,
defaultOptions: []
});
function create$53(context) {
return { JSXOpeningElement(node) {
switch (node.name.type) {
case AST_NODE_TYPES.JSXIdentifier:
if (/^[a-z]/u.test(node.name.name)) return;
context.sourceCode.markVariableAsUsed(node.name.name, node);
break;
case AST_NODE_TYPES.JSXMemberExpression: {
const { object } = node.name;
if (object.type === AST_NODE_TYPES.JSXIdentifier) context.sourceCode.markVariableAsUsed(object.name, node);
break;
}
}
} };
}
//#endregion
//#region src/rules/no-access-state-in-setstate.ts
const RULE_NAME$52 = "no-access-state-in-setstate";
const RULE_FEATURES$52 = [];
function isKeyLiteral$2(node, key) {
return match(key).with({ type: AST_NODE_TYPES.Literal }, constTrue).with({
type: AST_NODE_TYPES.TemplateLiteral,
expressions: []
}, constTrue).with({ type: AST_NODE_TYPES.Identifier }, () => !node.computed).otherwise(constFalse);
}
var no_access_state_in_setstate_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow accessing `this.state` inside `setState` calls.",
[Symbol.for("rule_features")]: RULE_FEATURES$52
},
messages: { noAccessStateInSetstate: "Do not access 'this.state' within 'setState'. Use the update function instead." },
schema: []
},
name: RULE_NAME$52,
create: create$52,
defaultOptions: []
});
function create$52(context) {
if (!context.sourceCode.text.includes("setState")) return {};
const classStack = [];
const methodStack = [];
const setStateStack = [];
return {
CallExpression(node) {
if (!isThisSetState(node)) return;
setStateStack.push([node, false]);
},
"CallExpression:exit"(node) {
if (!isThisSetState(node)) return;
setStateStack.pop();
},
ClassDeclaration(node) {
classStack.push([node, isClassComponent(node)]);
},
"ClassDeclaration:exit"() {
classStack.pop();
},
ClassExpression(node) {
classStack.push([node, isClassComponent(node)]);
},
"ClassExpression:exit"() {
classStack.pop();
},
MemberExpression(node) {
if (!AST.isThisExpression(node.object)) return;
const [currClass, isComponent = false] = classStack.at(-1) ?? [];
if (currClass == null || !isComponent) return;
const [currMethod, isStatic = false] = methodStack.at(-1) ?? [];
if (currMethod == null || isStatic) return;
const [setState, hasThisState = false] = setStateStack.at(-1) ?? [];
if (setState == null || hasThisState) return;
if (AST.getPropertyName(node.property) !== "state") return;
context.report({
messageId: "noAccessStateInSetstate",
node
});
},
MethodDefinition(node) {
methodStack.push([node, node.static]);
},
"MethodDefinition:exit"() {
methodStack.pop();
},
PropertyDefinition(node) {
methodStack.push([node, node.static]);
},
"PropertyDefinition:exit"() {
methodStack.pop();
},
VariableDeclarator(node) {
const [currClass, isComponent = false] = classStack.at(-1) ?? [];
if (currClass == null || !isComponent) return;
const [currMethod, isStatic = false] = methodStack.at(-1) ?? [];
if (currMethod == null || isStatic) return;
const [setState, hasThisState = false] = setStateStack.at(-1) ?? [];
if (setState == null || hasThisState) return;
if (node.init == null || !AST.isThisExpression(node.init) || node.id.type !== AST_NODE_TYPES.ObjectPattern) return;
if (!node.id.properties.some((prop) => prop.type === AST_NODE_TYPES.Property && isKeyLiteral$2(prop, prop.key) && AST.getPropertyName(prop.key) === "state")) return;
context.report({
messageId: "noAccessStateInSetstate",
node
});
}
};
}
//#endregion
//#region src/rules/no-array-index-key.ts
const RULE_NAME$51 = "no-array-index-key";
const RULE_FEATURES$51 = [];
const REACT_CHILDREN_METHOD = ["forEach", "map"];
function isReactChildrenMethod(name$7) {
return REACT_CHILDREN_METHOD.includes(name$7);
}
function isUsingReactChildren(context, node) {
const { importSource = "react" } = coerceSettings(context.settings);
const { callee } = node;
if (!("property" in callee) || !("object" in callee) || !("name" in callee.property)) return false;
if (!isReactChildrenMethod(callee.property.name)) return false;
const initialScope = context.sourceCode.getScope(node);
if (callee.object.type === AST_NODE_TYPES.Identifier && callee.object.name === "Children") return true;
if (callee.object.type === AST_NODE_TYPES.MemberExpression && "name" in callee.object.object) return isInitializedFromReact(callee.object.object.name, importSource, initialScope);
return false;
}
function getMapIndexParamName(context, node) {
const { callee } = node;
if (callee.type !== AST_NODE_TYPES.MemberExpression) return unit;
if (callee.property.type !== AST_NODE_TYPES.Identifier) return unit;
const { name: name$7 } = callee.property;
const indexPosition = AST.getArrayMethodCallbackIndexParamPosition(name$7);
if (indexPosition === -1) return unit;
const callbackArg = node.arguments[isUsingReactChildren(context, node) ? 1 : 0];
if (callbackArg == null) return unit;
if (!AST.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(callbackArg)) return unit;
const { params } = callbackArg;
if (params.length < indexPosition + 1) return unit;
const param = params.at(indexPosition);
return param != null && "name" in param ? param.name : unit;
}
function getIdentifiersFromBinaryExpression(side) {
if (side.type === AST_NODE_TYPES.Identifier) return [side];
if (side.type === AST_NODE_TYPES.BinaryExpression) return [...getIdentifiersFromBinaryExpression(side.left), ...getIdentifiersFromBinaryExpression(side.right)];
return [];
}
var no_array_index_key_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow an item's index in the array as its key.",
[Symbol.for("rule_features")]: RULE_FEATURES$51
},
messages: { noArrayIndexKey: "Do not use item index in the array as its key." },
schema: []
},
name: RULE_NAME$51,
create: create$51,
defaultOptions: []
});
function create$51(context) {
const indexParamNames = [];
function isArrayIndex(node) {
return node.type === AST_NODE_TYPES.Identifier && indexParamNames.some((name$7) => name$7 != null && name$7 === node.name);
}
function isCreateOrCloneElementCall(node) {
return isCreateElementCall(context, node) || isCloneElementCall(context, node);
}
function getReportDescriptors(node) {
switch (node.type) {
case AST_NODE_TYPES.Identifier:
if (indexParamNames.some((name$7) => name$7 != null && name$7 === node.name)) return [{
messageId: "noArrayIndexKey",
node
}];
return [];
case AST_NODE_TYPES.TemplateLiteral:
case AST_NODE_TYPES.BinaryExpression: {
const descriptors = [];
const expressions = node.type === AST_NODE_TYPES.TemplateLiteral ? node.expressions : getIdentifiersFromBinaryExpression(node);
for (const expression of expressions) if (isArrayIndex(expression)) descriptors.push({
messageId: "noArrayIndexKey",
node: expression
});
return descriptors;
}
case AST_NODE_TYPES.CallExpression: switch (true) {
case node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "toString" && isArrayIndex(node.callee.object): return [{
messageId: "noArrayIndexKey",
node: node.callee.object
}];
case node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "String" && node.arguments[0] != null && isArrayIndex(node.arguments[0]): return [{
messageId: "noArrayIndexKey",
node: node.arguments[0]
}];
}
}
return [];
}
return {
CallExpression(node) {
indexParamNames.push(getMapIndexParamName(context, node));
if (node.arguments.length === 0) return;
if (!isCreateOrCloneElementCall(node)) return;
const [, props] = node.arguments;
if (props?.type !== AST_NODE_TYPES.ObjectExpression) return;
for (const prop of props.properties) {
if (!isMatching({ key: { name: "key" } })(prop)) continue;
if (!("value" in prop)) continue;
for (const descriptor of getReportDescriptors(prop.value)) report(context)(descriptor);
}
},
"CallExpression:exit"() {
indexParamNames.pop();
},
JSXAttribute(node) {
if (node.name.name !== "key") return;
if (indexParamNames.length === 0) return;
if (node.value?.type !== AST_NODE_TYPES.JSXExpressionContainer) return;
for (const descriptor of getReportDescriptors(node.value.expression)) report(context)(descriptor);
}
};
}
//#endregion
//#region src/rules/no-children-count.ts
const RULE_NAME$50 = "no-children-count";
const RULE_FEATURES$50 = [];
var no_children_count_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.count`.",
[Symbol.for("rule_features")]: RULE_FEATURES$50
},
messages: { noChildrenCount: "Using 'Children.count' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$50,
create: create$50,
defaultOptions: []
});
function create$50(context) {
return { MemberExpression(node) {
if (isChildrenCount(context, node)) context.report({
messageId: "noChildrenCount",
node: node.property
});
} };
}
//#endregion
//#region src/rules/no-children-for-each.ts
const RULE_NAME$49 = "no-children-for-each";
const RULE_FEATURES$49 = [];
var no_children_for_each_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow 'Children.forEach'.",
[Symbol.for("rule_features")]: RULE_FEATURES$49
},
messages: { noChildrenForEach: "Using 'Children.forEach' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$49,
create: create$49,
defaultOptions: []
});
function create$49(context) {
return { MemberExpression(node) {
if (isChildrenForEach(context, node)) context.report({
messageId: "noChildrenForEach",
node: node.property
});
} };
}
//#endregion
//#region src/rules/no-children-map.ts
const RULE_NAME$48 = "no-children-map";
const RULE_FEATURES$48 = [];
var no_children_map_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.map`.",
[Symbol.for("rule_features")]: RULE_FEATURES$48
},
messages: { noChildrenMap: "Using 'Children.map' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$48,
create: create$48,
defaultOptions: []
});
function create$48(context) {
return { MemberExpression(node) {
if (isChildrenMap(context, node)) context.report({
messageId: "noChildrenMap",
node: node.property
});
} };
}
//#endregion
//#region src/rules/no-children-only.ts
const RULE_NAME$47 = "no-children-only";
const RULE_FEATURES$47 = [];
var no_children_only_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.only`.",
[Symbol.for("rule_features")]: RULE_FEATURES$47
},
messages: { noChildrenOnly: "Using 'Children.only' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$47,
create: create$47,
defaultOptions: []
});
function create$47(context) {
return { MemberExpression(node) {
if (isChildrenOnly(context, node)) context.report({
messageId: "noChildrenOnly",
node: node.property
});
} };
}
//#endregion
//#region src/rules/no-children-prop.ts
const RULE_NAME$46 = "no-children-prop";
const RULE_FEATURES$46 = [];
var no_children_prop_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow passing `children` as a prop.",
[Symbol.for("rule_features")]: RULE_FEATURES$46
},
messages: { noChildrenProp: "Do not pass 'children' as props." },
schema: []
},
name: RULE_NAME$46,
create: create$46,
defaultOptions: []
});
function create$46(context) {
return { JSXElement(node) {
const childrenProp = getJsxAttribute(context, node)("children");
if (childrenProp != null) context.report({
messageId: "noChildrenProp",
node: childrenProp
});
} };
}
//#endregion
//#region src/rules/no-children-to-array.ts
const RULE_NAME$45 = "no-children-to-array";
const RULE_FEATURES$45 = [];
var no_children_to_array_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.toArray`.",
[Symbol.for("rule_features")]: RULE_FEATURES$45
},
messages: { noChildrenToArray: "Using 'Children.toArray' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$45,
create: create$45,
defaultOptions: []
});
function create$45(context) {
return { MemberExpression(node) {
if (isChildrenToArray(context, node)) context.report({
messageId: "noChildrenToArray",
node: node.property
});
} };
}
//#endregion
//#region src/rules/no-class-component.ts
const RULE_NAME$44 = "no-class-component";
const RULE_FEATURES$44 = [];
var no_class_component_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow class components except for error boundaries.",
[Symbol.for("rule_features")]: RULE_FEATURES$44
},
messages: { noClassComponent: "Avoid using class components. Use function components instead." },
schema: []
},
name: RULE_NAME$44,
create: create$44,
defaultOptions: []
});
function create$44(context) {
if (!context.sourceCode.text.includes("Component")) return {};
const { ctx, listeners } = useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
for (const { name: name$7 = "anonymous", node: component } of ctx.getAllComponents(program)) {
if (component.body.body.some((m) => isComponentDidCatch(m) || isGetDerivedStateFromError(m))) continue;
context.report({
messageId: "noClassComponent",
node: component,
data: { name: name$7 }
});
}
}
};
}
//#endregion
//#region src/rules/no-clone-element.ts
const RULE_NAME$43 = "no-clone-element";
const RULE_FEATURES$43 = [];
var no_clone_element_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `cloneElement`.",
[Symbol.for("rule_features")]: RULE_FEATURES$43
},
messages: { noCloneElement: "Using 'cloneElement' is uncommon and can lead to fragile code. Use alternatives instead." },
schema: []
},
name: RULE_NAME$43,
create: create$43,
defaultOptions: []
});
function create$43(context) {
return { CallExpression(node) {
if (isCloneElementCall(context, node)) context.report({
messageId: "noCloneElement",
node
});
} };
}
//#endregion
//#region src/rules/no-component-will-mount.ts
const RULE_NAME$42 = "no-component-will-mount";
const RULE_FEATURES$42 = ["MOD"];
var no_component_will_mount_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replace usages of `componentWillMount` with `UNSAFE_componentWillMount`.",
[Symbol.for("rule_features")]: RULE_FEATURES$42
},
fixable: "code",
messages: { noComponentWillMount: "[Deprecated] Use 'UNSAFE_componentWillMount' instead." },
schema: []
},
name: RULE_NAME$42,
create: create$42,
defaultOptions: []
});
function create$42(context) {
if (!context.sourceCode.text.includes("componentWillMount")) return {};
const { ctx, listeners } = useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
for (const { node: component } of ctx.getAllComponents(program)) {
const { body } = component.body;
for (const member of body) if (isComponentWillMount(member)) context.report({
messageId: "noComponentWillMount",
node: member,
fix(fixer) {
if (!("key" in member)) return null;
return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
}
});
}
}
};
}
//#endregion
//#region src/rules/no-component-will-receive-props.ts
const RULE_NAME$41 = "no-component-will-receive-props";
const RULE_FEATURES$41 = ["MOD"];
var no_component_will_receive_props_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replace usages of `componentWillReceiveProps` with `UNSAFE_componentWillReceiveProps`.",
[Symbol.for("rule_features")]: RULE_FEATURES$41
},
fixable: "code",
messages: { noComponentWillReceiveProps: "[Deprecated] Use 'UNSAFE_componentWillReceiveProps' instead." },
schema: []
},
name: RULE_NAME$41,
create: create$41,
defaultOptions: []
});
function create$41(context) {
if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
const { ctx, listeners } = useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
for (const { node: component } of ctx.getAllComponents(program)) {
const { body } = component.body;
for (const member of body) if (isComponentWillReceiveProps(member)) context.report({
messageId: "noComponentWillReceiveProps",
node: member,
fix(fixer) {
if (!("key" in member)) return null;
return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
}
});
}
}
};
}
//#endregion
//#region src/rules/no-component-will-update.ts
const RULE_NAME$40 = "no-component-will-update";
const RULE_FEATURES$40 = ["MOD"];
var no_component_will_update_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replace usages of `componentWillUpdate` with `UNSAFE_componentWillUpdate`.",
[Symbol.for("rule_features")]: RULE_FEATURES$40
},
fixable: "code",
messages: { noComponentWillUpdate: "[Deprecated] Use 'UNSAFE_componentWillUpdate' instead." },
schema: []
},
name: RULE_NAME$40,
create: create$40,
defaultOptions: []
});
function create$40(context) {
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
const { ctx, listeners } = useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
for (const { node: component } of ctx.getAllComponents(program)) {
const { body } = component.body;
for (const member of body) if (isComponentWillUpdate(member)) context.report({
messageId: "noComponentWillUpdate",
node: member,
fix(fixer) {
if (!("key" in member)) return null;
return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
}
});
}
}
};
}
//#endregion
//#region src/rules/no-context-provider.ts
const RULE_NAME$39 = "no-context-provider";
const RULE_FEATURES$39 = ["MOD"];
var no_context_provider_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replace usages of `<Context.Provider>` with `<Context>`.",
[Symbol.for("rule_features")]: RULE_FEATURES$39
},
fixable: "code",
messages: { noContextProvider: "In React 19, you can render '<Context>' as a provider instead of '<Context.Provider>'." },
schema: []
},
name: RULE_NAME$39,
create: create$39,
defaultOptions: []
});
function create$39(context) {
if (!context.sourceCode.text.includes("Provider")) return {};
const { version: version$1 } = getSettingsFromContext(context);
if (compare(version$1, "19.0.0", "<")) return {};
return { JSXElement(node) {
const parts = getJsxElementType(context, node).split(".");
const selfName = parts.pop();
const contextFullName = parts.join(".");
const contextSelfName = parts.pop();
if (selfName !== "Provider") return;
if (contextSelfName == null || !contextSelfName.endsWith("Context")) return;
context.report({
messageId: "noContextProvider",
node,
fix(fixer) {
if (!isComponentNameLoose(contextSelfName)) return null;
const openingElement = node.openingElement;
const closingElement = node.closingElement;
if (closingElement == null) return fixer.replaceText(openingElement.name, contextFullName);
return [fixer.replaceText(openingElement.name, contextFullName), fixer.replaceText(closingElement.name, contextFullName)];
}
});
} };
}
//#endregion
//#region src/rules/no-create-ref.ts
const RULE_NAME$38 = "no-create-ref";
const RULE_FEATURES$38 = [];
var no_create_ref_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `createRef` in function components.",
[Symbol.for("rule_features")]: RULE_FEATURES$38
},
messages: { noCreateRef: "[Deprecated] Use 'useRef' instead." },
schema: []
},
name: RULE_NAME$38,
create: create$38,
defaultOptions: []
});
function create$38(context) {
return { CallExpression(node) {
if (isCreateRefCall(context, node) && AST.findParentNode(node, isClassComponent) == null) context.report({
messageId: "noCreateRef",
node
});
} };
}
//#endregion
//#region src/rules/no-default-props.ts
const RULE_NAME$37 = "no-default-props";
const RULE_FEATURES$37 = [];
var no_default_props_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `defaultProps` property in favor of ES6 default parameters.",
[Symbol.for("rule_features")]: RULE_FEATURES$37
},
messages: { noDefaultProps: "[Deprecated] Use ES6 default parameters instead." },
schema: []
},
name: RULE_NAME$37,
create: create$37,
defaultOptions: []
});
function create$37(context) {
if (!context.sourceCode.text.includes("defaultProps")) return {};
return { AssignmentExpression(node) {
if (node.operator !== "=" || node.left.type !== AST_NODE_TYPES.MemberExpression) return;
const { object, property } = node.left;
if (object.type !== AST_NODE_TYPES.Identifier) return;
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== "defaultProps") return;
if (!isComponentNameLoose(object.name)) return;
const variableNode = getVariableDefinitionNode(findVariable(object.name, context.sourceCode.getScope(node)), 0);
if (variableNode == null) return;
if (!AST.isFunction(variableNode)) return;
context.report({
messageId: "noDefaultProps",
node: property
});
} };
}
//#endregion
//#region src/rules/no-direct-mutation-state.ts
const RULE_NAME$36 = "no-direct-mutation-state";
const RULE_FEATURES$36 = [];
function isConstructorFunction(node) {
return AST.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && AST.isMethodOrProperty(node.parent) && node.parent.key.type === AST_NODE_TYPES.Identifier && node.parent.key.name === "constructor";
}
var no_direct_mutation_state_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow direct mutation of `this.state`.",
[Symbol.for("rule_features")]: RULE_FEATURES$36
},
messages: { noDirectMutationState: "Do not mutate state directly. Use 'setState()' instead." },
schema: []
},
name: RULE_NAME$36,
create: create$36,
defaultOptions: []
});
function create$36(context) {
return { AssignmentExpression(node) {
if (!isAssignmentToThisState(node)) return;
const parentClass = AST.findParentNode(node, AST.isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression]));
if (parentClass == null) return;
if (isClassComponent(parentClass) && context.sourceCode.getScope(node).block !== AST.findParentNode(node, isConstructorFunction)) context.report({
messageId: "noDirectMutationState",
node
});
} };
}
//#endregion
//#region src/rules/no-duplicate-key.ts
const RULE_NAME$35 = "no-duplicate-key";
const RULE_FEATURES$35 = [];
var no_duplicate_key_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow duplicate `key` on elements in the same array or a list of `children`.",
[Symbol.for("rule_features")]: RULE_FEATURES$35
},
messages: { noDuplicateKey: "A key must be unique. '{{value}}' is duplicated." },
schema: []
},
name: RULE_NAME$35,
create: create$35,
defaultOptions: []
});
function create$35(context) {
if (!context.sourceCode.text.includes("key=")) return {};
const keyedEntries = /* @__PURE__ */ new Map();
function isKeyValueEqual(a, b) {
const aValue = a.value;
const bValue = b.value;
if (aValue == null || bValue == null) return false;
return AST.isNodeEqual(aValue, bValue);
}
return {
"JSXAttribute[name.name='key']"(node) {
const jsxElement = node.parent.parent;
switch (jsxElement.parent.type) {
case AST_NODE_TYPES.ArrayExpression:
case AST_NODE_TYPES.JSXElement:
case AST_NODE_TYPES.JSXFragment: {
const root = jsxElement.parent;
const prevKeys = keyedEntries.get(root)?.keys ?? [];
keyedEntries.set(root, {
hasDuplicate: prevKeys.some((prevKey) => isKeyValueEqual(prevKey, node)),
keys: [...prevKeys, node],
root: jsxElement.parent
});
break;
}
default: {
const call = AST.findParentNode(jsxElement, AST.isArrayMapCall);
const iter = AST.findParentNode(jsxElement, (n) => n === call || AST.isFunction(n));
if (!AST.isFunction(iter)) return;
const arg0 = call?.arguments[0];
if (call == null || arg0 == null) return;
if (AST.getUnderlyingExpression(arg0) !== iter) return;
keyedEntries.set(call, {
hasDuplicate: node.value?.type === AST_NODE_TYPES.Literal,
keys: [node],
root: call
});
}
}
},
"Program:exit"() {
for (const { hasDuplicate, keys } of keyedEntries.values()) {
if (!hasDuplicate) continue;
for (const key of keys) context.report({
messageId: "noDuplicateKey",
node: key,
data: { value: context.sourceCode.getText(key) }
});
}
}
};
}
//#endregion
//#region src/rules/no-forward-ref.ts
const RULE_NAME$34 = "no-forward-ref";
const RULE_FEATURES$34 = ["MOD"];
var no_forward_ref_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replaces usages of `forwardRef` with passing `ref` as a prop.",
[Symbol.for("rule_features")]: RULE_FEATURES$34
},
fixable: "code",
messages: { noForwardRef: "In React 19, 'forwardRef' is no longer necessary. Pass 'ref' as a prop instead." },
schema: []
},
name: RULE_NAME$34,
create: create$34,
defaultOptions: []
});
function create$34(context) {
if (!context.sourceCode.text.includes("forwardRef")) return {};
const { version: version$1 } = getSettingsFromContext(context);
if (compare(version$1, "19.0.0", "<")) return {};
return { CallExpression(node) {
if (!isForwardRefCall(context, node)) return;
const id = AST.getFunctionId(node);
const fix = canFix(context, node) ? getFix(context, node) : null;
context.report({
messageId: "noForwardRef",
node: id ?? node,
fix
});
} };
}
/**
* Determines whether the given CallExpression can be safely auto-fixed by replacing
* the usage of `forwardRef` with passing `ref` as a prop
*
* @param context The rule context object
* @param node The CallExpression node to check
* @returns True if the call can be auto-fixed, false otherwise
*/
function canFix(context, node) {
const { importSource } = getSettingsFromContext(context);
const initialScope = context.sourceCode.getScope(node);
switch (node.callee.type) {
case AST_NODE_TYPES.Identifier: return isInitializedFromReact(node.callee.name, importSource, initialScope);
case AST_NODE_TYPES.MemberExpression: return node.callee.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.callee.object.name, importSource, initialScope);
default: return false;
}
}
/**
* Generates the fix for the `forwardRef` call
* @param context The rule context
* @param node The `forwardRef` call expression
* @returns A fixer function that applies the changes
*/
function getFix(context, node) {
return (fixer) => {
const [componentNode] = node.arguments;
if (componentNode == null || !AST.isFunction(componentNode)) return [];
return [
fixer.removeRange([node.range[0], componentNode.range[0]]),
fixer.removeRange([componentNode.range[1], node.range[1]]),
...getComponentPropsFixes(context, fixer, componentNode, node.typeArguments?.params ?? [])
];
};
}
/**
* Generates fixes for the component's props and ref arguments
* @param context The rule context
* @param fixer The rule fixer
* @param node The function component node
* @param typeArguments The type arguments from the `forwardRef` call
* @returns An array of fixes for the component's signature
*/
function getComponentPropsFixes(context, fixer, node, typeArguments) {
const getText = (node$1) => context.sourceCode.getText(node$1);
const [arg0, arg1] = node.params;
const [typeArg0, typeArg1] = typeArguments;
if (arg0 == null) return [];
const fixedArg0Text = match(arg0).with({ type: AST_NODE_TYPES.Identifier }, (n) => `...${n.name}`).with({ type: AST_NODE_TYPES.ObjectPattern }, (n) => n.properties.map(getText).join(", ")).otherwise(() => null);
const fixedArg1Text = match(arg1).with(P.nullish, () => "ref").with({
type: AST_NODE_TYPES.Identifier,
name: "ref"
}, () => "ref").with({
type: AST_NODE_TYPES.Identifier,
name: P.string
}, (n) => `ref: ${n.name}`).otherwise(() => null);
if (fixedArg0Text == null || fixedArg1Text == null) return [];
if (typeArg0 == null || typeArg1 == null) return [fixer.replaceText(arg0, [
"{",
fixedArg1Text + ",",
fixedArg0Text,
"}"
].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
const typeArg0Text = getText(typeArg0);
const typeArg1Text = getText(typeArg1);
return [fixer.replaceText(arg0, [
"{",
fixedArg1Text + ",",
fixedArg0Text,
"}:",
typeArg1Text,
"&",
"{",
`ref?:`,
`React.RefObject<${typeArg0Text} | null>`,
"}"
].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
}
//#endregion
//#region src/rules/no-implicit-key.ts
const RULE_NAME$33 = "no-implicit-key";
const RULE_FEATURES$33 = ["EXP"];
var no_implicit_key_default = createRule({
meta: {
type: "problem",
docs: {
description: "Prevents `key` from not being explicitly specified (e.g. spreading `key` from objects).",
[Symbol.for("rule_features")]: RULE_FEATURES$33
},
messages: { noImplicitKey: "Do not use implicit 'key' props." },
schema: []
},
name: RULE_NAME$33,
create: create$33,
defaultOptions: []
});
function create$33(context) {
return { JSXOpeningElement(node) {
const keyProp = getJsxAttribute(context, node.parent)("key");
const isKeyPropOnElement = node.attributes.some((n) => n.type === AST_NODE_TYPES.JSXAttribute && n.name.type === AST_NODE_TYPES.JSXIdentifier && n.name.name === "key");
if (keyProp != null && !isKeyPropOnElement) context.report({
messageId: "noImplicitKey",
node: keyProp
});
} };
}
//#endregion
//#region src/rules/no-leaked-conditional-rendering.ts
const RULE_NAME$32 = "no-leaked-conditional-rendering";
const RULE_FEATURES$32 = ["TSC"];
var no_leaked_conditional_rendering_default = createRule({
meta: {
type: "problem",
docs: {
description: "Prevents problematic leaked values from being rendered.",
[Symbol.for("rule_features")]: RULE_FEATURES$32
},
messages: { noLeakedConditionalRendering: "Potential leaked value {{value}} that might cause unintentionally rendered values or ren