eslint-plugin-react-debug
Version:
ESLint React's ESLint plugin for debugging related rules.
290 lines (277 loc) • 8.84 kB
JavaScript
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 };