diff --git a/apps/website/package.json b/apps/website/package.json index 0b73294bad..4eb97af8bd 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -35,7 +35,7 @@ "@local/configs": "workspace:*", "@mdx-js/mdx": "^3.1.0", "@next/eslint-plugin-next": "^15.2.3", - "@tailwindcss/postcss": "^4.0.14", + "@tailwindcss/postcss": "^4.0.15", "@tsconfig/next": "^2.0.3", "@tsconfig/node22": "^22.0.0", "@tsconfig/strictest": "^2.0.5", @@ -58,7 +58,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unicorn": "^57.0.0", "postcss": "^8.5.3", - "tailwindcss": "^4.0.14", + "tailwindcss": "^4.0.15", "tailwindcss-animated": "^2.0.0", "typescript": "^5.8.2", "typescript-eslint": "^8.27.0" diff --git a/packages/plugins/eslint-plugin-react-dom/src/rules/no-unknown-property.ts b/packages/plugins/eslint-plugin-react-dom/src/rules/no-unknown-property.ts index 610b039d92..9cd6ce26a3 100644 --- a/packages/plugins/eslint-plugin-react-dom/src/rules/no-unknown-property.ts +++ b/packages/plugins/eslint-plugin-react-dom/src/rules/no-unknown-property.ts @@ -1,12 +1,11 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -// @ts-nocheck /* eslint-disable */ // Ported from https://github.com/jsx-eslint/eslint-plugin-react/blob/master/lib/rules/no-unknown-property.js // TODO: Port to TypeScript - +// @ts-nocheck import { getSettingsFromContext } from "@eslint-react/shared"; import { createRule } from "../utils"; -import { compare, compareVersions } from "compare-versions"; +import { compare } from "compare-versions"; +import { createReport } from "@eslint-react/shared"; import type { RuleContext, RuleFeature } from "@eslint-react/shared"; import type { RuleListener } from "@typescript-eslint/utils/ts-eslint"; @@ -1091,6 +1090,7 @@ export default createRule({ }); export function create(context: RuleContext): RuleListener { + const report = createReport(context); function getIgnoreConfig() { return context.options[0]?.ignore || DEFAULTS.ignore; } @@ -1117,8 +1117,9 @@ export function create(context: RuleContext): RuleListener if (isValidDataAttribute(name)) { if (getRequireDataLowercase() && hasUpperCaseCharacter(name)) { - report(context, messages.dataLowercaseRequired, "dataLowercaseRequired", { + report({ node, + messageId: "dataLowercaseRequired", data: { name: actualName, lowerCaseName: actualName.toLowerCase(), @@ -1146,8 +1147,9 @@ export function create(context: RuleContext): RuleListener if (tagName && allowedTags) { // Scenario 1A: Allowed attribute found where not supposed to, report it if (allowedTags.indexOf(tagName) === -1) { - report(context, messages.invalidPropOnTag, "invalidPropOnTag", { + report({ node, + messageId: "invalidPropOnTag", data: { name: actualName, allowedTags: allowedTags.join(", "), @@ -1172,8 +1174,9 @@ export function create(context: RuleContext): RuleListener if (hasStandardNameButIsNotUsed) { // Scenario 2B: The name of the attribute is close to a standard one, report it with the standard name - report(context, messages.unknownPropWithStandardName, "unknownPropWithStandardName", { + report({ node, + messageId: "unknownPropWithStandardName", data: { name: actualName, standardName, @@ -1186,8 +1189,9 @@ export function create(context: RuleContext): RuleListener } // Scenario 3: We have an attribute that is unknown, report it - report(context, messages.unknownProp, "unknownProp", { + report({ node, + messageId: "unknownProp", data: { name: actualName, }, @@ -1204,13 +1208,6 @@ function getText(context, node) { return context.sourceCode.getText(node); } -function report(context, message, messageId, data) { - context.report({ - messageId, - ...data, - }); -} - function testReactVersion(context, comparator, version) { const { version: localVersion } = getSettingsFromContext(context); return compare(localVersion, version, comparator); diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts index a8787e5ec6..c4d5919c53 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts @@ -2,7 +2,7 @@ import * as AST from "@eslint-react/ast"; import { isCloneElementCall, isCreateElementCall, isInitializedFromReact } from "@eslint-react/core"; import { _ } from "@eslint-react/eff"; import type { RuleContext, RuleFeature } from "@eslint-react/shared"; -import { report, unsafeDecodeSettings } from "@eslint-react/shared"; +import { createReport, unsafeDecodeSettings } from "@eslint-react/shared"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; import type { TSESTree } from "@typescript-eslint/utils"; import type { ReportDescriptor, RuleListener } from "@typescript-eslint/utils/ts-eslint"; @@ -127,6 +127,7 @@ export default createRule<[], MessageID>({ }); export function create(context: RuleContext): RuleListener { + const report = createReport(context); const indexParamNames: Array = []; function isArrayIndex(node: TSESTree.Node): node is TSESTree.Identifier { @@ -217,7 +218,7 @@ export function create(context: RuleContext): RuleListener { continue; } getReportDescriptors(prop.value) - .map(report(context)); + .forEach(report); } }, "CallExpression:exit"() { @@ -234,7 +235,7 @@ export function create(context: RuleContext): RuleListener { return; } getReportDescriptors(node.value.expression) - .map(report(context)); + .forEach(report); }, }; } diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-leaked-conditional-rendering.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-leaked-conditional-rendering.ts index e6248d124e..36182367f9 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-leaked-conditional-rendering.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-leaked-conditional-rendering.ts @@ -1,7 +1,7 @@ import * as AST from "@eslint-react/ast"; import { _, flow, identity } from "@eslint-react/eff"; import type { RuleContext, RuleFeature } from "@eslint-react/shared"; -import { getSettingsFromContext, report } from "@eslint-react/shared"; +import { createReport, getSettingsFromContext } from "@eslint-react/shared"; import * as VAR from "@eslint-react/var"; import { getConstrainedTypeAtLocation } from "@typescript-eslint/type-utils"; import type { TSESTree } from "@typescript-eslint/types"; @@ -260,7 +260,7 @@ export function create(context: RuleContext): RuleListener { }) .otherwise(() => _); } - const visitorFunction = flow(getReportDescriptor, report(context)); + const visitorFunction = flow(getReportDescriptor, createReport(context)); return { "JSXExpressionContainer > ConditionalExpression": visitorFunction, "JSXExpressionContainer > LogicalExpression": visitorFunction, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts index 6e42eb8e92..fbe95d96a4 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts @@ -1,7 +1,7 @@ import * as AST from "@eslint-react/ast"; import { isChildrenToArrayCall } from "@eslint-react/core"; import * as JSX from "@eslint-react/jsx"; -import { report, type RuleContext, type RuleFeature } from "@eslint-react/shared"; +import { createReport, type RuleContext, type RuleFeature } from "@eslint-react/shared"; import type { TSESTree } from "@typescript-eslint/types"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; import type { ReportDescriptor, RuleListener } from "@typescript-eslint/utils/ts-eslint"; @@ -35,6 +35,7 @@ export default createRule<[], MessageID>({ }); export function create(context: RuleContext): RuleListener { + const report = createReport(context); const state = { isWithinChildrenToArray: false }; function checkIteratorElement(node: TSESTree.Node): null | ReportDescriptor { @@ -102,7 +103,7 @@ export function create(context: RuleContext): RuleListener { const initialScope = context.sourceCode.getScope(node); for (const element of elements) { if (!JSX.hasAttribute("key", element.openingElement.attributes, initialScope)) { - report(context)({ + report({ messageId: "missingKey", node: element, }); @@ -123,12 +124,10 @@ export function create(context: RuleContext): RuleListener { return; } if (fn.body.type === T.BlockStatement) { - for (const descriptor of checkBlockStatement(fn.body)) { - report(context)(descriptor); - } + checkBlockStatement(fn.body).forEach(report); return; } - report(context)(checkExpression(fn.body)); + report(checkExpression(fn.body)); }, "CallExpression:exit"(node) { if (!isChildrenToArrayCall(context, node)) { @@ -141,7 +140,7 @@ export function create(context: RuleContext): RuleListener { return; } if (node.parent.type === T.ArrayExpression) { - report(context)({ + report({ messageId: "unexpectedFragmentSyntax", node, }); diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-useless-fragment.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-useless-fragment.ts index 7b2345be88..bd01d784b2 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-useless-fragment.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-useless-fragment.ts @@ -36,7 +36,7 @@ function trimLikeReact(text: string) { return text.slice(start, end); } -function checkAndReport( +function doCheck( context: RuleContext, node: TSESTree.JSXElement | TSESTree.JSXFragment, allowExpressions: boolean, @@ -194,10 +194,10 @@ export function create(context: RuleContext, [option]: Optio return { JSXElement(node) { if (!JSX.isFragmentElement(node)) return; - checkAndReport(context, node, allowExpressions); + doCheck(context, node, allowExpressions); }, JSXFragment(node) { - checkAndReport(context, node, allowExpressions); + doCheck(context, node, allowExpressions); }, }; } diff --git a/packages/shared/docs/README.md b/packages/shared/docs/README.md index 1467acc04f..da7fba8df0 100644 --- a/packages/shared/docs/README.md +++ b/packages/shared/docs/README.md @@ -43,9 +43,9 @@ ## Functions +- [createReport](functions/createReport.md) - [getId](functions/getId.md) - [getReactVersion](functions/getReactVersion.md) - [getSettingsFromContext](functions/getSettingsFromContext.md) - [isInEditorEnv](functions/isInEditorEnv.md) - [isInGitHooksOrLintStaged](functions/isInGitHooksOrLintStaged.md) -- [report](functions/report.md) diff --git a/packages/shared/docs/functions/report.md b/packages/shared/docs/functions/createReport.md similarity index 50% rename from packages/shared/docs/functions/report.md rename to packages/shared/docs/functions/createReport.md index d3dda2d1f6..d705b689bd 100644 --- a/packages/shared/docs/functions/report.md +++ b/packages/shared/docs/functions/createReport.md @@ -2,11 +2,13 @@ *** -[@eslint-react/shared](../README.md) / report +[@eslint-react/shared](../README.md) / createReport -# Function: report() +# Function: createReport() -> **report**\<`MessageID`\>(`context`): (`descriptor`) => `void` +> **createReport**\<`MessageID`\>(`context`): (`descriptor`) => `void` + +Creates a report function that can conditionally report a descriptor. ## Type Parameters @@ -20,10 +22,14 @@ [`RuleContext`](../type-aliases/RuleContext.md) +The context of the rule + ## Returns `Function` +A function that takes a descriptor and reports it if it's not null or undefined + ### Parameters #### descriptor diff --git a/packages/shared/src/create-report.ts b/packages/shared/src/create-report.ts new file mode 100644 index 0000000000..75d3f4f7ba --- /dev/null +++ b/packages/shared/src/create-report.ts @@ -0,0 +1,15 @@ +import type { _ } from "@eslint-react/eff"; +import type { ReportDescriptor } from "@typescript-eslint/utils/ts-eslint"; + +import type { RuleContext } from "./types"; + +/** + * Creates a report function that can conditionally report a descriptor. + * @param context - The context of the rule + * @returns A function that takes a descriptor and reports it if it's not null or undefined + */ +export function createReport(context: RuleContext) { + return (descriptor: _ | null | ReportDescriptor) => { + if (descriptor != null) context.report(descriptor); + }; +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 9716e2ff0b..59783927e9 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,9 +1,9 @@ export * from "./constants"; +export * from "./create-report"; export * from "./create-rule"; export * from "./env"; export * from "./get-id"; export * from "./get-react-version"; -export * from "./report"; export * from "./schemas"; export * from "./settings"; export type * from "./types"; diff --git a/packages/shared/src/report.ts b/packages/shared/src/report.ts deleted file mode 100644 index 6dfbce9271..0000000000 --- a/packages/shared/src/report.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ReportDescriptor } from "@typescript-eslint/utils/ts-eslint"; - -import type { RuleContext } from "./types"; - -export function report(context: RuleContext) { - return (descriptor: undefined | null | ReportDescriptor) => { - if (descriptor != null) context.report(descriptor); - }; -}