UNPKG

eslint-plugin-react-dom

Version:

ESLint React's ESLint plugin for React DOM related rules.

1,930 lines (1,909 loc) • 54.6 kB
import { DEFAULT_ESLINT_REACT_SETTINGS, RE_JAVASCRIPT_PROTOCOL, WEBSITE_URL, getConfigAdapters, getSettingsFromContext } from "@eslint-react/shared"; import { getJsxAttribute, getJsxElementType, isJsxHostElement, isJsxText, resolveJsxAttributeValue } from "@eslint-react/core"; import { ESLintUtils } from "@typescript-eslint/utils"; import { AST_NODE_TYPES } from "@typescript-eslint/types"; import { compare } from "compare-versions"; //#region rolldown:runtime var __defProp = Object.defineProperty; var __export = (all, symbols) => { let target = {}; for (var name$3 in all) { __defProp(target, name$3, { get: all[name$3], enumerable: true }); } if (symbols) { __defProp(target, Symbol.toStringTag, { value: "Module" }); } return target; }; //#endregion //#region package.json var name$2 = "eslint-plugin-react-dom"; var version = "2.4.0"; //#endregion //#region src/utils/create-jsx-element-resolver.ts /** * Creates a resolver for JSX elements that determines both the JSX element type * and the underlying DOM element type. * * This resolver handles: * 1. Regular HTML elements (div, span, etc.) * 2. Polymorphic components (components that can render as different elements via a prop) * * @param context The ESLint rule context * @returns An object with a resolve method to determine element types */ function createJsxElementResolver(context) { const { polymorphicPropName } = getSettingsFromContext(context); return { resolve(node) { const elementName = getJsxElementType(context, node); const result = { domElementType: elementName, jsxElementType: elementName }; if (elementName === elementName.toLowerCase() || polymorphicPropName == null) return result; const polymorphicProp = getJsxAttribute(context, node)(polymorphicPropName); if (polymorphicProp != null) { const staticValue = resolveJsxAttributeValue(context, polymorphicProp).toStatic(polymorphicPropName); if (typeof staticValue === "string") return { ...result, domElementType: staticValue }; } return result; } }; } //#endregion //#region src/utils/create-rule.ts function getDocsUrl(ruleName) { return `${WEBSITE_URL}/docs/rules/dom-${ruleName}`; } const createRule = ESLintUtils.RuleCreator(getDocsUrl); //#endregion //#region src/rules/no-dangerously-set-innerhtml.ts const RULE_NAME$17 = "no-dangerously-set-innerhtml"; const DSIH$1 = "dangerouslySetInnerHTML"; var no_dangerously_set_innerhtml_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `dangerouslySetInnerHTML`." }, messages: { noDangerouslySetInnerhtml: "Using 'dangerouslySetInnerHTML' may have security implications." }, schema: [] }, name: RULE_NAME$17, create: create$17, defaultOptions: [] }); function create$17(context) { if (!context.sourceCode.text.includes(DSIH$1)) return {}; return { JSXElement(node) { const dsihProp = getJsxAttribute(context, node)(DSIH$1); if (dsihProp == null) return; context.report({ messageId: "noDangerouslySetInnerhtml", node: dsihProp }); } }; } //#endregion //#region src/rules/no-dangerously-set-innerhtml-with-children.ts const RULE_NAME$16 = "no-dangerously-set-innerhtml-with-children"; var no_dangerously_set_innerhtml_with_children_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `dangerouslySetInnerHTML` and `children` at the same time." }, messages: { noDangerouslySetInnerhtmlWithChildren: "A DOM component cannot use both children and 'dangerouslySetInnerHTML'." }, schema: [] }, name: RULE_NAME$16, create: create$16, defaultOptions: [] }); const DSIH = "dangerouslySetInnerHTML"; /** * Checks if a JSX child node is considered significant (i.e., not just whitespace for formatting) * @param node The JSX child node to check * @returns `true` if the node is significant, `false` otherwise */ function isSignificantChildren(node) { if (!isJsxText(node)) return true; return !(node.raw.trim() === "" && node.raw.includes("\n")); } function create$16(context) { if (!context.sourceCode.text.includes(DSIH)) return {}; return { JSXElement(node) { const findJsxAttribute = getJsxAttribute(context, node); if (findJsxAttribute(DSIH) == null) return; const childrenPropOrNode = findJsxAttribute("children") ?? node.children.find(isSignificantChildren); if (childrenPropOrNode == null) return; context.report({ messageId: "noDangerouslySetInnerhtmlWithChildren", node: childrenPropOrNode }); } }; } //#endregion //#region src/rules/no-find-dom-node.ts const RULE_NAME$15 = "no-find-dom-node"; var no_find_dom_node_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `findDOMNode`." }, messages: { noFindDomNode: "[Deprecated] Use alternatives instead." }, schema: [] }, name: RULE_NAME$15, create: create$15, defaultOptions: [] }); const findDOMNode = "findDOMNode"; function create$15(context) { if (!context.sourceCode.text.includes(findDOMNode)) return {}; return { CallExpression(node) { const { callee } = node; switch (callee.type) { case AST_NODE_TYPES.Identifier: if (callee.name === findDOMNode) context.report({ messageId: "noFindDomNode", node }); return; case AST_NODE_TYPES.MemberExpression: if (callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === findDOMNode) context.report({ messageId: "noFindDomNode", node }); return; } } }; } //#endregion //#region src/rules/no-flush-sync.ts const RULE_NAME$14 = "no-flush-sync"; var no_flush_sync_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `flushSync`." }, messages: { noFlushSync: "Using 'flushSync' is uncommon and can hurt the performance of your app." }, schema: [] }, name: RULE_NAME$14, create: create$14, defaultOptions: [] }); const flushSync = "flushSync"; function create$14(context) { if (!context.sourceCode.text.includes(flushSync)) return {}; return { CallExpression(node) { const { callee } = node; switch (callee.type) { case AST_NODE_TYPES.Identifier: if (callee.name === flushSync) context.report({ messageId: "noFlushSync", node }); return; case AST_NODE_TYPES.MemberExpression: if (callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === flushSync) context.report({ messageId: "noFlushSync", node }); return; } } }; } //#endregion //#region src/rules/no-hydrate.ts const RULE_NAME$13 = "no-hydrate"; var no_hydrate_default = createRule({ meta: { type: "problem", docs: { description: "Replaces usages of `ReactDom.hydrate()` with `hydrateRoot()`." }, fixable: "code", messages: { noHydrate: "[Deprecated] Use 'hydrateRoot()' instead." }, schema: [] }, name: RULE_NAME$13, create: create$13, defaultOptions: [] }); const hydrate = "hydrate"; function create$13(context) { if (!context.sourceCode.text.includes(hydrate)) return {}; if (compare(getSettingsFromContext(context).version, "18.0.0", "<")) return {}; const reactDomNames = /* @__PURE__ */ new Set(); const hydrateNames = /* @__PURE__ */ new Set(); return { CallExpression(node) { switch (true) { case node.callee.type === AST_NODE_TYPES.Identifier && hydrateNames.has(node.callee.name): context.report({ messageId: "noHydrate", node, fix: getFix$2(context, node) }); return; case node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === hydrate && reactDomNames.has(node.callee.object.name): context.report({ messageId: "noHydrate", node, fix: getFix$2(context, node) }); return; } }, ImportDeclaration(node) { const [baseSource] = node.source.value.split("/"); if (baseSource !== "react-dom") return; for (const specifier of node.specifiers) switch (specifier.type) { case AST_NODE_TYPES.ImportSpecifier: if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue; if (specifier.imported.name === hydrate) hydrateNames.add(specifier.local.name); continue; case AST_NODE_TYPES.ImportDefaultSpecifier: case AST_NODE_TYPES.ImportNamespaceSpecifier: reactDomNames.add(specifier.local.name); continue; } } }; } function getFix$2(context, node) { const getText$1 = (n) => context.sourceCode.getText(n); return (fixer) => { const [arg0, arg1] = node.arguments; if (arg0 == null || arg1 == null) return null; return [fixer.insertTextBefore(context.sourceCode.ast, "import { hydrateRoot } from \"react-dom/client\";\n"), fixer.replaceText(node, `hydrateRoot(${getText$1(arg1)}, ${getText$1(arg0)})`)]; }; } //#endregion //#region src/rules/no-missing-button-type.ts const RULE_NAME$12 = "no-missing-button-type"; const BUTTON_TYPES = [ "button", "submit", "reset" ]; var no_missing_button_type_default = createRule({ meta: { type: "problem", docs: { description: "Enforces explicit `type` attribute for `button` elements." }, hasSuggestions: true, messages: { addButtonType: "Add 'type' attribute with value '{{type}}'.", noMissingButtonType: "Add missing 'type' attribute on 'button' component." }, schema: [] }, name: RULE_NAME$12, create: create$12, defaultOptions: [] }); function create$12(context) { const resolver = createJsxElementResolver(context); return { JSXElement(node) { if (resolver.resolve(node).domElementType !== "button") return; if (getJsxAttribute(context, node)("type") != null) return; context.report({ messageId: "noMissingButtonType", node: node.openingElement, suggest: BUTTON_TYPES.map((type) => ({ messageId: "addButtonType", data: { type }, fix: (fixer) => fixer.insertTextAfter(node.openingElement.name, ` type="${type}"`) })) }); } }; } //#endregion //#region src/rules/no-missing-iframe-sandbox.ts const RULE_NAME$11 = "no-missing-iframe-sandbox"; var no_missing_iframe_sandbox_default = createRule({ meta: { type: "problem", docs: { description: "Enforces explicit `sandbox` prop for `iframe` elements." }, fixable: "code", hasSuggestions: true, messages: { addIframeSandbox: "Add 'sandbox' prop with value '{{value}}'.", noMissingIframeSandbox: "Add missing 'sandbox' prop on 'iframe' component." }, schema: [] }, name: RULE_NAME$11, create: create$11, defaultOptions: [] }); function create$11(context) { const resolver = createJsxElementResolver(context); return { JSXElement(node) { const { domElementType } = resolver.resolve(node); if (domElementType !== "iframe") return; const sandboxProp = getJsxAttribute(context, node)("sandbox"); if (sandboxProp == null) { context.report({ messageId: "noMissingIframeSandbox", node: node.openingElement, suggest: [{ messageId: "addIframeSandbox", data: { value: "" }, fix(fixer) { return fixer.insertTextAfter(node.openingElement.name, ` sandbox=""`); } }] }); return; } const sandboxValue = resolveJsxAttributeValue(context, sandboxProp); if (typeof sandboxValue.toStatic("sandbox") === "string") return; context.report({ messageId: "noMissingIframeSandbox", node: sandboxValue.node ?? sandboxProp, suggest: [{ messageId: "addIframeSandbox", data: { value: "" }, fix(fixer) { if (sandboxValue.kind.startsWith("spread")) return null; return fixer.replaceText(sandboxProp, `sandbox=""`); } }] }); } }; } //#endregion //#region src/rules/no-namespace.ts const RULE_NAME$10 = "no-namespace"; var no_namespace_default = createRule({ meta: { type: "problem", docs: { description: "Enforces the absence of a `namespace` in React elements." }, messages: { noNamespace: "A React component '{{name}}' must not be in a namespace, as React does not support them." }, schema: [] }, name: RULE_NAME$10, create: create$10, defaultOptions: [] }); function create$10(context) { return { JSXElement(node) { const name$3 = getJsxElementType(context, node); if (typeof name$3 !== "string" || !name$3.includes(":")) return; context.report({ messageId: "noNamespace", node: node.openingElement.name, data: { name: name$3 } }); } }; } //#endregion //#region src/rules/no-render.ts const RULE_NAME$9 = "no-render"; var no_render_default = createRule({ meta: { type: "problem", docs: { description: "Replaces usages of `ReactDom.render()` with `createRoot(node).render()`." }, fixable: "code", messages: { noRender: "[Deprecated] Use 'createRoot(node).render()' instead." }, schema: [] }, name: RULE_NAME$9, create: create$9, defaultOptions: [] }); function create$9(context) { if (!context.sourceCode.text.includes("render")) return {}; if (compare(getSettingsFromContext(context).version, "18.0.0", "<")) return {}; const reactDomNames = new Set(["ReactDOM", "ReactDom"]); const renderNames = /* @__PURE__ */ new Set(); return { CallExpression(node) { switch (true) { case node.callee.type === AST_NODE_TYPES.Identifier && renderNames.has(node.callee.name): context.report({ messageId: "noRender", node, fix: getFix$1(context, node) }); return; case node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "render" && reactDomNames.has(node.callee.object.name): context.report({ messageId: "noRender", node, fix: getFix$1(context, node) }); return; } }, ImportDeclaration(node) { const [baseSource] = node.source.value.split("/"); if (baseSource !== "react-dom") return; for (const specifier of node.specifiers) switch (specifier.type) { case AST_NODE_TYPES.ImportSpecifier: if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue; if (specifier.imported.name === "render") renderNames.add(specifier.local.name); continue; case AST_NODE_TYPES.ImportDefaultSpecifier: case AST_NODE_TYPES.ImportNamespaceSpecifier: reactDomNames.add(specifier.local.name); continue; } } }; } /** * Provides a fixer function to replace `render(app, container)` with `createRoot(container).render(app)` * @param context The rule context * @param node The `CallExpression` node to fix * @returns A fixer function or null if the fix cannot be applied */ function getFix$1(context, node) { const getText$1 = (n) => context.sourceCode.getText(n); return (fixer) => { const [arg0, arg1] = node.arguments; if (arg0 == null || arg1 == null) return null; return [fixer.insertTextBefore(context.sourceCode.ast, "import { createRoot } from \"react-dom/client\";\n"), fixer.replaceText(node, `createRoot(${getText$1(arg1)}).render(${getText$1(arg0)})`)]; }; } //#endregion //#region src/rules/no-render-return-value.ts const RULE_NAME$8 = "no-render-return-value"; const banParentTypes = [ AST_NODE_TYPES.VariableDeclarator, AST_NODE_TYPES.Property, AST_NODE_TYPES.ReturnStatement, AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.AssignmentExpression ]; var no_render_return_value_default = createRule({ meta: { type: "problem", docs: { description: "Disallow the return value of `ReactDOM.render`." }, messages: { noRenderReturnValue: "Do not depend on the return value from 'ReactDOM.render'." }, schema: [] }, name: RULE_NAME$8, create: create$8, defaultOptions: [] }); function create$8(context) { const reactDomNames = new Set(["ReactDOM", "ReactDom"]); const renderNames = /* @__PURE__ */ new Set(); return { CallExpression(node) { switch (true) { case node.callee.type === AST_NODE_TYPES.Identifier && renderNames.has(node.callee.name) && banParentTypes.includes(node.parent.type): context.report({ messageId: "noRenderReturnValue", node }); return; case node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "render" && reactDomNames.has(node.callee.object.name) && banParentTypes.includes(node.parent.type): context.report({ messageId: "noRenderReturnValue", node }); return; } }, ImportDeclaration(node) { const [baseSource] = node.source.value.split("/"); if (baseSource !== "react-dom") return; for (const specifier of node.specifiers) switch (specifier.type) { case AST_NODE_TYPES.ImportSpecifier: if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue; if (specifier.imported.name === "render") renderNames.add(specifier.local.name); continue; case AST_NODE_TYPES.ImportDefaultSpecifier: case AST_NODE_TYPES.ImportNamespaceSpecifier: reactDomNames.add(specifier.local.name); continue; } } }; } //#endregion //#region src/rules/no-script-url.ts const RULE_NAME$7 = "no-script-url"; var no_script_url_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `javascript:` URLs as attribute values." }, messages: { noScriptUrl: "Using a `javascript:` URL is a security risk and should be avoided." }, schema: [] }, name: RULE_NAME$7, create: create$7, defaultOptions: [] }); function create$7(context) { return { JSXAttribute(node) { if (node.name.type !== AST_NODE_TYPES.JSXIdentifier || node.value == null) return; const value = resolveJsxAttributeValue(context, node).toStatic(); if (typeof value === "string" && RE_JAVASCRIPT_PROTOCOL.test(value)) context.report({ messageId: "noScriptUrl", node: node.value }); } }; } //#endregion //#region src/rules/no-string-style-prop.ts const RULE_NAME$6 = "no-string-style-prop"; var no_string_style_prop_default = createRule({ meta: { type: "problem", docs: { description: "Disallows the use of string style prop." }, messages: { noStringStyleProp: "Do not use string style prop. Use an object instead." }, schema: [] }, name: RULE_NAME$6, create: create$6, defaultOptions: [] }); function create$6(context) { return { JSXElement(node) { if (!isJsxHostElement(context, node)) return; const styleProp = getJsxAttribute(context, node)("style"); if (styleProp == null) return; const styleValue = resolveJsxAttributeValue(context, styleProp); if (typeof styleValue.toStatic() === "string") context.report({ messageId: "noStringStyleProp", node: styleValue.node ?? styleProp }); } }; } //#endregion //#region src/rules/no-unknown-property.ts const RULE_NAME$5 = "no-unknown-property"; const DEFAULTS = { ignore: [], requireDataLowercase: false }; /** * Map of standard HTML attributes to their React counterparts */ const DOM_ATTRIBUTE_NAMES = { "accept-charset": "acceptCharset", class: "className", crossorigin: "crossOrigin", for: "htmlFor", "http-equiv": "httpEquiv", nomodule: "noModule" }; /** * Map of SVG attributes to their React camelCase equivalents */ const SVGDOM_ATTRIBUTE_NAMES = { "accent-height": "accentHeight", "alignment-baseline": "alignmentBaseline", "arabic-form": "arabicForm", "baseline-shift": "baselineShift", "cap-height": "capHeight", "clip-path": "clipPath", "clip-rule": "clipRule", "color-interpolation": "colorInterpolation", "color-interpolation-filters": "colorInterpolationFilters", "color-profile": "colorProfile", "color-rendering": "colorRendering", "dominant-baseline": "dominantBaseline", "enable-background": "enableBackground", "fill-opacity": "fillOpacity", "fill-rule": "fillRule", "flood-color": "floodColor", "flood-opacity": "floodOpacity", "font-family": "fontFamily", "font-size": "fontSize", "font-size-adjust": "fontSizeAdjust", "font-stretch": "fontStretch", "font-style": "fontStyle", "font-variant": "fontVariant", "font-weight": "fontWeight", "glyph-name": "glyphName", "glyph-orientation-horizontal": "glyphOrientationHorizontal", "glyph-orientation-vertical": "glyphOrientationVertical", "horiz-adv-x": "horizAdvX", "horiz-origin-x": "horizOriginX", "image-rendering": "imageRendering", "letter-spacing": "letterSpacing", "lighting-color": "lightingColor", "marker-end": "markerEnd", "marker-mid": "markerMid", "marker-start": "markerStart", "overline-position": "overlinePosition", "overline-thickness": "overlineThickness", "paint-order": "paintOrder", "panose-1": "panose1", "pointer-events": "pointerEvents", "rendering-intent": "renderingIntent", "shape-rendering": "shapeRendering", "stop-color": "stopColor", "stop-opacity": "stopOpacity", "strikethrough-position": "strikethroughPosition", "strikethrough-thickness": "strikethroughThickness", "stroke-dasharray": "strokeDasharray", "stroke-dashoffset": "strokeDashoffset", "stroke-linecap": "strokeLinecap", "stroke-linejoin": "strokeLinejoin", "stroke-miterlimit": "strokeMiterlimit", "stroke-opacity": "strokeOpacity", "stroke-width": "strokeWidth", "text-anchor": "textAnchor", "text-decoration": "textDecoration", "text-rendering": "textRendering", "underline-position": "underlinePosition", "underline-thickness": "underlineThickness", "unicode-bidi": "unicodeBidi", "unicode-range": "unicodeRange", "units-per-em": "unitsPerEm", "v-alphabetic": "vAlphabetic", "v-hanging": "vHanging", "v-ideographic": "vIdeographic", "v-mathematical": "vMathematical", "vector-effect": "vectorEffect", "vert-adv-y": "vertAdvY", "vert-origin-x": "vertOriginX", "vert-origin-y": "vertOriginY", "word-spacing": "wordSpacing", "writing-mode": "writingMode", "x-height": "xHeight", "xlink:actuate": "xlinkActuate", "xlink:arcrole": "xlinkArcrole", "xlink:href": "xlinkHref", "xlink:role": "xlinkRole", "xlink:show": "xlinkShow", "xlink:title": "xlinkTitle", "xlink:type": "xlinkType", "xml:base": "xmlBase", "xml:lang": "xmlLang", "xml:space": "xmlSpace" }; /** * Map of attributes that are only valid on specific HTML tags */ const ATTRIBUTE_TAGS_MAP = { as: ["link"], abbr: ["th", "td"], align: [ "applet", "caption", "col", "colgroup", "hr", "iframe", "img", "table", "tbody", "td", "tfoot", "th", "thead", "tr" ], allowFullScreen: ["iframe", "video"], autoPictureInPicture: ["video"], charset: ["meta"], checked: ["input"], controls: ["audio", "video"], controlsList: ["audio", "video"], crossOrigin: [ "script", "img", "video", "audio", "link", "image" ], disablePictureInPicture: ["video"], disableRemotePlayback: ["audio", "video"], displaystyle: ["math"], download: ["a", "area"], fill: [ "altGlyph", "circle", "ellipse", "g", "line", "marker", "mask", "path", "polygon", "polyline", "rect", "svg", "symbol", "text", "textPath", "tref", "tspan", "use", "animate", "animateColor", "animateMotion", "animateTransform", "set" ], focusable: ["svg"], imageSizes: ["link"], imageSrcSet: ["link"], loop: ["audio", "video"], mozAllowFullScreen: ["iframe", "video"], muted: ["audio", "video"], noModule: ["script"], onAbort: ["audio", "video"], onCanPlay: ["audio", "video"], onCanPlayThrough: ["audio", "video"], onCancel: ["dialog"], onClose: ["dialog"], onDurationChange: ["audio", "video"], onEmptied: ["audio", "video"], onEncrypted: ["audio", "video"], onEnded: ["audio", "video"], onError: [ "audio", "video", "img", "link", "source", "script", "picture", "iframe" ], onLoad: [ "script", "img", "link", "picture", "iframe", "object", "source" ], onLoadStart: ["audio", "video"], onLoadedData: ["audio", "video"], onLoadedMetadata: ["audio", "video"], onPause: ["audio", "video"], onPlay: ["audio", "video"], onPlaying: ["audio", "video"], onProgress: ["audio", "video"], onRateChange: ["audio", "video"], onResize: ["audio", "video"], onSeeked: ["audio", "video"], onSeeking: ["audio", "video"], onStalled: ["audio", "video"], onSuspend: ["audio", "video"], onTimeUpdate: ["audio", "video"], onVolumeChange: ["audio", "video"], onWaiting: ["audio", "video"], playsInline: ["video"], poster: ["video"], preload: ["audio", "video"], property: ["meta"], returnValue: ["dialog"], scrolling: ["iframe"], valign: [ "tr", "td", "th", "thead", "tbody", "tfoot", "colgroup", "col" ], viewBox: [ "marker", "pattern", "svg", "symbol", "view" ], webkitAllowFullScreen: ["iframe", "video"], webkitDirectory: ["input"] }; /** * Single-word HTML/DOM properties */ const DOM_PROPERTY_NAMES_ONE_WORD = [ "dir", "draggable", "hidden", "id", "lang", "nonce", "part", "slot", "style", "title", "translate", "inert", "accept", "action", "allow", "alt", "as", "async", "buffered", "capture", "challenge", "cite", "code", "cols", "content", "coords", "csp", "data", "decoding", "default", "defer", "disabled", "form", "headers", "height", "high", "href", "icon", "importance", "integrity", "kind", "label", "language", "loading", "list", "loop", "low", "manifest", "max", "media", "method", "min", "multiple", "muted", "name", "open", "optimum", "pattern", "ping", "placeholder", "poster", "preload", "profile", "rel", "required", "reversed", "role", "rows", "sandbox", "scope", "seamless", "selected", "shape", "size", "sizes", "span", "src", "start", "step", "summary", "target", "type", "value", "width", "wmode", "wrap", "accumulate", "additive", "alphabetic", "amplitude", "ascent", "azimuth", "bbox", "begin", "bias", "by", "clip", "color", "cursor", "cx", "cy", "d", "decelerate", "descent", "direction", "display", "divisor", "dur", "dx", "dy", "elevation", "end", "exponent", "fill", "filter", "format", "from", "fr", "fx", "fy", "g1", "g2", "hanging", "height", "hreflang", "ideographic", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "local", "mask", "mode", "offset", "opacity", "operator", "order", "orient", "orientation", "origin", "overflow", "path", "ping", "points", "r", "radius", "rel", "restart", "result", "rotate", "rx", "ry", "scale", "seed", "slope", "spacing", "speed", "stemh", "stemv", "string", "stroke", "to", "transform", "u1", "u2", "unicode", "values", "version", "visibility", "widths", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "property", "ref", "key", "children", "results", "security", "controls" ]; /** * Multi-word (camelCase) HTML/DOM properties */ const DOM_PROPERTY_NAMES_TWO_WORDS = [ "accessKey", "autoCapitalize", "autoFocus", "contentEditable", "enterKeyHint", "exportParts", "inputMode", "itemID", "itemRef", "itemProp", "itemScope", "itemType", "spellCheck", "tabIndex", "acceptCharset", "autoComplete", "autoPlay", "border", "cellPadding", "cellSpacing", "classID", "codeBase", "colSpan", "contextMenu", "dateTime", "encType", "formAction", "formEncType", "formMethod", "formNoValidate", "formTarget", "frameBorder", "hrefLang", "httpEquiv", "imageSizes", "imageSrcSet", "isMap", "keyParams", "keyType", "marginHeight", "marginWidth", "maxLength", "mediaGroup", "minLength", "noValidate", "onAnimationEnd", "onAnimationIteration", "onAnimationStart", "onBlur", "onChange", "onClick", "onContextMenu", "onCopy", "onCompositionEnd", "onCompositionStart", "onCompositionUpdate", "onCut", "onDoubleClick", "onDrag", "onDragEnd", "onDragEnter", "onDragExit", "onDragLeave", "onError", "onFocus", "onInput", "onKeyDown", "onKeyPress", "onKeyUp", "onLoad", "onWheel", "onDragOver", "onDragStart", "onDrop", "onMouseDown", "onMouseEnter", "onMouseLeave", "onMouseMove", "onMouseOut", "onMouseOver", "onMouseUp", "onPaste", "onScroll", "onSelect", "onSubmit", "onToggle", "onTransitionEnd", "radioGroup", "readOnly", "referrerPolicy", "rowSpan", "srcDoc", "srcLang", "srcSet", "useMap", "fetchPriority", "crossOrigin", "accentHeight", "alignmentBaseline", "arabicForm", "attributeName", "attributeType", "baseFrequency", "baselineShift", "baseProfile", "calcMode", "capHeight", "clipPathUnits", "clipPath", "clipRule", "colorInterpolation", "colorInterpolationFilters", "colorProfile", "colorRendering", "contentScriptType", "contentStyleType", "diffuseConstant", "dominantBaseline", "edgeMode", "enableBackground", "fillOpacity", "fillRule", "filterRes", "filterUnits", "floodColor", "floodOpacity", "fontFamily", "fontSize", "fontSizeAdjust", "fontStretch", "fontStyle", "fontVariant", "fontWeight", "glyphName", "glyphOrientationHorizontal", "glyphOrientationVertical", "glyphRef", "gradientTransform", "gradientUnits", "horizAdvX", "horizOriginX", "imageRendering", "kernelMatrix", "kernelUnitLength", "keyPoints", "keySplines", "keyTimes", "lengthAdjust", "letterSpacing", "lightingColor", "limitingConeAngle", "markerEnd", "markerMid", "markerStart", "markerHeight", "markerUnits", "markerWidth", "maskContentUnits", "maskUnits", "mathematical", "numOctaves", "overlinePosition", "overlineThickness", "panose1", "paintOrder", "pathLength", "patternContentUnits", "patternTransform", "patternUnits", "pointerEvents", "pointsAtX", "pointsAtY", "pointsAtZ", "preserveAlpha", "preserveAspectRatio", "primitiveUnits", "referrerPolicy", "refX", "refY", "rendering-intent", "repeatCount", "repeatDur", "requiredExtensions", "requiredFeatures", "shapeRendering", "specularConstant", "specularExponent", "spreadMethod", "startOffset", "stdDeviation", "stitchTiles", "stopColor", "stopOpacity", "strikethroughPosition", "strikethroughThickness", "strokeDasharray", "strokeDashoffset", "strokeLinecap", "strokeLinejoin", "strokeMiterlimit", "strokeOpacity", "strokeWidth", "surfaceScale", "systemLanguage", "tableValues", "targetX", "targetY", "textAnchor", "textDecoration", "textRendering", "textLength", "transformOrigin", "underlinePosition", "underlineThickness", "unicodeBidi", "unicodeRange", "unitsPerEm", "vAlphabetic", "vHanging", "vIdeographic", "vMathematical", "vectorEffect", "vertAdvY", "vertOriginX", "vertOriginY", "viewBox", "viewTarget", "wordSpacing", "writingMode", "xHeight", "xChannelSelector", "xlinkActuate", "xlinkArcrole", "xlinkHref", "xlinkRole", "xlinkShow", "xlinkTitle", "xlinkType", "xmlBase", "xmlLang", "xmlnsXlink", "xmlSpace", "yChannelSelector", "zoomAndPan", "autoCorrect", "autoSave", "className", "dangerouslySetInnerHTML", "defaultValue", "defaultChecked", "htmlFor", "onBeforeInput", "onChange", "onInvalid", "onReset", "onTouchCancel", "onTouchEnd", "onTouchMove", "onTouchStart", "suppressContentEditableWarning", "suppressHydrationWarning", "onAbort", "onCanPlay", "onCanPlayThrough", "onDurationChange", "onEmptied", "onEncrypted", "onEnded", "onLoadedData", "onLoadedMetadata", "onLoadStart", "onPause", "onPlay", "onPlaying", "onProgress", "onRateChange", "onResize", "onSeeked", "onSeeking", "onStalled", "onSuspend", "onTimeUpdate", "onVolumeChange", "onWaiting", "onCopyCapture", "onCutCapture", "onPasteCapture", "onCompositionEndCapture", "onCompositionStartCapture", "onCompositionUpdateCapture", "onFocusCapture", "onBlurCapture", "onChangeCapture", "onBeforeInputCapture", "onInputCapture", "onResetCapture", "onSubmitCapture", "onInvalidCapture", "onLoadCapture", "onErrorCapture", "onKeyDownCapture", "onKeyPressCapture", "onKeyUpCapture", "onAbortCapture", "onCanPlayCapture", "onCanPlayThroughCapture", "onDurationChangeCapture", "onEmptiedCapture", "onEncryptedCapture", "onEndedCapture", "onLoadedDataCapture", "onLoadedMetadataCapture", "onLoadStartCapture", "onPauseCapture", "onPlayCapture", "onPlayingCapture", "onProgressCapture", "onRateChangeCapture", "onSeekedCapture", "onSeekingCapture", "onStalledCapture", "onSuspendCapture", "onTimeUpdateCapture", "onVolumeChangeCapture", "onWaitingCapture", "onSelectCapture", "onTouchCancelCapture", "onTouchEndCapture", "onTouchMoveCapture", "onTouchStartCapture", "onScrollCapture", "onWheelCapture", "onAnimationEndCapture", "onAnimationIteration", "onAnimationStartCapture", "onTransitionEndCapture", "onAuxClick", "onAuxClickCapture", "onClickCapture", "onContextMenuCapture", "onDoubleClickCapture", "onDragCapture", "onDragEndCapture", "onDragEnterCapture", "onDragExitCapture", "onDragLeaveCapture", "onDragOverCapture", "onDragStartCapture", "onDropCapture", "onMouseDown", "onMouseDownCapture", "onMouseMoveCapture", "onMouseOutCapture", "onMouseOverCapture", "onMouseUpCapture", "autoPictureInPicture", "controlsList", "disablePictureInPicture", "disableRemotePlayback" ]; /** * DOM properties that are exempt from case sensitivity checks */ const DOM_PROPERTIES_IGNORE_CASE = [ "charset", "allowFullScreen", "webkitAllowFullScreen", "mozAllowFullScreen", "webkitDirectory" ]; /** * List of ARIA attributes */ const ARIA_PROPERTIES = [ "aria-atomic", "aria-braillelabel", "aria-brailleroledescription", "aria-busy", "aria-controls", "aria-current", "aria-describedby", "aria-description", "aria-details", "aria-disabled", "aria-dropeffect", "aria-errormessage", "aria-flowto", "aria-grabbed", "aria-haspopup", "aria-hidden", "aria-invalid", "aria-keyshortcuts", "aria-label", "aria-labelledby", "aria-live", "aria-owns", "aria-relevant", "aria-roledescription", "aria-autocomplete", "aria-checked", "aria-expanded", "aria-level", "aria-modal", "aria-multiline", "aria-multiselectable", "aria-orientation", "aria-placeholder", "aria-pressed", "aria-readonly", "aria-required", "aria-selected", "aria-sort", "aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-valuetext", "aria-activedescendant", "aria-colcount", "aria-colindex", "aria-colindextext", "aria-colspan", "aria-posinset", "aria-rowcount", "aria-rowindex", "aria-rowindextext", "aria-rowspan", "aria-setsize" ]; /** * React-specific pointer event handlers added in React 16.4 */ const REACT_ON_PROPS = [ "onGotPointerCapture", "onGotPointerCaptureCapture", "onLostPointerCapture", "onLostPointerCapture", "onLostPointerCaptureCapture", "onPointerCancel", "onPointerCancelCapture", "onPointerDown", "onPointerDownCapture", "onPointerEnter", "onPointerEnterCapture", "onPointerLeave", "onPointerLeaveCapture", "onPointerMove", "onPointerMoveCapture", "onPointerOut", "onPointerOutCapture", "onPointerOver", "onPointerOverCapture", "onPointerUp", "onPointerUpCapture" ]; /** * Popover API properties added in React 19 */ const POPOVER_API_PROPS = [ "popover", "popoverTarget", "popoverTargetAction", "onToggle", "onBeforeToggle" ]; /** * Gets all valid DOM property names based on React version * @param context ESLint rule context * @returns Array of valid DOM property names */ function getDOMPropertyNames(context) { const ALL_DOM_PROPERTY_NAMES = DOM_PROPERTY_NAMES_TWO_WORDS.concat(DOM_PROPERTY_NAMES_ONE_WORD); if (testReactVersion(context, "<=", "16.1.0")) { ALL_DOM_PROPERTY_NAMES.push("allowTransparency"); return ALL_DOM_PROPERTY_NAMES; } if (testReactVersion(context, ">=", "16.4.0")) ALL_DOM_PROPERTY_NAMES.push(...REACT_ON_PROPS); testReactVersion(context, ">=", "19.0.0-rc.0") ? ALL_DOM_PROPERTY_NAMES.push(...POPOVER_API_PROPS) : ALL_DOM_PROPERTY_NAMES.push(...POPOVER_API_PROPS.map((prop) => prop.toLowerCase())); return ALL_DOM_PROPERTY_NAMES; } /** * Checks if a node's parent is a JSX tag that is written with lowercase letters, * and is not a custom web component. * @param childNode JSX element being tested * @returns Whether the node is a valid HTML tag in JSX */ function isValidHTMLTagInJSX(childNode) { if (/^[a-z][^-]*$/.test(childNode.parent.name.name)) return !childNode.parent.attributes.some((attrNode) => attrNode.type === "JSXAttribute" && attrNode.name.type === "JSXIdentifier" && attrNode.name.name === "is"); return false; } /** * Normalizes attribute names that should be case-insensitive * @param name Attribute name to normalize * @returns Normalized attribute name */ function normalizeAttributeCase(name$3) { return DOM_PROPERTIES_IGNORE_CASE.find((element) => element.toLowerCase() === name$3.toLowerCase()) || name$3; } /** * Checks if an attribute name is a valid data-* attribute * @param name Attribute name to test * @returns Whether the attribute is a valid data attribute */ function isValidDataAttribute(name$3) { return !/^data-xml/i.test(name$3) && /^data-[^:]*$/.test(name$3); } /** * Checks if an attribute name has uppercase characters * @param name Attribute name to test * @returns Whether the name has uppercase characters */ function hasUpperCaseCharacter(name$3) { return name$3.toLowerCase() !== name$3; } /** * Checks if an attribute is a valid ARIA attribute * @param name Attribute name to test * @returns Whether the attribute is a valid ARIA attribute */ function isValidAriaAttribute(name$3) { return ARIA_PROPERTIES.some((element) => element === name$3); } /** * Gets the tag name for a JSXAttribute * @param node JSXAttribute to get tag name from * @returns Tag name or null */ function getTagName(node) { if (node?.parent?.name) return node.parent.name.name; return null; } /** * Checks if the tag name has a dot (member expression) * @param node JSXAttribute to check * @returns Whether the tag name has a dot */ function tagNameHasDot(node) { return !!(node.parent?.name && node.parent.name.type === "JSXMemberExpression"); } /** * Gets the standard name of an attribute * @param name Attribute name * @param context ESLint context * @returns Standard name or undefined */ function getStandardName(name$3, context) { if (has(DOM_ATTRIBUTE_NAMES, name$3)) return DOM_ATTRIBUTE_NAMES[name$3]; if (has(SVGDOM_ATTRIBUTE_NAMES, name$3)) return SVGDOM_ATTRIBUTE_NAMES[name$3]; return getDOMPropertyNames(context).find((element) => element.toLowerCase() === name$3.toLowerCase()); } /** * Checks if an object has a property * @param obj Object to check * @param key Key to check for * @returns Whether the object has the property */ function has(obj, key) { return Object.hasOwn(obj, key); } /** * Gets text of a node * @param context ESLint context * @param node Node to get text from * @returns Node's text */ function getText(context, node) { return context.sourceCode.getText(node); } /** * Tests React version against a comparator * @param context ESLint context * @param comparator Comparison operator * @param version Version to compare against * @returns Comparison result */ function testReactVersion(context, comparator, version$1) { const { version: localVersion } = getSettingsFromContext(context); return compare(localVersion, version$1, comparator); } const messages = { dataLowercaseRequired: "React does not recognize data-* props with uppercase characters on a DOM element. Found '{{name}}', use '{{lowerCaseName}}' instead", invalidPropOnTag: "Invalid property '{{name}}' found on tag '{{tagName}}', but it is only allowed on: {{allowedTags}}", unknownProp: "Unknown property '{{name}}' found", unknownPropWithStandardName: "Unknown property '{{name}}' found, use '{{standardName}}' instead" }; var no_unknown_property_default = createRule({ meta: { type: "problem", docs: { description: "Disallow unknown `DOM` property." }, fixable: "code", messages, schema: [{ type: "object", additionalProperties: false, properties: { ignore: { type: "array", items: { type: "string" } }, requireDataLowercase: { type: "boolean", default: false } } }] }, name: RULE_NAME$5, create: create$5, defaultOptions: [] }); /** * Create function for the ESLint rule * @param context ESLint rule context * @returns Rule listener */ function create$5(context) { /** * Gets the ignore configuration from rule options * @returns Array of attribute names to ignore */ function getIgnoreConfig() { return context.options[0]?.ignore || DEFAULTS.ignore; } /** * Gets the requireDataLowercase option from rule options * @returns Whether data attributes must be lowercase */ function getRequireDataLowercase() { return context.options[0] && typeof context.options[0].requireDataLowercase !== "undefined" ? !!context.options[0].requireDataLowercase : DEFAULTS.requireDataLowercase; } return { JSXAttribute(node) { const ignoreNames = getIgnoreConfig(); const actualName = getText(context, node.name); if (ignoreNames.indexOf(actualName) >= 0) return; const name$3 = normalizeAttributeCase(actualName); if (tagNameHasDot(node)) return; if (isValidDataAttribute(name$3)) { if (getRequireDataLowercase() && hasUpperCaseCharacter(name$3)) context.report({ node, messageId: "dataLowercaseRequired", data: { name: actualName, lowerCaseName: actualName.toLowerCase() } }); return; } if (isValidAriaAttribute(name$3)) return; const tagName = getTagName(node); if (tagName === "fbt" || tagName === "fbs") return; if (!isValidHTMLTagInJSX(node)) return; const allowedTags = has(ATTRIBUTE_TAGS_MAP, name$3) ? ATTRIBUTE_TAGS_MAP[name$3] : null; if (tagName && allowedTags) { if (allowedTags.indexOf(tagName) === -1) context.report({ node, messageId: "invalidPropOnTag", data: { name: actualName, allowedTags: allowedTags.join(", "), tagName } }); return; } const standardName = getStandardName(name$3, context); const hasStandardNameButIsNotUsed = !!standardName && standardName !== name$3; if (!!standardName && standardName === name$3) return; if (hasStandardNameButIsNotUsed) { context.report({ node, messageId: "unknownPropWithStandardName", data: { name: actualName, standardName }, fix(fixer) { return fixer.replaceText(node.name, standardName); } }); return; } context.report({ node, messageId: "unknownProp", data: { name: actualName } }); } }; } //#endregion //#region src/rules/no-unsafe-iframe-sandbox.ts const RULE_NAME$4 = "no-unsafe-iframe-sandbox"; const UNSAFE_SANDBOX_VALUES = ["allow-scripts", "allow-same-origin"]; /** * Checks if the sandbox attribute value contains an unsafe combination * An iframe with both "allow-scripts" and "allow-same-origin" can remove its sandbox attribute, * making it as insecure as an iframe without any sandboxing * @param value The value of the sandbox attribute * @returns `true` if the value is a string and contains an unsafe combination, `false` otherwise */ function isUnsafeSandboxCombination(value) { if (typeof value !== "string") return false; return UNSAFE_SANDBOX_VALUES.every((v) => value.includes(v)); } var no_unsafe_iframe_sandbox_default = createRule({ meta: { type: "problem", docs: { description: "Enforces `sandbox` attribute for `iframe` elements is not set to unsafe combinations." }, messages: { noUnsafeIframeSandbox: "Unsafe 'sandbox' attribute value on 'iframe' component." }, schema: [] }, name: RULE_NAME$4, create: create$4, defaultOptions: [] }); function create$4(context) { const resolver = createJsxElementResolver(context); return { JSXElement(node) { if (resolver.resolve(node).domElementType !== "iframe") return; const sandboxProp = getJsxAttribute(context, node)("sandbox"); if (sandboxProp == null) return; const sandboxValue = resolveJsxAttributeValue(context, sandboxProp); if (isUnsafeSandboxCombination(sandboxValue.toStatic("sandbox"))) context.report({ messageId: "noUnsafeIframeSandbox", node: sandboxValue.node ?? sandboxProp }); } }; } //#endregion //#region src/rules/no-unsafe-target-blank.ts const RULE_NAME$3 = "no-unsafe-target-blank"; /** * Checks if a value appears to be an external link. * External links typically start with http(s):// or have protocol-relative format. * @param value The value to check * @returns Whether the value represents an external link */ function isExternalLinkLike(value) { if (typeof value !== "string") return false; return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value); } /** * Checks if a rel prop value contains the necessary security attributes. * At minimum, it should contain "noreferrer". * @param value The rel prop value to check * @returns Whether the rel value is considered secure */ function isSafeRel(value) { if (typeof value !== "string") return false; return value === "noreferrer" || /\bnoreferrer\b/u.test(value); } var no_unsafe_target_blank_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `target=\"_blank\"` without `rel=\"noreferrer noopener\"`." }, fixable: "code", hasSuggestions: true, messages: { addRelNoreferrerNoopener: `Add 'rel="noreferrer noopener"' to the link to prevent security risks.`, noUnsafeTargetBlank: `Using 'target="_blank"' on an external link without 'rel="noreferrer noopener"' is a security risk.` }, schema: [] }, name: RULE_NAME$3, create: create$3, defaultOptions: [] }); function create$3(context) { const resolver = createJsxElementResolver(context); return { JSXElement(node) { const { domElementType } = resolver.resolve(node); if (domElementType !== "a") return; const findAttribute = getJsxAttribute(context, node); const targetProp = findAttribute("target"); if (targetProp == null) return; if (resolveJsxAttributeValue(context, targetProp).toStatic("target") !== "_blank") return; const hrefProp = findAttribute("href"); if (hrefProp == null) return; if (!isExternalLinkLike(resolveJsxAttributeValue(context, hrefProp).toStatic("href"))) return; const relProp = findAttribute("rel"); if (relProp == null) { context.report({ messageId: "noUnsafeTargetBlank", node: node.openingElement, suggest: [{ messageId: "addRelNoreferrerNoopener", fix(fixer) { return fixer.insertTextAfter(node.openingElement.name, ` rel="noreferrer noopener"`); } }] }); return; } if (isSafeRel(resolveJsxAttributeValue(context, relProp).toStatic("rel"))) return; context.report({ messageId: "noUnsafeTargetBlank", node: relProp, suggest: [{ messageId: "addRelNoreferrerNoopener", fix(fixer) { return fixer.replaceText(relProp, `rel="noreferrer noopener"`); } }] }); } }; } //#endregion //#region src/rules/no-use-form-state.ts const RULE_NAME$2 = "no-use-form-state"; var no_use_form_state_default = createRule({ meta: { type: "problem", docs: { description: "Replaces usages of `useFormState` with `useActionState`." }, fixable: "code", messages: { noUseFormState: "[Deprecated] Use 'useActionState' from 'react' package instead." }, schema: [] }, name: RULE_NAME$2, create: create$2, defaultOptions: [] }); function create$2(context) { if (!context.sourceCode.text.includes("useFormState")) return {}; if (compare(getSettingsFromContext(context).version, "19.0.0", "<")) return {}; const reactDomNames = /* @__PURE__ */ new Set(); const useFormStateNames = /* @__PURE__ */ new Set(); return { CallExpression(node) { switch (true) { case node.callee.type === AST_NODE_TYPES.Identifier && useFormStateNames.has(node.callee.name): context.report({ messageId: "noUseFormState", node, fix: getFix(context, node) }); return; case node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "useFormState" && reactDomNames.has(node.callee.object.name): context.report({ messageId: "noUseFormState", node, fix: getFix(context, node) }); return; } }, ImportDeclaration(node) { const [baseSource] = node.source.value.split("/"); if (baseSource !== "react-dom") return; for (const specifier of node.specifiers) switch (specifier.type) { case AST_NODE_TYPES.ImportSpecifier: if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue; if (specifier.imported.name === "useFormState") useFormStateNames.add(specifier.local.name); continue; case AST_NODE_TYPES.ImportDefaultSpecifier: case AST_NODE_TYPES.ImportNamespaceSpecifier: reactDomNames.add(specifier.local.name); continue; } } }; } function getFix(context, node) { const { importSource } = getSettingsFromContext(context); return (fixer) => { return [fixer.insertTextBefore(context.sourceCode.ast, `import { useActionState } from "${importSource}";\n`), fixer.replaceText(node.callee, "useActionState")]; }; } //#endregion //#region src/rules/no-void-elements-with-children.ts const RULE_NAME$1 = "no-void-elements-with-children"; const voidElements = new Set([ "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr" ]); var no_void_elements_with_children_default = createRule({ meta: { type: "problem", docs: { description: "Disallow `children` in void DOM elements." }, messages: { noVoidElementsWithChildren: "'{{elementType}}' is a void element tag and must not have children." }, schema: [] }, name: RULE_NAME$1, create: create$1, defaultOptions: [] }); function create$1(context) { const resolver = createJsxElementResolver(context); return { JSXElement(node) { const { domElementType } = resolver.resolve(node); if (!voidElements.has(domElementType)) return; const findJsxAttribute = getJsxAttribute(context, node); const hasChildrenProp = findJsxAttribute("children") != null; const hasDangerouslySetInnerHTML = findJsxAttribute("dangerouslySetInnerHTML") != null; if (node.children.length > 0 || hasChildrenProp || hasDangerouslySetInnerHTML) context.report({ messageId: "noVoidElementsWithChildren", n