UNPKG

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
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