eslint-plugin-react-x
Version:
A set of composable ESLint rules for for libraries and frameworks that use React as a UI runtime.
1,595 lines (1,584 loc) • 126 kB
JavaScript
'use strict';
var shared = require('@eslint-react/shared');
var ER25 = require('@eslint-react/core');
var utils = require('@typescript-eslint/utils');
var kit = require('@eslint-react/kit');
var types = require('@typescript-eslint/types');
var VAR2 = require('@eslint-react/var');
var tsPattern = require('ts-pattern');
var ts = require('typescript');
var AST8 = require('@eslint-react/ast');
var eff = require('@eslint-react/eff');
var compareVersions = require('compare-versions');
var typeUtils = require('@typescript-eslint/type-utils');
var tsApiUtils = require('ts-api-utils');
var isImmutableType = require('is-immutable-type');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var ER25__namespace = /*#__PURE__*/_interopNamespace(ER25);
var VAR2__namespace = /*#__PURE__*/_interopNamespace(VAR2);
var ts__default = /*#__PURE__*/_interopDefault(ts);
var AST8__namespace = /*#__PURE__*/_interopNamespace(AST8);
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name5 in all)
__defProp(target, name5, { get: all[name5], enumerable: true });
};
// src/configs/recommended.ts
var recommended_exports = {};
__export(recommended_exports, {
name: () => name,
rules: () => rules,
settings: () => settings
});
var name = "react-x/recommended";
var rules = {
"react-x/jsx-no-duplicate-props": "warn",
"react-x/jsx-uses-react": "warn",
"react-x/jsx-uses-vars": "warn",
"react-x/no-access-state-in-setstate": "error",
"react-x/no-array-index-key": "warn",
"react-x/no-children-count": "warn",
"react-x/no-children-for-each": "warn",
"react-x/no-children-map": "warn",
"react-x/no-children-only": "warn",
"react-x/no-children-to-array": "warn",
"react-x/no-clone-element": "warn",
"react-x/no-comment-textnodes": "warn",
"react-x/no-component-will-mount": "error",
"react-x/no-component-will-receive-props": "error",
"react-x/no-component-will-update": "error",
"react-x/no-context-provider": "warn",
"react-x/no-create-ref": "error",
"react-x/no-default-props": "error",
"react-x/no-direct-mutation-state": "error",
"react-x/no-duplicate-key": "warn",
"react-x/no-forward-ref": "warn",
"react-x/no-implicit-key": "warn",
"react-x/no-missing-key": "error",
"react-x/no-misused-capture-owner-stack": "error",
"react-x/no-nested-component-definitions": "error",
"react-x/no-nested-lazy-component-declarations": "warn",
"react-x/no-prop-types": "error",
"react-x/no-redundant-should-component-update": "error",
"react-x/no-set-state-in-component-did-mount": "warn",
"react-x/no-set-state-in-component-did-update": "warn",
"react-x/no-set-state-in-component-will-update": "warn",
"react-x/no-string-refs": "error",
"react-x/no-unsafe-component-will-mount": "warn",
"react-x/no-unsafe-component-will-receive-props": "warn",
"react-x/no-unsafe-component-will-update": "warn",
"react-x/no-unstable-context-value": "warn",
"react-x/no-unstable-default-props": "warn",
"react-x/no-unused-class-component-members": "warn",
"react-x/no-unused-state": "warn",
"react-x/no-use-context": "warn",
"react-x/no-useless-forward-ref": "warn"
};
var settings = {
"react-x": shared.DEFAULT_ESLINT_REACT_SETTINGS
};
// src/configs/recommended-type-checked.ts
var recommended_type_checked_exports = {};
__export(recommended_type_checked_exports, {
name: () => name3,
rules: () => rules3,
settings: () => settings3
});
// src/configs/recommended-typescript.ts
var recommended_typescript_exports = {};
__export(recommended_typescript_exports, {
name: () => name2,
rules: () => rules2,
settings: () => settings2
});
var name2 = "react-x/recommended-typescript";
var rules2 = {
...rules,
"react-x/jsx-no-duplicate-props": "off",
"react-x/jsx-no-undef": "off",
"react-x/jsx-uses-react": "off",
"react-x/jsx-uses-vars": "off"
};
var settings2 = {
...settings
};
// src/configs/recommended-type-checked.ts
var name3 = "react-x/recommended-type-checked";
var rules3 = {
...rules2,
"react-x/no-leaked-conditional-rendering": "warn"
// "react-x/prefer-read-only-props": "warn",
};
var settings3 = {
...settings2
};
// package.json
var name4 = "eslint-plugin-react-x";
var version = "1.48.4";
var createRule = utils.ESLintUtils.RuleCreator(shared.getDocsUrl("x"));
// src/rules/avoid-shorthand-boolean.ts
var RULE_NAME = "avoid-shorthand-boolean";
var RULE_FEATURES = [];
var avoid_shorthand_boolean_default = createRule({
meta: {
type: "problem",
docs: {
description: "Enforces explicit boolean values for boolean attributes.",
[Symbol.for("rule_features")]: RULE_FEATURES
},
fixable: "code",
messages: {
avoidShorthandBoolean: "Avoid using shorthand boolean attribute '{{propName}}'. Use '{{propName}}={true}' instead."
},
schema: []
},
name: RULE_NAME,
create,
defaultOptions: []
});
function create(context) {
return {
JSXAttribute(node) {
if (node.value == null) {
context.report({
messageId: "avoidShorthandBoolean",
node,
data: {
propName: ER25__namespace.getAttributeName(context, node)
},
fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`)
});
}
}
};
}
var RULE_NAME2 = "avoid-shorthand-fragment";
var RULE_FEATURES2 = [];
var avoid_shorthand_fragment_default = createRule({
meta: {
type: "problem",
docs: {
description: "Enforces explicit `<Fragment>` components instead of the shorthand `<>` or `</>` syntax.",
[Symbol.for("rule_features")]: RULE_FEATURES2
},
messages: {
avoidShorthandFragment: "Avoid using shorthand fragment syntax. Use '{{jsxFragmentFactory}}' component instead."
},
schema: []
},
name: RULE_NAME2,
create: create2,
defaultOptions: []
});
function create2(context) {
const jsxConfigFromContext = kit.JsxConfig.getFromContext(context);
const jsxConfigFromAnnotation = kit.JsxConfig.getFromAnnotation(context);
const jsxConfig = {
...jsxConfigFromContext,
...jsxConfigFromAnnotation
};
return {
JSXFragment(node) {
context.report({
messageId: "avoidShorthandFragment",
node,
data: {
jsxFragmentFactory: jsxConfig.jsxFragmentFactory
}
});
}
};
}
var RULE_NAME3 = "jsx-no-duplicate-props";
var RULE_FEATURES3 = [];
var jsx_no_duplicate_props_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow duplicate props in JSX elements.",
[Symbol.for("rule_features")]: RULE_FEATURES3
},
messages: {
jsxNoDuplicateProps: "This JSX property is assigned multiple times."
},
schema: []
},
name: RULE_NAME3,
create: create3,
defaultOptions: []
});
function create3(context) {
return {
JSXOpeningElement(node) {
const props = [];
for (const attr of node.attributes) {
if (attr.type === types.AST_NODE_TYPES.JSXSpreadAttribute) {
continue;
}
const name5 = attr.name.name;
if (typeof name5 !== "string") {
continue;
}
if (!props.includes(name5)) {
props.push(name5);
continue;
}
context.report({
messageId: "jsxNoDuplicateProps",
node: attr
});
}
}
};
}
var RULE_NAME4 = "jsx-no-undef";
var RULE_FEATURES4 = [];
var jsx_no_undef_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow undefined variables in JSX.",
[Symbol.for("rule_features")]: RULE_FEATURES4
},
messages: {
jsxNoUndef: "JSX variable '{{name}}' is not defined."
},
schema: []
},
name: RULE_NAME4,
create: create4,
defaultOptions: []
});
function create4(context) {
return {
JSXOpeningElement(node) {
const name5 = tsPattern.match(node.name).with({ type: types.AST_NODE_TYPES.JSXIdentifier }, (n) => n.name).with({ type: types.AST_NODE_TYPES.JSXMemberExpression, object: { type: types.AST_NODE_TYPES.JSXIdentifier } }, (n) => n.object.name).otherwise(() => null);
if (name5 == null) return;
if (name5 === "this") return;
if (/^[a-z]/u.test(name5)) return;
if (VAR2__namespace.findVariable(name5, context.sourceCode.getScope(node)) == null) {
context.report({
messageId: "jsxNoUndef",
node,
data: {
name: name5
}
});
}
}
};
}
var RULE_NAME5 = "jsx-uses-react";
var RULE_FEATURES5 = [];
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_FEATURES5
},
messages: {
jsxUsesReact: "Marked {{name}} as used."
},
schema: []
},
name: RULE_NAME5,
create: create5,
defaultOptions: []
});
function create5(context) {
const jsxConfig = {
...kit.JsxConfig.getFromContext(context),
...kit.JsxConfig.getFromAnnotation(context)
};
const { jsx, jsxFactory, jsxFragmentFactory } = jsxConfig;
if (jsx === ts.JsxEmit.ReactJSX || jsx === ts.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, name5) {
if (process.env["ESLINT_REACT_DEBUG"] !== "1") return;
context.report({
messageId: "jsxUsesReact",
node,
data: { name: name5 }
});
}
var RULE_NAME6 = "jsx-uses-vars";
var RULE_FEATURES6 = [];
var jsx_uses_vars_default = createRule({
meta: {
type: "problem",
docs: {
description: "Marks variables used in JSX elements as used.",
[Symbol.for("rule_features")]: RULE_FEATURES6
},
messages: {
jsxUsesVars: ""
},
schema: []
},
name: RULE_NAME6,
create: create6,
defaultOptions: []
});
function create6(context) {
return {
JSXOpeningElement(node) {
switch (node.name.type) {
case types.AST_NODE_TYPES.JSXIdentifier: {
if (/^[a-z]/u.test(node.name.name)) {
return;
}
context.sourceCode.markVariableAsUsed(node.name.name, node);
break;
}
case types.AST_NODE_TYPES.JSXMemberExpression: {
const { object } = node.name;
if (object.type === types.AST_NODE_TYPES.JSXIdentifier) {
context.sourceCode.markVariableAsUsed(object.name, node);
}
break;
}
}
}
};
}
var RULE_NAME7 = "no-access-state-in-setstate";
var RULE_FEATURES7 = [];
function isKeyLiteral(node, key) {
return tsPattern.match(key).with({ type: types.AST_NODE_TYPES.Literal }, eff.constTrue).with({ type: types.AST_NODE_TYPES.TemplateLiteral, expressions: [] }, eff.constTrue).with({ type: types.AST_NODE_TYPES.Identifier }, () => !node.computed).otherwise(eff.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_FEATURES7
},
messages: {
noAccessStateInSetstate: "Do not access 'this.state' within 'setState'. Use the update function instead."
},
schema: []
},
name: RULE_NAME7,
create: create7,
defaultOptions: []
});
function create7(context) {
if (!context.sourceCode.text.includes("setState")) {
return {};
}
const classEntries = [];
const methodEntries = [];
const setStateEntries = [];
return {
CallExpression(node) {
if (!ER25__namespace.isThisSetState(node)) {
return;
}
setStateEntries.push([node, false]);
},
"CallExpression:exit"(node) {
if (!ER25__namespace.isThisSetState(node)) {
return;
}
setStateEntries.pop();
},
ClassDeclaration(node) {
classEntries.push([node, ER25__namespace.isClassComponent(node)]);
},
"ClassDeclaration:exit"() {
classEntries.pop();
},
ClassExpression(node) {
classEntries.push([node, ER25__namespace.isClassComponent(node)]);
},
"ClassExpression:exit"() {
classEntries.pop();
},
MemberExpression(node) {
if (!AST8__namespace.isThisExpression(node.object)) {
return;
}
const [currClass, isComponent = false] = classEntries.at(-1) ?? [];
if (currClass == null || !isComponent) {
return;
}
const [currMethod, isStatic = false] = methodEntries.at(-1) ?? [];
if (currMethod == null || isStatic) {
return;
}
const [setState, hasThisState = false] = setStateEntries.at(-1) ?? [];
if (setState == null || hasThisState) {
return;
}
if (AST8__namespace.getPropertyName(node.property) !== "state") {
return;
}
context.report({ messageId: "noAccessStateInSetstate", node });
},
MethodDefinition(node) {
methodEntries.push([node, node.static]);
},
"MethodDefinition:exit"() {
methodEntries.pop();
},
PropertyDefinition(node) {
methodEntries.push([node, node.static]);
},
"PropertyDefinition:exit"() {
methodEntries.pop();
},
VariableDeclarator(node) {
const [currClass, isComponent = false] = classEntries.at(-1) ?? [];
if (currClass == null || !isComponent) {
return;
}
const [currMethod, isStatic = false] = methodEntries.at(-1) ?? [];
if (currMethod == null || isStatic) {
return;
}
const [setState, hasThisState = false] = setStateEntries.at(-1) ?? [];
if (setState == null || hasThisState) {
return;
}
if (node.init == null || !AST8__namespace.isThisExpression(node.init) || node.id.type !== types.AST_NODE_TYPES.ObjectPattern) {
return;
}
const hasState = node.id.properties.some(
(prop) => prop.type === types.AST_NODE_TYPES.Property && isKeyLiteral(prop, prop.key) && AST8__namespace.getPropertyName(prop.key) === "state"
);
if (!hasState) {
return;
}
context.report({ messageId: "noAccessStateInSetstate", node });
}
};
}
var RULE_NAME8 = "no-array-index-key";
var RULE_FEATURES8 = [];
var reactChildrenMethod = ["forEach", "map"];
function isReactChildrenMethod(name5) {
return reactChildrenMethod.some((method) => method === name5);
}
function isUsingReactChildren(context, node) {
const { importSource = "react" } = shared.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 === types.AST_NODE_TYPES.Identifier && callee.object.name === "Children") {
return true;
}
if (callee.object.type === types.AST_NODE_TYPES.MemberExpression && "name" in callee.object.object) {
return ER25__namespace.isInitializedFromReact(callee.object.object.name, importSource, initialScope);
}
return false;
}
function getMapIndexParamName(context, node) {
const { callee } = node;
if (callee.type !== types.AST_NODE_TYPES.MemberExpression) {
return eff._;
}
if (callee.property.type !== types.AST_NODE_TYPES.Identifier) {
return eff._;
}
const { name: name5 } = callee.property;
const indexPosition = AST8__namespace.getArrayMethodCallbackIndexParamPosition(name5);
if (indexPosition === -1) {
return eff._;
}
const callbackArg = node.arguments[isUsingReactChildren(context, node) ? 1 : 0];
if (callbackArg == null) {
return eff._;
}
if (!AST8__namespace.isOneOf([types.AST_NODE_TYPES.ArrowFunctionExpression, types.AST_NODE_TYPES.FunctionExpression])(callbackArg)) {
return eff._;
}
const { params } = callbackArg;
if (params.length < indexPosition + 1) {
return eff._;
}
const param = params.at(indexPosition);
return param != null && "name" in param ? param.name : eff._;
}
function getIdentifiersFromBinaryExpression(side) {
if (side.type === types.AST_NODE_TYPES.Identifier) {
return [side];
}
if (side.type === types.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_FEATURES8
},
messages: {
noArrayIndexKey: "Do not use item index in the array as its key."
},
schema: []
},
name: RULE_NAME8,
create: create8,
defaultOptions: []
});
function create8(context) {
const report = kit.Reporter.make(context);
const indexParamNames = [];
function isArrayIndex(node) {
return node.type === types.AST_NODE_TYPES.Identifier && indexParamNames.some((name5) => name5 != null && name5 === node.name);
}
function isCreateOrCloneElementCall(node) {
return ER25__namespace.isCreateElementCall(context, node) || ER25__namespace.isCloneElementCall(context, node);
}
function getReportDescriptors(node) {
switch (node.type) {
// key={bar}
case types.AST_NODE_TYPES.Identifier: {
if (indexParamNames.some((name5) => name5 != null && name5 === node.name)) {
return [{
messageId: "noArrayIndexKey",
node
}];
}
return [];
}
// key={`foo-${bar}`} or key={'foo' + bar}
case types.AST_NODE_TYPES.TemplateLiteral:
case types.AST_NODE_TYPES.BinaryExpression: {
const descriptors = [];
const expressions = node.type === types.AST_NODE_TYPES.TemplateLiteral ? node.expressions : getIdentifiersFromBinaryExpression(node);
for (const expression of expressions) {
if (isArrayIndex(expression)) {
descriptors.push({
messageId: "noArrayIndexKey",
node: expression
});
}
}
return descriptors;
}
// key={bar.toString()} or key={String(bar)}
case types.AST_NODE_TYPES.CallExpression: {
switch (true) {
// key={bar.toString()}
case (node.callee.type === types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === "toString" && isArrayIndex(node.callee.object)): {
return [{
messageId: "noArrayIndexKey",
node: node.callee.object
}];
}
// key={String(bar)}
case (node.callee.type === types.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 !== types.AST_NODE_TYPES.ObjectExpression) {
return;
}
for (const prop of props.properties) {
if (!tsPattern.isMatching({ key: { name: "key" } })(prop)) {
continue;
}
if (!("value" in prop)) {
continue;
}
for (const descriptor of getReportDescriptors(prop.value)) {
report.send(descriptor);
}
}
},
"CallExpression:exit"() {
indexParamNames.pop();
},
JSXAttribute(node) {
if (node.name.name !== "key") {
return;
}
if (indexParamNames.length === 0) {
return;
}
if (node.value?.type !== types.AST_NODE_TYPES.JSXExpressionContainer) {
return;
}
for (const descriptor of getReportDescriptors(node.value.expression)) {
report.send(descriptor);
}
}
};
}
var RULE_NAME9 = "no-children-count";
var RULE_FEATURES9 = [];
var no_children_count_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.count`.",
[Symbol.for("rule_features")]: RULE_FEATURES9
},
messages: {
noChildrenCount: "Using 'Children.count' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME9,
create: create9,
defaultOptions: []
});
function create9(context) {
return {
MemberExpression(node) {
if (ER25__namespace.isChildrenCount(context, node)) {
context.report({
messageId: "noChildrenCount",
node: node.property
});
}
}
};
}
var RULE_NAME10 = "no-children-for-each";
var RULE_FEATURES10 = [];
var no_children_for_each_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow 'Children.forEach'.",
[Symbol.for("rule_features")]: RULE_FEATURES10
},
messages: {
noChildrenForEach: "Using 'Children.forEach' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME10,
create: create10,
defaultOptions: []
});
function create10(context) {
return {
MemberExpression(node) {
if (ER25__namespace.isChildrenForEach(context, node)) {
context.report({
messageId: "noChildrenForEach",
node: node.property
});
}
}
};
}
var RULE_NAME11 = "no-children-map";
var RULE_FEATURES11 = [];
var no_children_map_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.map`.",
[Symbol.for("rule_features")]: RULE_FEATURES11
},
messages: {
noChildrenMap: "Using 'Children.map' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME11,
create: create11,
defaultOptions: []
});
function create11(context) {
return {
MemberExpression(node) {
if (ER25__namespace.isChildrenMap(context, node)) {
context.report({
messageId: "noChildrenMap",
node: node.property
});
}
}
};
}
var RULE_NAME12 = "no-children-only";
var RULE_FEATURES12 = [];
var no_children_only_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.only`.",
[Symbol.for("rule_features")]: RULE_FEATURES12
},
messages: {
noChildrenOnly: "Using 'Children.only' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME12,
create: create12,
defaultOptions: []
});
function create12(context) {
return {
MemberExpression(node) {
if (ER25__namespace.isChildrenOnly(context, node)) {
context.report({
messageId: "noChildrenOnly",
node: node.property
});
}
}
};
}
var RULE_NAME13 = "no-children-prop";
var RULE_FEATURES13 = [];
var no_children_prop_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow passing `children` as a prop.",
[Symbol.for("rule_features")]: RULE_FEATURES13
},
messages: {
noChildrenProp: "Do not pass 'children' as props."
},
schema: []
},
name: RULE_NAME13,
create: create13,
defaultOptions: []
});
function create13(context) {
return {
JSXElement(node) {
const attributes = node.openingElement.attributes;
const childrenProp = ER25__namespace.getAttribute(context, "children", attributes, context.sourceCode.getScope(node));
if (childrenProp != null) {
context.report({
messageId: "noChildrenProp",
node: childrenProp
});
}
}
};
}
var RULE_NAME14 = "no-children-to-array";
var RULE_FEATURES14 = [];
var no_children_to_array_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `Children.toArray`.",
[Symbol.for("rule_features")]: RULE_FEATURES14
},
messages: {
noChildrenToArray: "Using 'Children.toArray' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME14,
create: create14,
defaultOptions: []
});
function create14(context) {
return {
MemberExpression(node) {
if (ER25__namespace.isChildrenToArray(context, node)) {
context.report({
messageId: "noChildrenToArray",
node: node.property
});
}
}
};
}
var RULE_NAME15 = "no-class-component";
var RULE_FEATURES15 = [];
var no_class_component_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow class components except for error boundaries.",
[Symbol.for("rule_features")]: RULE_FEATURES15
},
messages: {
noClassComponent: "Avoid using class components. Use function components instead."
},
schema: []
},
name: RULE_NAME15,
create: create15,
defaultOptions: []
});
function create15(context) {
if (!context.sourceCode.text.includes("Component")) return {};
const { ctx, listeners } = ER25__namespace.useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
const components = ctx.getAllComponents(program);
for (const { name: name5 = "anonymous", node: component } of components.values()) {
if (component.body.body.some((m) => ER25__namespace.isComponentDidCatch(m) || ER25__namespace.isGetDerivedStateFromError(m))) {
continue;
}
context.report({
messageId: "noClassComponent",
node: component,
data: {
name: name5
}
});
}
}
};
}
var RULE_NAME16 = "no-clone-element";
var RULE_FEATURES16 = [];
var no_clone_element_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `cloneElement`.",
[Symbol.for("rule_features")]: RULE_FEATURES16
},
messages: {
noCloneElement: "Using 'cloneElement' is uncommon and can lead to fragile code. Use alternatives instead."
},
schema: []
},
name: RULE_NAME16,
create: create16,
defaultOptions: []
});
function create16(context) {
return {
CallExpression(node) {
if (ER25__namespace.isCloneElementCall(context, node)) {
context.report({
messageId: "noCloneElement",
node
});
}
}
};
}
var RULE_NAME17 = "no-comment-textnodes";
var RULE_FEATURES17 = [];
var no_comment_textnodes_default = createRule({
meta: {
type: "problem",
docs: {
description: "Prevents comments from being inserted as text nodes.",
[Symbol.for("rule_features")]: RULE_FEATURES17
},
messages: {
noCommentTextnodes: "Possible misused comment in text node. Comments inside children section of tag should be placed inside braces."
},
schema: []
},
name: RULE_NAME17,
create: create17,
defaultOptions: []
});
function create17(context) {
function hasCommentLike(node) {
if (AST8__namespace.isOneOf([types.AST_NODE_TYPES.JSXAttribute, types.AST_NODE_TYPES.JSXExpressionContainer])(node.parent)) {
return false;
}
const rawValue = context.sourceCode.getText(node);
return /^\s*\/(?:\/|\*)/mu.test(rawValue);
}
const visitorFunction = (node) => {
if (!AST8__namespace.isOneOf([types.AST_NODE_TYPES.JSXElement, types.AST_NODE_TYPES.JSXFragment])(node.parent)) {
return;
}
if (!hasCommentLike(node)) {
return;
}
if (!node.parent.type.includes("JSX")) {
return;
}
context.report({
messageId: "noCommentTextnodes",
node
});
};
return {
JSXText: visitorFunction,
Literal: visitorFunction
};
}
var RULE_NAME18 = "no-complex-conditional-rendering";
var RULE_FEATURES18 = [
"EXP"
];
var no_complex_conditional_rendering_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow complex conditional rendering in JSX expressions.",
[Symbol.for("rule_features")]: RULE_FEATURES18
},
messages: {
noComplexConditionalRendering: "Avoid complex conditional rendering. Extract the logic into separate elements or components."
},
schema: []
},
name: RULE_NAME18,
create: create18,
defaultOptions: []
});
function create18(context) {
const visitorFunction = (node) => {
const jsxExpContainer = node.parent?.parent;
if (!AST8__namespace.is(types.AST_NODE_TYPES.JSXExpressionContainer)(jsxExpContainer)) {
return;
}
if (!AST8__namespace.isOneOf([types.AST_NODE_TYPES.JSXElement, types.AST_NODE_TYPES.JSXFragment])(jsxExpContainer.parent)) {
return;
}
if (!jsxExpContainer.parent.children.includes(jsxExpContainer)) {
return;
}
context.report({
messageId: "noComplexConditionalRendering",
node: jsxExpContainer
});
};
return {
"JSXExpressionContainer > ConditionalExpression > ConditionalExpression": visitorFunction,
"JSXExpressionContainer > ConditionalExpression > LogicalExpression": visitorFunction,
"JSXExpressionContainer > LogicalExpression > ConditionalExpression": visitorFunction,
"JSXExpressionContainer > LogicalExpression[operator='&&'] > LogicalExpression[operator='||']": visitorFunction,
"JSXExpressionContainer > LogicalExpression[operator='||'] > LogicalExpression[operator='&&']": visitorFunction
};
}
var RULE_NAME19 = "no-component-will-mount";
var RULE_FEATURES19 = [
"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_FEATURES19
},
fixable: "code",
messages: {
noComponentWillMount: "[Deprecated] Use 'UNSAFE_componentWillMount' instead."
},
schema: []
},
name: RULE_NAME19,
create: create19,
defaultOptions: []
});
function create19(context) {
if (!context.sourceCode.text.includes("componentWillMount")) return {};
const { ctx, listeners } = ER25__namespace.useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
const components = ctx.getAllComponents(program);
for (const { node: component } of components.values()) {
const { body } = component.body;
for (const member of body) {
if (ER25__namespace.isComponentWillMount(member)) {
context.report({
messageId: "noComponentWillMount",
node: member,
fix(fixer) {
if (!("key" in member)) {
return null;
}
return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
}
});
}
}
}
}
};
}
var RULE_NAME20 = "no-component-will-receive-props";
var RULE_FEATURES20 = [
"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_FEATURES20
},
fixable: "code",
messages: {
noComponentWillReceiveProps: "[Deprecated] Use 'UNSAFE_componentWillReceiveProps' instead."
},
schema: []
},
name: RULE_NAME20,
create: create20,
defaultOptions: []
});
function create20(context) {
if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
const { ctx, listeners } = ER25__namespace.useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
const components = ctx.getAllComponents(program);
for (const { node: component } of components.values()) {
const { body } = component.body;
for (const member of body) {
if (ER25__namespace.isComponentWillReceiveProps(member)) {
context.report({
messageId: "noComponentWillReceiveProps",
node: member,
fix(fixer) {
if (!("key" in member)) {
return null;
}
return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
}
});
}
}
}
}
};
}
var RULE_NAME21 = "no-component-will-update";
var RULE_FEATURES21 = [
"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_FEATURES21
},
fixable: "code",
messages: {
noComponentWillUpdate: "[Deprecated] Use 'UNSAFE_componentWillUpdate' instead."
},
schema: []
},
name: RULE_NAME21,
create: create21,
defaultOptions: []
});
function create21(context) {
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
const { ctx, listeners } = ER25__namespace.useComponentCollectorLegacy();
return {
...listeners,
"Program:exit"(program) {
const components = ctx.getAllComponents(program);
for (const { node: component } of components.values()) {
const { body } = component.body;
for (const member of body) {
if (ER25__namespace.isComponentWillUpdate(member)) {
context.report({
messageId: "noComponentWillUpdate",
node: member,
fix(fixer) {
if (!("key" in member)) {
return null;
}
return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
}
});
}
}
}
}
};
}
var RULE_NAME22 = "no-context-provider";
var RULE_FEATURES22 = [
"MOD"
];
var no_context_provider_default = createRule({
meta: {
type: "problem",
docs: {
description: "Replace usages of `<Context.Provider>` with `<Context>`.",
[Symbol.for("rule_features")]: RULE_FEATURES22
},
fixable: "code",
messages: {
noContextProvider: "In React 19, you can render '<Context>' as a provider instead of '<Context.Provider>'."
},
schema: []
},
name: RULE_NAME22,
create: create22,
defaultOptions: []
});
function create22(context) {
if (!context.sourceCode.text.includes("Provider")) return {};
const { version: version2 } = shared.getSettingsFromContext(context);
if (compareVersions.compare(version2, "19.0.0", "<")) return {};
return {
JSXElement(node) {
const fullName = ER25__namespace.getElementType(context, node);
const parts = fullName.split(".");
const selfName = parts.pop();
const contextFullName = parts.join(".");
const contextSelfName = parts.pop();
if (selfName !== "Provider") return;
if (contextSelfName == null) return;
context.report({
messageId: "noContextProvider",
node,
fix(fixer) {
if (!ER25__namespace.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)
];
}
});
}
};
}
var RULE_NAME23 = "no-create-ref";
var RULE_FEATURES23 = [];
var no_create_ref_default = createRule({
meta: {
type: "problem",
docs: {
description: "Disallow `createRef` in function components.",
[Symbol.for("rule_features")]: RULE_FEATURES23
},
messages: {
noCreateRef: "[Deprecated] Use 'useRef' instead."
},
schema: []
},
name: RULE_NAME23,
create: create23,
defaultOptions: []
});
function create23(context) {
return {
CallExpression(node) {
if (ER25__namespace.isCreateRefCall(context, node) && AST8__namespace.findParentNode(node, ER25__namespace.isClassComponent) == null) {
context.report({ messageId: "noCreateRef", node });
}
}
};
}
var RULE_NAME24 = "no-default-props";
var RULE_FEATURES24 = [];
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_FEATURES24
},
messages: {
noDefaultProps: "[Deprecated] Use ES6 default parameters instead."
},
schema: []
},
name: RULE_NAME24,
create: create24,
defaultOptions: []
});
function create24(context) {
if (!context.sourceCode.text.includes("defaultProps")) return {};
return {
AssignmentExpression(node) {
if (node.operator !== "=" || node.left.type !== types.AST_NODE_TYPES.MemberExpression) {
return;
}
const { object, property } = node.left;
if (object.type !== types.AST_NODE_TYPES.Identifier) {
return;
}
if (property.type !== types.AST_NODE_TYPES.Identifier || property.name !== "defaultProps") {
return;
}
if (!ER25__namespace.isComponentNameLoose(object.name)) {
return;
}
const variable = VAR2__namespace.findVariable(object.name, context.sourceCode.getScope(node));
const variableNode = VAR2__namespace.getVariableInitNode(variable, 0);
if (variableNode == null) return;
if (!AST8__namespace.isFunction(variableNode) && !ER25__namespace.isClassComponent(variableNode)) return;
context.report({ messageId: "noDefaultProps", node: property });
},
PropertyDefinition(node) {
if (!ER25__namespace.isClassComponent(node.parent.parent)) {
return;
}
if (!node.static || node.key.type !== types.AST_NODE_TYPES.Identifier || node.key.name !== "defaultProps") {
return;
}
context.report({ messageId: "noDefaultProps", node });
}
};
}
var RULE_NAME25 = "no-direct-mutation-state";
var RULE_FEATURES25 = [];
function isConstructorFunction(node) {
return AST8__namespace.isOneOf([types.AST_NODE_TYPES.FunctionDeclaration, types.AST_NODE_TYPES.FunctionExpression])(node) && AST8__namespace.isMethodOrProperty(node.parent) && node.parent.key.type === types.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_FEATURES25
},
messages: {
noDirectMutationState: "Do not mutate state directly. Use 'setState()' instead."
},
schema: []
},
name: RULE_NAME25,
create: create25,
defaultOptions: []
});
function create25(context) {
return {
AssignmentExpression(node) {
if (!ER25__namespace.isAssignmentToThisState(node)) return;
const parentClass = AST8__namespace.findParentNode(
node,
AST8__namespace.isOneOf([
types.AST_NODE_TYPES.ClassDeclaration,
types.AST_NODE_TYPES.ClassExpression
])
);
if (parentClass == null) return;
if (ER25__namespace.isClassComponent(parentClass) && context.sourceCode.getScope(node).block !== AST8__namespace.findParentNode(node, isConstructorFunction)) {
context.report({
messageId: "noDirectMutationState",
node
});
}
}
};
}
var RULE_NAME26 = "no-duplicate-key";
var RULE_FEATURES26 = [];
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_FEATURES26
},
messages: {
noDuplicateKey: "A key must be unique. '{{value}}' is duplicated."
},
schema: []
},
name: RULE_NAME26,
create: create26,
defaultOptions: []
});
function create26(context) {
if (!context.sourceCode.getText().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 AST8__namespace.isNodeEqual(aValue, bValue);
}
return {
"JSXAttribute[name.name='key']"(node) {
const jsxElement = node.parent.parent;
switch (jsxElement.parent.type) {
case types.AST_NODE_TYPES.ArrayExpression:
case types.AST_NODE_TYPES.JSXElement:
case types.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 = AST8__namespace.findParentNode(jsxElement, AST8__namespace.isArrayMapCall);
const iter = AST8__namespace.findParentNode(jsxElement, (n) => n === call || AST8__namespace.isFunction(n));
if (!AST8__namespace.isFunction(iter)) return;
const arg0 = call?.arguments[0];
if (call == null || arg0 == null) return;
if (AST8__namespace.getJSExpression(arg0) !== iter) {
return;
}
keyedEntries.set(call, {
hasDuplicate: node.value?.type === types.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)
}
});
}
}
}
};
}
var RULE_NAME27 = "no-forward-ref";
var RULE_FEATURES27 = [
"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_FEATURES27
},
fixable: "code",
messages: {
noForwardRef: "In React 19, 'forwardRef' is no longer necessary. Pass 'ref' as a prop instead."
},
schema: []
},
name: RULE_NAME27,
create: create27,
defaultOptions: []
});
function create27(context) {
if (!context.sourceCode.text.includes("forwardRef")) {
return {};
}
const { version: version2 } = shared.getSettingsFromContext(context);
if (compareVersions.compare(version2, "19.0.0", "<")) {
return {};
}
return {
CallExpression(node) {
if (!ER25__namespace.isForwardRefCall(context, node)) {
return;
}
const id = AST8__namespace.getFunctionId(node);
context.report({
messageId: "noForwardRef",
node: id ?? node,
fix: getFix(context, node)
});
}
};
}
function getFix(context, node) {
return (fixer) => {
const [componentNode] = node.arguments;
if (componentNode == null || !AST8__namespace.isFunction(componentNode)) {
return [];
}
return [
// unwrap component from forwardRef call
fixer.removeRange([node.range[0], componentNode.range[0]]),
fixer.removeRange([componentNode.range[1], node.range[1]]),
// update component props and ref arguments to match the new signature
...getComponentPropsFixes(
context,
fixer,
componentNode,
node.typeArguments?.params ?? []
)
];
};
}
function getComponentPropsFixes(context, fixer, node, typeArguments) {
const getText = (node2) => context.sourceCode.getText(node2);
const [arg0, arg1] = node.params;
const [typeArg0, typeArg1] = typeArguments;
if (arg0 == null) {
return [];
}
const fixedArg0Text = tsPattern.match(arg0).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => `...${n.name}`).with({ type: types.AST_NODE_TYPES.ObjectPattern }, (n) => n.properties.map(getText).join(", ")).otherwise(() => null);
const fixedArg1Text = tsPattern.match(arg1).with(tsPattern.P.nullish, () => "ref").with({ type: types.AST_NODE_TYPES.Identifier, name: "ref" }, () => "ref").with({ type: types.AST_NODE_TYPES.Identifier, name: tsPattern.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]])]
];
}
var RULE_NAME28 = "no-implicit-key";
var RULE_FEATURES28 = [
"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_FEATURES28
},
messages: {
noImplicitKey: "Do not use implicit 'key' props."
},
schema: []
},
name: RULE_NAME28,
create: create28,
defaultOptions: []
});
function create28(context) {
return {
JSXOpeningElement(node) {
const initialScope = context.sourceCode.getScope(node);
const keyProp = ER25__namespace.getAttribute(context, "key", node.attributes, initialScope);
const isKeyPropOnElement = node.attributes.some(
(n) => n.type === types.AST_NODE_TYPES.JSXAttribute && n.name.type === types.AST_NODE_TYPES.JSXIdentifier && n.name.name === "key"
);
if (keyProp != null && !isKeyPropOnElement) {
context.report({ messageId: "noImplicitKey", node: keyProp });
}
}
};
}
var RULE_NAME29 = "no-leaked-conditional-rendering";
var RULE_FEATURES29 = [
"TSC"
];
var tsHelpers = {
isAnyType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.TypeParameter | ts__default.default.TypeFlags.Any),
isBigIntType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.BigIntLike),
isBooleanType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.BooleanLike),
isEnumType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.EnumLike),
isFalsyBigIntType: (type) => type.isLiteral() && tsPattern.isMatching({ value: { base10Value: "0" } }, type),
isFalsyNumberType: (type) => type.isNumberLiteral() && type.value === 0,
isFalsyStringType: (type) => type.isStringLiteral() && type.value === "",
isNeverType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.Never),
isNullishType: (type) => tsApiUtils.isTypeFlagSet(
type,
ts__default.default.TypeFlags.Null | ts__default.default.TypeFlags.Undefined | ts__default.default.TypeFlags.VoidLike
),
isNumberType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.NumberLike),
isObjectType: (type) => !tsApiUtils.isTypeFlagSet(
type,
ts__default.default.TypeFlags.Null | ts__default.default.TypeFlags.Undefined | ts__default.default.TypeFlags.VoidLike | ts__default.default.TypeFlags.BooleanLike | ts__default.default.TypeFlags.StringLike | ts__default.default.TypeFlags.NumberLike | ts__default.default.TypeFlags.BigIntLike | ts__default.default.TypeFlags.TypeParameter | ts__default.default.TypeFlags.Any | ts__default.default.TypeFlags.Unknown | ts__default.default.TypeFlags.Never
),
isStringType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.StringLike),
isTruthyBigIntType: (type) => type.isLiteral() && tsPattern.isMatching({ value: { base10Value: tsPattern.P.not("0") } }, type),
isTruthyNumberType: (type) => type.isNumberLiteral() && type.value !== 0,
isTruthyStringType: (type) => type.isStringLiteral() && type.value !== "",
isUnknownType: (type) => tsApiUtils.isTypeFlagSet(type, ts__default.default.TypeFlags.Unknown)
};
function inspectVariantTypes(types) {
const variantTypes = /