eslint-plugin-react-rsc 5.3.3-next.2 → 5.3.4-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +75 -3
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ const rules$4 = { "react-rsc/function-definition": "off" };
|
|
|
34
34
|
//#endregion
|
|
35
35
|
//#region package.json
|
|
36
36
|
var name$4 = "eslint-plugin-react-rsc";
|
|
37
|
-
var version = "5.3.
|
|
37
|
+
var version = "5.3.4-beta.0";
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/utils/create-rule.ts
|
|
@@ -53,7 +53,12 @@ var function_definition_default = createRule({
|
|
|
53
53
|
fixable: "code",
|
|
54
54
|
messages: {
|
|
55
55
|
file: "Functions exported from files with `use server` directive are React Server Functions and therefore must be async.",
|
|
56
|
-
|
|
56
|
+
fileDirectivePosition: "The '{{name}}' directive must be at the very beginning of the file, before any imports or other code.",
|
|
57
|
+
fileDirectiveQuote: "The '{{name}}' directive must be written with single or double quotes, not backticks.",
|
|
58
|
+
local: "Functions with `use server` directive are React Server Functions and therefore must be async.",
|
|
59
|
+
localDirectivePosition: "The '{{name}}' directive must be at the very beginning of the function body.",
|
|
60
|
+
localDirectiveQuote: "The '{{name}}' directive must be written with single or double quotes, not backticks.",
|
|
61
|
+
localDirectiveUnexpected: "The '{{name}}' directive can only be used at the top of a file, not inside a function body."
|
|
57
62
|
},
|
|
58
63
|
schema: []
|
|
59
64
|
},
|
|
@@ -62,7 +67,9 @@ var function_definition_default = createRule({
|
|
|
62
67
|
defaultOptions: []
|
|
63
68
|
});
|
|
64
69
|
function create(context) {
|
|
65
|
-
|
|
70
|
+
const hasUseServer = context.sourceCode.text.includes("use server");
|
|
71
|
+
const hasUseClient = context.sourceCode.text.includes("use client");
|
|
72
|
+
if (!hasUseServer && !hasUseClient) return {};
|
|
66
73
|
const hasFileLevelUseServerDirective = context.sourceCode.ast.body.some(Check.isDirective("use server"));
|
|
67
74
|
/**
|
|
68
75
|
* Check if `node` is an async function, and report if not
|
|
@@ -110,8 +117,68 @@ function create(context) {
|
|
|
110
117
|
if (!Check.isFunction(unwrapped)) return;
|
|
111
118
|
reportNonAsyncFunction(unwrapped, "file");
|
|
112
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Check file-level directives for correct position and quote style.
|
|
122
|
+
* Well-formed directives at the beginning of the file will have a `directive` property.
|
|
123
|
+
* If they appear after other code, the parser will not set `directive`.
|
|
124
|
+
*/
|
|
125
|
+
function checkFileLevelDirectives() {
|
|
126
|
+
for (const node of context.sourceCode.ast.body) {
|
|
127
|
+
if (node.type !== AST_NODE_TYPES.ExpressionStatement) continue;
|
|
128
|
+
if (Check.isLiteral("string")(node.expression)) {
|
|
129
|
+
const value = node.expression.value;
|
|
130
|
+
if ((value === "use server" || value === "use client") && node.directive == null) context.report({
|
|
131
|
+
data: { name: value },
|
|
132
|
+
messageId: "fileDirectivePosition",
|
|
133
|
+
node
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (node.expression.type === AST_NODE_TYPES.TemplateLiteral && node.expression.quasis.length === 1 && node.expression.expressions.length === 0) {
|
|
138
|
+
const value = node.expression.quasis[0]?.value.cooked;
|
|
139
|
+
if (value === "use server" || value === "use client") context.report({
|
|
140
|
+
data: { name: value },
|
|
141
|
+
messageId: "fileDirectiveQuote",
|
|
142
|
+
node
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check function-level directives for correct position and quote style.
|
|
149
|
+
* @param node The function node to check
|
|
150
|
+
*/
|
|
151
|
+
function checkFunctionDirectives(node) {
|
|
152
|
+
if (node.body.type !== AST_NODE_TYPES.BlockStatement) return;
|
|
153
|
+
for (const stmt of node.body.body) {
|
|
154
|
+
if (stmt.type !== AST_NODE_TYPES.ExpressionStatement) continue;
|
|
155
|
+
if (Check.isLiteral("string")(stmt.expression)) {
|
|
156
|
+
const value = stmt.expression.value;
|
|
157
|
+
if (value === "use server" && stmt.directive == null) context.report({
|
|
158
|
+
data: { name: value },
|
|
159
|
+
messageId: "localDirectivePosition",
|
|
160
|
+
node: stmt
|
|
161
|
+
});
|
|
162
|
+
if (value === "use client") context.report({
|
|
163
|
+
data: { name: value },
|
|
164
|
+
messageId: "localDirectiveUnexpected",
|
|
165
|
+
node: stmt
|
|
166
|
+
});
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (stmt.expression.type === AST_NODE_TYPES.TemplateLiteral && stmt.expression.quasis.length === 1 && stmt.expression.expressions.length === 0) {
|
|
170
|
+
const value = stmt.expression.quasis[0]?.value.cooked;
|
|
171
|
+
if (value === "use server" || value === "use client") context.report({
|
|
172
|
+
data: { name: value },
|
|
173
|
+
messageId: "localDirectiveQuote",
|
|
174
|
+
node: stmt
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
113
179
|
return merge({
|
|
114
180
|
ArrowFunctionExpression(node) {
|
|
181
|
+
checkFunctionDirectives(node);
|
|
115
182
|
checkLocalServerFunction(node);
|
|
116
183
|
},
|
|
117
184
|
ExportDefaultDeclaration(node) {
|
|
@@ -131,10 +198,15 @@ function create(context) {
|
|
|
131
198
|
if (node.source == null && node.specifiers.length > 0) for (const spec of node.specifiers) findAndCheckExportedFunctionDeclarations(spec.local);
|
|
132
199
|
},
|
|
133
200
|
FunctionDeclaration(node) {
|
|
201
|
+
checkFunctionDirectives(node);
|
|
134
202
|
checkLocalServerFunction(node);
|
|
135
203
|
},
|
|
136
204
|
FunctionExpression(node) {
|
|
205
|
+
checkFunctionDirectives(node);
|
|
137
206
|
checkLocalServerFunction(node);
|
|
207
|
+
},
|
|
208
|
+
Program() {
|
|
209
|
+
checkFileLevelDirectives();
|
|
138
210
|
}
|
|
139
211
|
});
|
|
140
212
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-rsc",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.4-beta.0",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for RSC related rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"@typescript-eslint/types": "^8.59.0",
|
|
43
43
|
"@typescript-eslint/utils": "^8.59.0",
|
|
44
44
|
"ts-pattern": "^5.9.0",
|
|
45
|
-
"@eslint-react/ast": "5.3.
|
|
46
|
-
"@eslint-react/core": "5.3.
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
45
|
+
"@eslint-react/ast": "5.3.4-beta.0",
|
|
46
|
+
"@eslint-react/core": "5.3.4-beta.0",
|
|
47
|
+
"@eslint-react/var": "5.3.4-beta.0",
|
|
48
|
+
"@eslint-react/eslint": "5.3.4-beta.0",
|
|
49
|
+
"@eslint-react/shared": "5.3.4-beta.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "^19.2.14",
|