eslint-plugin-react-rsc 5.3.3-next.0 → 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 +78 -7
- package/package.json +10 -10
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
|
|
@@ -102,24 +109,83 @@ function create(context) {
|
|
|
102
109
|
/**
|
|
103
110
|
* Find function declarations from exports and check them
|
|
104
111
|
* @param id The identifier of the exported function
|
|
105
|
-
* @param node The export declaration node
|
|
106
112
|
*/
|
|
107
|
-
function findAndCheckExportedFunctionDeclarations(id
|
|
113
|
+
function findAndCheckExportedFunctionDeclarations(id) {
|
|
108
114
|
const initNode = resolve(context, id);
|
|
109
115
|
if (initNode == null) return;
|
|
110
116
|
const unwrapped = Extract.unwrap(initNode);
|
|
111
117
|
if (!Check.isFunction(unwrapped)) return;
|
|
112
118
|
reportNonAsyncFunction(unwrapped, "file");
|
|
113
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
|
+
}
|
|
114
179
|
return merge({
|
|
115
180
|
ArrowFunctionExpression(node) {
|
|
181
|
+
checkFunctionDirectives(node);
|
|
116
182
|
checkLocalServerFunction(node);
|
|
117
183
|
},
|
|
118
184
|
ExportDefaultDeclaration(node) {
|
|
119
185
|
if (!hasFileLevelUseServerDirective) return;
|
|
120
186
|
const decl = node.declaration;
|
|
121
187
|
if (reportNonAsyncFunction(decl, "file")) return;
|
|
122
|
-
if (decl.type === AST_NODE_TYPES.Identifier) findAndCheckExportedFunctionDeclarations(decl
|
|
188
|
+
if (decl.type === AST_NODE_TYPES.Identifier) findAndCheckExportedFunctionDeclarations(decl);
|
|
123
189
|
},
|
|
124
190
|
ExportNamedDeclaration(node) {
|
|
125
191
|
if (!hasFileLevelUseServerDirective) return;
|
|
@@ -129,13 +195,18 @@ function create(context) {
|
|
|
129
195
|
if (decl.type === AST_NODE_TYPES.VariableDeclaration) for (const declarator of decl.declarations) reportNonAsyncFunction(declarator.init, "file");
|
|
130
196
|
return;
|
|
131
197
|
}
|
|
132
|
-
if (node.source == null && node.specifiers.length > 0) for (const spec of node.specifiers) findAndCheckExportedFunctionDeclarations(spec.local
|
|
198
|
+
if (node.source == null && node.specifiers.length > 0) for (const spec of node.specifiers) findAndCheckExportedFunctionDeclarations(spec.local);
|
|
133
199
|
},
|
|
134
200
|
FunctionDeclaration(node) {
|
|
201
|
+
checkFunctionDirectives(node);
|
|
135
202
|
checkLocalServerFunction(node);
|
|
136
203
|
},
|
|
137
204
|
FunctionExpression(node) {
|
|
205
|
+
checkFunctionDirectives(node);
|
|
138
206
|
checkLocalServerFunction(node);
|
|
207
|
+
},
|
|
208
|
+
Program() {
|
|
209
|
+
checkFileLevelDirectives();
|
|
139
210
|
}
|
|
140
211
|
});
|
|
141
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",
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"./package.json"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
41
|
-
"@typescript-eslint/type-utils": "^8.
|
|
42
|
-
"@typescript-eslint/types": "^8.
|
|
43
|
-
"@typescript-eslint/utils": "^8.
|
|
40
|
+
"@typescript-eslint/scope-manager": "^8.59.0",
|
|
41
|
+
"@typescript-eslint/type-utils": "^8.59.0",
|
|
42
|
+
"@typescript-eslint/types": "^8.59.0",
|
|
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",
|