Skip to content

Commit 15b2612

Browse files
authored
refactor: add 'createReport' helper (#1002)
1 parent 8a6e060 commit 15b2612

File tree

11 files changed

+55
-46
lines changed

11 files changed

+55
-46
lines changed

apps/website/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@local/configs": "workspace:*",
3636
"@mdx-js/mdx": "^3.1.0",
3737
"@next/eslint-plugin-next": "^15.2.3",
38-
"@tailwindcss/postcss": "^4.0.14",
38+
"@tailwindcss/postcss": "^4.0.15",
3939
"@tsconfig/next": "^2.0.3",
4040
"@tsconfig/node22": "^22.0.0",
4141
"@tsconfig/strictest": "^2.0.5",
@@ -58,7 +58,7 @@
5858
"eslint-plugin-simple-import-sort": "^12.1.1",
5959
"eslint-plugin-unicorn": "^57.0.0",
6060
"postcss": "^8.5.3",
61-
"tailwindcss": "^4.0.14",
61+
"tailwindcss": "^4.0.15",
6262
"tailwindcss-animated": "^2.0.0",
6363
"typescript": "^5.8.2",
6464
"typescript-eslint": "^8.27.0"

packages/plugins/eslint-plugin-react-dom/src/rules/no-unknown-property.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
/* eslint-disable @typescript-eslint/ban-ts-comment */
2-
// @ts-nocheck
31
/* eslint-disable */
42
// Ported from https://github.com/jsx-eslint/eslint-plugin-react/blob/master/lib/rules/no-unknown-property.js
53
// TODO: Port to TypeScript
6-
4+
// @ts-nocheck
75
import { getSettingsFromContext } from "@eslint-react/shared";
86
import { createRule } from "../utils";
9-
import { compare, compareVersions } from "compare-versions";
7+
import { compare } from "compare-versions";
8+
import { createReport } from "@eslint-react/shared";
109
import type { RuleContext, RuleFeature } from "@eslint-react/shared";
1110
import type { RuleListener } from "@typescript-eslint/utils/ts-eslint";
1211

@@ -1091,6 +1090,7 @@ export default createRule({
10911090
});
10921091

10931092
export function create(context: RuleContext<MessageID, unknown[]>): RuleListener {
1093+
const report = createReport(context);
10941094
function getIgnoreConfig() {
10951095
return context.options[0]?.ignore || DEFAULTS.ignore;
10961096
}
@@ -1117,8 +1117,9 @@ export function create(context: RuleContext<MessageID, unknown[]>): RuleListener
11171117

11181118
if (isValidDataAttribute(name)) {
11191119
if (getRequireDataLowercase() && hasUpperCaseCharacter(name)) {
1120-
report(context, messages.dataLowercaseRequired, "dataLowercaseRequired", {
1120+
report({
11211121
node,
1122+
messageId: "dataLowercaseRequired",
11221123
data: {
11231124
name: actualName,
11241125
lowerCaseName: actualName.toLowerCase(),
@@ -1146,8 +1147,9 @@ export function create(context: RuleContext<MessageID, unknown[]>): RuleListener
11461147
if (tagName && allowedTags) {
11471148
// Scenario 1A: Allowed attribute found where not supposed to, report it
11481149
if (allowedTags.indexOf(tagName) === -1) {
1149-
report(context, messages.invalidPropOnTag, "invalidPropOnTag", {
1150+
report({
11501151
node,
1152+
messageId: "invalidPropOnTag",
11511153
data: {
11521154
name: actualName,
11531155
allowedTags: allowedTags.join(", "),
@@ -1172,8 +1174,9 @@ export function create(context: RuleContext<MessageID, unknown[]>): RuleListener
11721174

11731175
if (hasStandardNameButIsNotUsed) {
11741176
// Scenario 2B: The name of the attribute is close to a standard one, report it with the standard name
1175-
report(context, messages.unknownPropWithStandardName, "unknownPropWithStandardName", {
1177+
report({
11761178
node,
1179+
messageId: "unknownPropWithStandardName",
11771180
data: {
11781181
name: actualName,
11791182
standardName,
@@ -1186,8 +1189,9 @@ export function create(context: RuleContext<MessageID, unknown[]>): RuleListener
11861189
}
11871190

11881191
// Scenario 3: We have an attribute that is unknown, report it
1189-
report(context, messages.unknownProp, "unknownProp", {
1192+
report({
11901193
node,
1194+
messageId: "unknownProp",
11911195
data: {
11921196
name: actualName,
11931197
},
@@ -1204,13 +1208,6 @@ function getText(context, node) {
12041208
return context.sourceCode.getText(node);
12051209
}
12061210

1207-
function report(context, message, messageId, data) {
1208-
context.report({
1209-
messageId,
1210-
...data,
1211-
});
1212-
}
1213-
12141211
function testReactVersion(context, comparator, version) {
12151212
const { version: localVersion } = getSettingsFromContext(context);
12161213
return compare(localVersion, version, comparator);

packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as AST from "@eslint-react/ast";
22
import { isCloneElementCall, isCreateElementCall, isInitializedFromReact } from "@eslint-react/core";
33
import { _ } from "@eslint-react/eff";
44
import type { RuleContext, RuleFeature } from "@eslint-react/shared";
5-
import { report, unsafeDecodeSettings } from "@eslint-react/shared";
5+
import { createReport, unsafeDecodeSettings } from "@eslint-react/shared";
66
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
77
import type { TSESTree } from "@typescript-eslint/utils";
88
import type { ReportDescriptor, RuleListener } from "@typescript-eslint/utils/ts-eslint";
@@ -127,6 +127,7 @@ export default createRule<[], MessageID>({
127127
});
128128

129129
export function create(context: RuleContext<MessageID, []>): RuleListener {
130+
const report = createReport(context);
130131
const indexParamNames: Array<string | _> = [];
131132

132133
function isArrayIndex(node: TSESTree.Node): node is TSESTree.Identifier {
@@ -217,7 +218,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
217218
continue;
218219
}
219220
getReportDescriptors(prop.value)
220-
.map(report(context));
221+
.forEach(report);
221222
}
222223
},
223224
"CallExpression:exit"() {
@@ -234,7 +235,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
234235
return;
235236
}
236237
getReportDescriptors(node.value.expression)
237-
.map(report(context));
238+
.forEach(report);
238239
},
239240
};
240241
}

packages/plugins/eslint-plugin-react-x/src/rules/no-leaked-conditional-rendering.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as AST from "@eslint-react/ast";
22
import { _, flow, identity } from "@eslint-react/eff";
33
import type { RuleContext, RuleFeature } from "@eslint-react/shared";
4-
import { getSettingsFromContext, report } from "@eslint-react/shared";
4+
import { createReport, getSettingsFromContext } from "@eslint-react/shared";
55
import * as VAR from "@eslint-react/var";
66
import { getConstrainedTypeAtLocation } from "@typescript-eslint/type-utils";
77
import type { TSESTree } from "@typescript-eslint/types";
@@ -260,7 +260,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
260260
})
261261
.otherwise(() => _);
262262
}
263-
const visitorFunction = flow(getReportDescriptor, report(context));
263+
const visitorFunction = flow(getReportDescriptor, createReport(context));
264264
return {
265265
"JSXExpressionContainer > ConditionalExpression": visitorFunction,
266266
"JSXExpressionContainer > LogicalExpression": visitorFunction,

packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as AST from "@eslint-react/ast";
22
import { isChildrenToArrayCall } from "@eslint-react/core";
33
import * as JSX from "@eslint-react/jsx";
4-
import { report, type RuleContext, type RuleFeature } from "@eslint-react/shared";
4+
import { createReport, type RuleContext, type RuleFeature } from "@eslint-react/shared";
55
import type { TSESTree } from "@typescript-eslint/types";
66
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
77
import type { ReportDescriptor, RuleListener } from "@typescript-eslint/utils/ts-eslint";
@@ -35,6 +35,7 @@ export default createRule<[], MessageID>({
3535
});
3636

3737
export function create(context: RuleContext<MessageID, []>): RuleListener {
38+
const report = createReport(context);
3839
const state = { isWithinChildrenToArray: false };
3940

4041
function checkIteratorElement(node: TSESTree.Node): null | ReportDescriptor<MessageID> {
@@ -102,7 +103,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
102103
const initialScope = context.sourceCode.getScope(node);
103104
for (const element of elements) {
104105
if (!JSX.hasAttribute("key", element.openingElement.attributes, initialScope)) {
105-
report(context)({
106+
report({
106107
messageId: "missingKey",
107108
node: element,
108109
});
@@ -123,12 +124,10 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
123124
return;
124125
}
125126
if (fn.body.type === T.BlockStatement) {
126-
for (const descriptor of checkBlockStatement(fn.body)) {
127-
report(context)(descriptor);
128-
}
127+
checkBlockStatement(fn.body).forEach(report);
129128
return;
130129
}
131-
report(context)(checkExpression(fn.body));
130+
report(checkExpression(fn.body));
132131
},
133132
"CallExpression:exit"(node) {
134133
if (!isChildrenToArrayCall(context, node)) {
@@ -141,7 +140,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
141140
return;
142141
}
143142
if (node.parent.type === T.ArrayExpression) {
144-
report(context)({
143+
report({
145144
messageId: "unexpectedFragmentSyntax",
146145
node,
147146
});

packages/plugins/eslint-plugin-react-x/src/rules/no-useless-fragment.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function trimLikeReact(text: string) {
3636
return text.slice(start, end);
3737
}
3838

39-
function checkAndReport(
39+
function doCheck(
4040
context: RuleContext,
4141
node: TSESTree.JSXElement | TSESTree.JSXFragment,
4242
allowExpressions: boolean,
@@ -194,10 +194,10 @@ export function create(context: RuleContext<MessageID, Options>, [option]: Optio
194194
return {
195195
JSXElement(node) {
196196
if (!JSX.isFragmentElement(node)) return;
197-
checkAndReport(context, node, allowExpressions);
197+
doCheck(context, node, allowExpressions);
198198
},
199199
JSXFragment(node) {
200-
checkAndReport(context, node, allowExpressions);
200+
doCheck(context, node, allowExpressions);
201201
},
202202
};
203203
}

packages/shared/docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343

4444
## Functions
4545

46+
- [createReport](functions/createReport.md)
4647
- [getId](functions/getId.md)
4748
- [getReactVersion](functions/getReactVersion.md)
4849
- [getSettingsFromContext](functions/getSettingsFromContext.md)
4950
- [isInEditorEnv](functions/isInEditorEnv.md)
5051
- [isInGitHooksOrLintStaged](functions/isInGitHooksOrLintStaged.md)
51-
- [report](functions/report.md)

packages/shared/docs/functions/report.md renamed to packages/shared/docs/functions/createReport.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
***
44

5-
[@eslint-react/shared](../README.md) / report
5+
[@eslint-react/shared](../README.md) / createReport
66

7-
# Function: report()
7+
# Function: createReport()
88

9-
> **report**\<`MessageID`\>(`context`): (`descriptor`) => `void`
9+
> **createReport**\<`MessageID`\>(`context`): (`descriptor`) => `void`
10+
11+
Creates a report function that can conditionally report a descriptor.
1012

1113
## Type Parameters
1214

@@ -20,10 +22,14 @@
2022

2123
[`RuleContext`](../type-aliases/RuleContext.md)
2224

25+
The context of the rule
26+
2327
## Returns
2428

2529
`Function`
2630

31+
A function that takes a descriptor and reports it if it's not null or undefined
32+
2733
### Parameters
2834

2935
#### descriptor
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { _ } from "@eslint-react/eff";
2+
import type { ReportDescriptor } from "@typescript-eslint/utils/ts-eslint";
3+
4+
import type { RuleContext } from "./types";
5+
6+
/**
7+
* Creates a report function that can conditionally report a descriptor.
8+
* @param context - The context of the rule
9+
* @returns A function that takes a descriptor and reports it if it's not null or undefined
10+
*/
11+
export function createReport<MessageID extends string>(context: RuleContext) {
12+
return (descriptor: _ | null | ReportDescriptor<MessageID>) => {
13+
if (descriptor != null) context.report(descriptor);
14+
};
15+
}

packages/shared/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
export * from "./constants";
2+
export * from "./create-report";
23
export * from "./create-rule";
34
export * from "./env";
45
export * from "./get-id";
56
export * from "./get-react-version";
6-
export * from "./report";
77
export * from "./schemas";
88
export * from "./settings";
99
export type * from "./types";

0 commit comments

Comments
 (0)