UNPKG

eslint-plugin-react-debug

Version:

ESLint React's ESLint plugin for debugging related rules.

290 lines (277 loc) • 8.84 kB
import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, getConfigAdapters, getSettingsFromContext, report } from "@eslint-react/shared"; import { ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, JsxEmit, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, isInitializedFromReact, isJsxFragmentElement, useComponentCollector, useComponentCollectorLegacy, useHookCollector } from "@eslint-react/core"; import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils"; import { flow } from "@eslint-react/eff"; import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from "@typescript-eslint/types"; import { P, match } from "ts-pattern"; //#region rolldown:runtime var __defProp = Object.defineProperty; var __export = (all, symbols) => { let target = {}; for (var name$2 in all) { __defProp(target, name$2, { get: all[name$2], enumerable: true }); } if (symbols) { __defProp(target, Symbol.toStringTag, { value: "Module" }); } return target; }; //#endregion //#region src/configs/all.ts var all_exports = /* @__PURE__ */ __export({ name: () => name$1, rules: () => rules, settings: () => settings }); const name$1 = "react-debug/all"; const rules = { "react-debug/class-component": "warn", "react-debug/function-component": "warn", "react-debug/hook": "warn", "react-debug/is-from-react": "warn", "react-debug/jsx": "warn" }; const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS }; //#endregion //#region package.json var name = "eslint-plugin-react-debug"; var version = "2.3.13"; //#endregion //#region src/utils/create-rule.ts function getDocsUrl(ruleName) { return `${WEBSITE_URL}/docs/rules/debug-${ruleName}`; } const createRule = ESLintUtils.RuleCreator(getDocsUrl); //#endregion //#region src/utils/stringify.ts function stringify(value) { return JSON.stringify(value, null, 2); } //#endregion //#region src/rules/class-component.ts const RULE_NAME$4 = "class-component"; const RULE_FEATURES$4 = ["DBG"]; var class_component_default = createRule({ meta: { type: "problem", docs: { description: "Reports all class components.", [Symbol.for("rule_features")]: RULE_FEATURES$4 }, messages: { classComponent: "{{json}}" }, schema: [] }, name: RULE_NAME$4, create: create$4, defaultOptions: [] }); function create$4(context) { const { ctx, listeners } = useComponentCollectorLegacy(); return { ...listeners, "Program:exit"(program) { for (const { name: name$2 = "anonymous", node: component } of ctx.getAllComponents(program)) context.report({ messageId: "classComponent", node: component, data: { json: stringify({ name: name$2 }) } }); } }; } //#endregion //#region src/rules/function-component.ts const RULE_NAME$3 = "function-component"; const RULE_FEATURES$3 = ["DBG"]; var function_component_default = createRule({ meta: { type: "problem", docs: { description: "Reports all function components.", [Symbol.for("rule_features")]: RULE_FEATURES$3 }, messages: { functionComponent: "{{json}}" }, schema: [] }, name: RULE_NAME$3, create: create$3, defaultOptions: [] }); function create$3(context) { const { ctx, listeners } = useComponentCollector(context, { collectDisplayName: true, collectHookCalls: true, hint: DEFAULT_COMPONENT_DETECTION_HINT }); return { ...listeners, "Program:exit"(program) { for (const { name: name$2 = "anonymous", node, displayName, flag, hookCalls } of ctx.getAllComponents(program)) context.report({ messageId: "functionComponent", node, data: { json: stringify({ name: name$2, displayName: displayName == null ? "none" : context.sourceCode.getText(displayName), forwardRef: (flag & ComponentFlag.ForwardRef) > 0n, hookCalls: hookCalls.length, memo: (flag & ComponentFlag.Memo) > 0n }) } }); } }; } //#endregion //#region src/rules/hook.ts const RULE_NAME$2 = "hook"; const RULE_FEATURES$2 = ["DBG"]; var hook_default = createRule({ meta: { type: "problem", docs: { description: "Reports all React Hooks.", [Symbol.for("rule_features")]: RULE_FEATURES$2 }, messages: { hook: "{{json}}" }, schema: [] }, name: RULE_NAME$2, create: create$2, defaultOptions: [] }); function create$2(context) { const { ctx, listeners } = useHookCollector(); return { ...listeners, "Program:exit"(program) { for (const { name: name$2, node, hookCalls } of ctx.getAllHooks(program)) context.report({ messageId: "hook", node, data: { json: stringify({ name: name$2, hookCalls: hookCalls.length }) } }); } }; } //#endregion //#region src/rules/is-from-react.ts const RULE_NAME$1 = "is-from-react"; const RULE_FEATURES$1 = ["DBG"]; var is_from_react_default = createRule({ meta: { type: "problem", docs: { description: "Reports all identifiers that are initialized from React.", [Symbol.for("rule_features")]: RULE_FEATURES$1 }, messages: { isFromReact: "{{json}}" }, schema: [] }, name: RULE_NAME$1, create: create$1, defaultOptions: [] }); function create$1(context) { const { importSource = "react" } = getSettingsFromContext(context); function visitorFunction(node) { if (node.parent.type === AST_NODE_TYPES.ImportSpecifier && node.parent.imported === node && node.parent.imported.name === node.parent.local.name) return; const name$2 = node.name; if (!isFromReact(node, importSource, context.sourceCode.getScope(node))) return; context.report({ messageId: "isFromReact", node, data: { json: stringify({ name: name$2, importSource }) } }); } return { Identifier: visitorFunction, JSXIdentifier: visitorFunction }; } /** * Check if an identifier node is initialized from React * @param node The identifier node to check * @param importSource The import source to check against * @param initialScope Initial scope to search for the identifier * @returns Whether the identifier node is initialized from React */ function isFromReact(node, importSource, initialScope) { const name$2 = node.name; switch (true) { case node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.property === node && node.parent.object.type === AST_NODE_TYPES.Identifier: return isInitializedFromReact(node.parent.object.name, importSource, initialScope); case node.parent.type === AST_NODE_TYPES.JSXMemberExpression && node.parent.property === node && node.parent.object.type === AST_NODE_TYPES.JSXIdentifier: return isInitializedFromReact(node.parent.object.name, importSource, initialScope); default: return isInitializedFromReact(name$2, importSource, initialScope); } } //#endregion //#region src/rules/jsx.ts const RULE_NAME = "jsx"; const RULE_FEATURES = ["DBG"]; var jsx_default = createRule({ meta: { type: "problem", docs: { description: "Reports all JSX elements and fragments.", [Symbol.for("rule_features")]: RULE_FEATURES }, messages: { jsx: "{{json}}" }, schema: [] }, name: RULE_NAME, create, defaultOptions: [] }); function create(context) { const jsxConfigFromContext = getJsxConfigFromContext(context); const jsxConfigFromAnnotation = getJsxConfigFromAnnotation(context); const jsxConfig = { ...jsxConfigFromContext, ...jsxConfigFromAnnotation }; function getReportDescriptor(context$1) { return (node) => ({ messageId: "jsx", node, data: { json: stringify({ kind: match(node).with({ type: AST_NODE_TYPES$1.JSXElement }, (n) => isJsxFragmentElement(context$1, n) ? "fragment" : "element").with({ type: AST_NODE_TYPES$1.JSXFragment }, () => "fragment").exhaustive(), type: getJsxElementType(context$1, node), jsx: match(jsxConfig.jsx).with(JsxEmit.None, () => "none").with(JsxEmit.ReactJSX, () => "react-jsx").with(JsxEmit.ReactJSXDev, () => "react-jsx-dev").with(JsxEmit.React, () => "react").with(JsxEmit.ReactNative, () => "react-native").with(JsxEmit.Preserve, () => "preserve").otherwise(() => "unknown"), jsxFactory: jsxConfig.jsxFactory, jsxFragmentFactory: jsxConfig.jsxFragmentFactory, jsxImportSource: jsxConfig.jsxImportSource, jsxRuntime: match(jsxConfig.jsx).with(P.union(JsxEmit.None, JsxEmit.ReactJSX, JsxEmit.ReactJSXDev), () => "automatic").otherwise(() => "classic") }) } }); } return { "JSXElement, JSXFragment": flow(getReportDescriptor(context), report(context)) }; } //#endregion //#region src/plugin.ts const plugin = { meta: { name, version }, rules: { ["class-component"]: class_component_default, ["function-component"]: function_component_default, ["hook"]: hook_default, ["is-from-react"]: is_from_react_default, ["jsx"]: jsx_default } }; //#endregion //#region src/index.ts const { toFlatConfig } = getConfigAdapters("react-debug", plugin); var src_default = { ...plugin, configs: { ["all"]: toFlatConfig(all_exports) } }; //#endregion export { src_default as default };