From 9a2a29a3bac9db876556eea17e330afe89e5c0e9 Mon Sep 17 00:00:00 2001 From: Rel1cx Date: Wed, 26 Feb 2025 12:35:23 +0800 Subject: [PATCH] refactor: rename 'strictImportCheck' to 'skipImportCheck' and update related documentation --- apps/website/content/docs/configurations.mdx | 10 +++---- apps/website/content/docs/configurations.tsx | 6 ++-- packages/core/src/hook/is.ts | 29 +++++++++---------- packages/core/src/utils/is-from-react.ts | 8 ++--- .../src/rules/is-from-react.spec.ts | 21 -------------- .../src/rules/use-state.spec.ts | 4 +-- .../src/rules/no-children-count.spec.ts | 2 +- .../src/rules/no-children-for-each.spec.ts | 2 +- .../src/rules/no-children-map.spec.ts | 2 +- .../src/rules/no-children-only.spec.ts | 2 +- .../src/rules/no-children-to-array.spec.ts | 2 +- .../shared/docs/functions/defineSettings.md | 10 +++---- .../DEFAULT_ESLINT_REACT_SETTINGS.md | 8 ++--- packages/shared/src/schemas.ts | 6 ++-- packages/shared/src/settings.ts | 2 +- 15 files changed, 45 insertions(+), 69 deletions(-) diff --git a/apps/website/content/docs/configurations.mdx b/apps/website/content/docs/configurations.mdx index bce31e1854..32de2deb8d 100644 --- a/apps/website/content/docs/configurations.mdx +++ b/apps/website/content/docs/configurations.mdx @@ -45,16 +45,16 @@ For example, if you are using `@pika/react` instead of `react`, you can set the import React from "@pika/react"; ``` -### `strictImportCheck` +### `skipImportCheck` -Check both the shape and the import to determine if an API is from React before applying the rules. +When determining whether an API originates from React, bypass the import source check. -This can prevent false positives when using a irrelevant third-party library that has similar APIs to React. +By default, the rule checks only the shape of the API to determine if it is a React API. If `skipImportCheck` is set to `false`, the rule will check both the shape and the import source. -For example, if you set the `strictImportCheck` to `true`, then the `memo` function from `irrelevant-library` will not be recognized as React's `memo`: +For example, when `skipImportCheck` is set to false, the `memo` function from `unrelated-library` will not be recognized as React's `memo`. ```ts -import { memo } from "irrelevant-library"; +import { memo } from "unrelated-library"; const NonComponentFunction = memo(() => { // ^^^^ diff --git a/apps/website/content/docs/configurations.tsx b/apps/website/content/docs/configurations.tsx index f908c7d1b0..1f0352ddb9 100644 --- a/apps/website/content/docs/configurations.tsx +++ b/apps/website/content/docs/configurations.tsx @@ -18,14 +18,14 @@ export function SettingsTypeTable() { description: The source where React is imported from ⤵, default: "react", }, - strictImportCheck: { + skipImportCheck: { type: "boolean", description: ( - + Check both the shape and the import to determine if an API is from React before applying the rules. ⤵ ), - default: "false", + default: "true", }, polymorphicPropName: { type: "string", diff --git a/packages/core/src/hook/is.ts b/packages/core/src/hook/is.ts index 7185f1b68b..b13bae6f96 100644 --- a/packages/core/src/hook/is.ts +++ b/packages/core/src/hook/is.ts @@ -5,6 +5,7 @@ import { unsafeDecodeSettings } from "@eslint-react/shared"; import type { TSESTree } from "@typescript-eslint/types"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; +import { DEFAULT_ESLINT_REACT_SETTINGS } from "../../../shared/src/schemas"; import { isInitializedFromReact } from "../utils"; import { isReactHookName } from "./hook-name"; @@ -35,23 +36,21 @@ export function isReactHookCall(node: TSESTree.Node | _) { export function isReactHookCallWithName(context: RuleContext, node: TSESTree.CallExpression | _) { if (node == null) return constFalse; - const settings = unsafeDecodeSettings(context.settings); - const importSource = settings.importSource ?? "react"; + const { + importSource = DEFAULT_ESLINT_REACT_SETTINGS.importSource, + skipImportCheck = true, + } = unsafeDecodeSettings(context.settings); const initialScope = context.sourceCode.getScope(node); return (name: string) => { switch (true) { case node.callee.type === T.Identifier && node.callee.name === name: - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - return !settings.strictImportCheck - || isInitializedFromReact(name, importSource, initialScope); + return skipImportCheck || isInitializedFromReact(name, importSource, initialScope); case node.callee.type === T.MemberExpression && node.callee.property.type === T.Identifier && node.callee.property.name === name && "name" in node.callee.object: - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - return !settings.strictImportCheck - || isInitializedFromReact(node.callee.object.name, importSource, initialScope); + return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope); default: return false; } @@ -73,23 +72,21 @@ export function isReactHookCallWithNameLoose(node: TSESTree.CallExpression | _) } export function isReactHookCallWithNameAlias(context: RuleContext, name: string, alias: string[]) { - const settings = unsafeDecodeSettings(context); - const importSource = settings.importSource ?? "react"; + const { + importSource = DEFAULT_ESLINT_REACT_SETTINGS.importSource, + skipImportCheck = true, + } = unsafeDecodeSettings(context.settings); return (node: TSESTree.CallExpression) => { const initialScope = context.sourceCode.getScope(node); switch (true) { case node.callee.type === T.Identifier && node.callee.name === name: - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - return !settings.strictImportCheck - || isInitializedFromReact(name, importSource, initialScope); + return skipImportCheck || isInitializedFromReact(name, importSource, initialScope); case node.callee.type === T.MemberExpression && node.callee.property.type === T.Identifier && node.callee.property.name === name && "name" in node.callee.object: - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - return !settings.strictImportCheck - || isInitializedFromReact(node.callee.object.name, importSource, initialScope); + return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope); default: return alias.some(isReactHookCallWithNameLoose(node)); } diff --git a/packages/core/src/utils/is-from-react.ts b/packages/core/src/utils/is-from-react.ts index 4671a31ec0..92050a9f5d 100644 --- a/packages/core/src/utils/is-from-react.ts +++ b/packages/core/src/utils/is-from-react.ts @@ -39,8 +39,8 @@ export function isFromReactStrict( export function isFromReact(name: string) { return (context: RuleContext, node: TSESTree.Identifier | TSESTree.MemberExpression) => { - const { importSource = defaultImportSource, strictImportCheck = false } = unsafeDecodeSettings(context.settings); - if (!strictImportCheck) return isFromReactLoose(node, name); + const { importSource = defaultImportSource, skipImportCheck = true } = unsafeDecodeSettings(context.settings); + if (skipImportCheck) return isFromReactLoose(node, name); return isFromReactStrict(node, name, importSource, context.sourceCode.getScope(node)); }; } @@ -88,8 +88,8 @@ export function isFromReactMemberStrict( export function isFromReactMember(memberName: string, name: string) { return (context: RuleContext, node: TSESTree.MemberExpression) => { - const { importSource = defaultImportSource, strictImportCheck = false } = unsafeDecodeSettings(context.settings); - if (!strictImportCheck) return isFromReactMemberLoose(node, memberName, name); + const { importSource = defaultImportSource, skipImportCheck = true } = unsafeDecodeSettings(context.settings); + if (skipImportCheck) return isFromReactMemberLoose(node, memberName, name); return isFromReactMemberStrict(node, memberName, name, importSource, context.sourceCode.getScope(node)); }; } diff --git a/packages/plugins/eslint-plugin-react-debug/src/rules/is-from-react.spec.ts b/packages/plugins/eslint-plugin-react-debug/src/rules/is-from-react.spec.ts index f26c7b2e7c..04e12b9206 100644 --- a/packages/plugins/eslint-plugin-react-debug/src/rules/is-from-react.spec.ts +++ b/packages/plugins/eslint-plugin-react-debug/src/rules/is-from-react.spec.ts @@ -27,7 +27,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -45,7 +44,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -66,7 +64,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -85,7 +82,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -107,7 +103,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -132,7 +127,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -154,7 +148,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -171,7 +164,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -189,7 +181,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -210,7 +201,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -229,7 +219,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -251,7 +240,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -282,7 +270,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "@pika/react", - strictImportCheck: true, }, }, }, @@ -302,7 +289,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -322,7 +308,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -336,7 +321,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -348,7 +332,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -360,7 +343,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -372,7 +354,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -386,7 +367,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, @@ -402,7 +382,6 @@ ruleTester.run(RULE_NAME, rule, { settings: { "react-x": { importSource: "react", - strictImportCheck: true, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts index 255b894432..9aee29932e 100644 --- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts +++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts @@ -36,7 +36,7 @@ ruleTester.run(RULE_NAME, rule, { }], settings: { "react-x": { - strictImportCheck: false, + skipImportCheck: true, }, }, }, @@ -159,7 +159,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-count.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-count.spec.ts index 42709f4956..fca160161b 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-count.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-count.spec.ts @@ -96,7 +96,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-for-each.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-for-each.spec.ts index f0de11a71f..221ab6bfae 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-for-each.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-for-each.spec.ts @@ -92,7 +92,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-map.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-map.spec.ts index af855096be..00a0db46fa 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-map.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-map.spec.ts @@ -106,7 +106,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-only.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-only.spec.ts index dec444be99..dcbf2dd521 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-only.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-only.spec.ts @@ -71,7 +71,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-to-array.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-to-array.spec.ts index c12214a768..d53c6b3800 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-children-to-array.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-children-to-array.spec.ts @@ -103,7 +103,7 @@ ruleTester.run(RULE_NAME, rule, { `, settings: { "react-x": { - strictImportCheck: true, + skipImportCheck: false, }, }, }, diff --git a/packages/shared/docs/functions/defineSettings.md b/packages/shared/docs/functions/defineSettings.md index a8318812e5..a82ada7a1c 100644 --- a/packages/shared/docs/functions/defineSettings.md +++ b/packages/shared/docs/functions/defineSettings.md @@ -188,7 +188,7 @@ This is used to determine the type of the component. `"as"` ``` -#### strictImportCheck +#### skipImportCheck `boolean` = `...` @@ -200,7 +200,7 @@ This can prevent false positives when using a irrelevant third-party library tha **Default** -`false` +`true` #### version? @@ -397,9 +397,9 @@ This is used to determine the type of the component. `"as"` ``` -### strictImportCheck +### skipImportCheck -> **strictImportCheck**: `boolean` +> **skipImportCheck**: `boolean` Check both the shape and the import to determine if an API is from React. @@ -409,7 +409,7 @@ This can prevent false positives when using a irrelevant third-party library tha #### Default -`false` +`true` ### version? diff --git a/packages/shared/docs/variables/DEFAULT_ESLINT_REACT_SETTINGS.md b/packages/shared/docs/variables/DEFAULT_ESLINT_REACT_SETTINGS.md index 1eeff93597..c3494d0232 100644 --- a/packages/shared/docs/variables/DEFAULT_ESLINT_REACT_SETTINGS.md +++ b/packages/shared/docs/variables/DEFAULT_ESLINT_REACT_SETTINGS.md @@ -56,13 +56,13 @@ This is used to inform the ESLint React plugins how to treat these components du > `readonly` **polymorphicPropName**: `"as"` = `"as"` -### strict +### skipImportCheck -> `readonly` **strict**: `false` = `false` +> `readonly` **skipImportCheck**: `true` = `true` -### strictImportCheck +### strict -> `readonly` **strictImportCheck**: `false` = `false` +> `readonly` **strict**: `false` = `false` ### version diff --git a/packages/shared/src/schemas.ts b/packages/shared/src/schemas.ts index 20c8e68187..35784ad35d 100644 --- a/packages/shared/src/schemas.ts +++ b/packages/shared/src/schemas.ts @@ -122,9 +122,9 @@ export const ESLintReactSettingsSchema = object({ /** * Check both the shape and the import to determine if an API is from React. * @description This can prevent false positives when using a irrelevant third-party library that has similar APIs to React. - * @default `false` + * @default `true` */ - strictImportCheck: optional(boolean(), false), + skipImportCheck: optional(boolean(), true), /** * React version to use, "detect" means auto detect React version from the project’s dependencies. * If `importSource` is specified, an equivalent version of React should be provided here. @@ -177,8 +177,8 @@ export const DEFAULT_ESLINT_REACT_SETTINGS = { jsxPragma: "createElement", jsxPragmaFrag: "Fragment", polymorphicPropName: "as", + skipImportCheck: true, strict: false, - strictImportCheck: false, version: "detect", additionalHooks: { useEffect: ["useIsomorphicLayoutEffect"], diff --git a/packages/shared/src/settings.ts b/packages/shared/src/settings.ts index bc373f5346..7e14d60ae7 100644 --- a/packages/shared/src/settings.ts +++ b/packages/shared/src/settings.ts @@ -36,8 +36,8 @@ export interface ESLintReactSettingsNormalized { additionalHooks: CustomHooks; importSource: string; polymorphicPropName: string | _; + skipImportCheck: boolean; // strict: boolean; - strictImportCheck: boolean; version: string; }