eslint-plugin-th-rules 1.15.5 → 1.15.6
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/rules/top-level-functions.js +46 -34
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.15.6](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.15.5...v1.15.6) (2024-12-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* enhance top-level functions rule to support async and export keywords ([cca9ceb](https://github.com/tomerh2001/eslint-plugin-th-rules/commit/cca9cebe77fa01820048a55c444e55bd297b883c))
|
|
7
|
+
|
|
1
8
|
## [1.15.5](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.15.4...v1.15.5) (2024-12-30)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
/* eslint-disable unicorn/prefer-module */
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* @type {Object}
|
|
5
|
-
* @property {string} type - The type of the rule, in this case, 'suggestion'.
|
|
6
|
-
* @property {Object} docs - Documentation related to the rule.
|
|
7
|
-
* @property {string} docs.description - A brief description of the rule.
|
|
8
|
-
* @property {string} docs.category - The category of the rule, 'Stylistic Issues'.
|
|
9
|
-
* @property {boolean} docs.recommended - Indicates if the rule is recommended.
|
|
10
|
-
* @property {string} docs.url - The URL to the documentation of the rule.
|
|
11
|
-
* @property {string} fixable - Indicates if the rule is fixable, 'code'.
|
|
12
|
-
* @property {Array} schema - The schema for the rule options.
|
|
13
|
-
*/
|
|
14
3
|
const meta = {
|
|
15
4
|
type: 'suggestion',
|
|
16
5
|
docs: {
|
|
@@ -29,10 +18,13 @@ const meta = {
|
|
|
29
18
|
* @param {string} funcName - The name of the new function.
|
|
30
19
|
* @param {ArrowFunctionExpression} arrowNode - The ArrowFunctionExpression node.
|
|
31
20
|
* @param {import('eslint').SourceCode} sourceCode - The ESLint SourceCode object.
|
|
32
|
-
* @param {boolean} isExport - Whether or not this function is exported.
|
|
21
|
+
* @param {boolean} isExport - Whether or not this function is exported (e.g., `export const foo = ...`).
|
|
33
22
|
* @returns {string} The replacement code.
|
|
34
23
|
*/
|
|
35
24
|
function buildArrowFunctionReplacement(functionName, arrowNode, sourceCode, isExport) {
|
|
25
|
+
const asyncKeyword = arrowNode.async ? 'async ' : '';
|
|
26
|
+
const exportKeyword = isExport ? 'export ' : '';
|
|
27
|
+
|
|
36
28
|
const parametersText = arrowNode.params.map(parameter => sourceCode.getText(parameter)).join(', ');
|
|
37
29
|
|
|
38
30
|
let bodyText;
|
|
@@ -43,8 +35,7 @@ function buildArrowFunctionReplacement(functionName, arrowNode, sourceCode, isEx
|
|
|
43
35
|
bodyText = `{ return ${expressionText}; }`;
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
|
|
47
|
-
return `${exportKeyword}function ${functionName}(${parametersText}) ${bodyText}`;
|
|
38
|
+
return `${exportKeyword}${asyncKeyword}function ${functionName}(${parametersText}) ${bodyText}`;
|
|
48
39
|
}
|
|
49
40
|
|
|
50
41
|
/**
|
|
@@ -57,36 +48,41 @@ function buildArrowFunctionReplacement(functionName, arrowNode, sourceCode, isEx
|
|
|
57
48
|
* @returns {string} The replacement code.
|
|
58
49
|
*/
|
|
59
50
|
function buildFunctionExpressionReplacement(functionName, functionExprNode, sourceCode, isExport) {
|
|
51
|
+
const asyncKeyword = functionExprNode.async ? 'async ' : '';
|
|
52
|
+
const exportKeyword = isExport ? 'export ' : '';
|
|
53
|
+
|
|
60
54
|
const parametersText = functionExprNode.params.map(parameter => sourceCode.getText(parameter)).join(', ');
|
|
61
55
|
const bodyText = sourceCode.getText(functionExprNode.body);
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
return `${exportKeyword}function ${functionName}(${parametersText}) ${bodyText}`;
|
|
57
|
+
return `${exportKeyword}${asyncKeyword}function ${functionName}(${parametersText}) ${bodyText}`;
|
|
65
58
|
}
|
|
66
59
|
|
|
67
60
|
/**
|
|
68
|
-
* Build a replacement for an anonymous top-level FunctionDeclaration.
|
|
61
|
+
* Build a replacement for an anonymous top-level FunctionDeclaration (including async).
|
|
69
62
|
*
|
|
70
63
|
* @param {import('eslint').SourceCode} sourceCode
|
|
71
64
|
* @param {import('estree').FunctionDeclaration} node
|
|
72
65
|
* @param {string} [funcName='defaultFunction']
|
|
66
|
+
* @param {boolean} [isExport=false]
|
|
73
67
|
*/
|
|
74
|
-
function buildAnonymousFunctionDeclarationReplacement(sourceCode, node, functionName = 'defaultFunction') {
|
|
68
|
+
function buildAnonymousFunctionDeclarationReplacement(sourceCode, node, functionName = 'defaultFunction', isExport = false) {
|
|
75
69
|
const originalText = sourceCode.getText(node);
|
|
70
|
+
const asyncKeyword = node.async ? 'async ' : '';
|
|
71
|
+
const exportKeyword = isExport ? 'export ' : '';
|
|
72
|
+
|
|
73
|
+
let replaced = originalText;
|
|
74
|
+
const asyncFunctionRegex = /^\s*async\s+function\s*\(/;
|
|
75
|
+
const functionRegex = /^\s*function\s*\(/;
|
|
76
|
+
|
|
77
|
+
replaced = asyncFunctionRegex.test(replaced) ? replaced.replace(asyncFunctionRegex, `async function ${functionName}(`) : replaced.replace(functionRegex, `function ${functionName}(`);
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return
|
|
79
|
+
if (isExport && !replaced.trimStart().startsWith('export')) {
|
|
80
|
+
replaced = `${exportKeyword}${replaced}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return replaced;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
/**
|
|
85
|
-
* ESLint rule to enforce naming conventions for top-level functions.
|
|
86
|
-
*
|
|
87
|
-
* @param {Object} context - The rule context provided by ESLint.
|
|
88
|
-
* @returns {Object} An object containing visitor methods for AST nodes.
|
|
89
|
-
*/
|
|
90
86
|
function create(context) {
|
|
91
87
|
const sourceCode = context.getSourceCode();
|
|
92
88
|
|
|
@@ -129,7 +125,10 @@ function create(context) {
|
|
|
129
125
|
isExport,
|
|
130
126
|
);
|
|
131
127
|
|
|
132
|
-
return fixer.replaceText(
|
|
128
|
+
return fixer.replaceText(
|
|
129
|
+
isExport ? grandParent : declParent,
|
|
130
|
+
replacement,
|
|
131
|
+
);
|
|
133
132
|
},
|
|
134
133
|
});
|
|
135
134
|
} else if (node.init.type === 'FunctionExpression') {
|
|
@@ -143,7 +142,10 @@ function create(context) {
|
|
|
143
142
|
sourceCode,
|
|
144
143
|
isExport,
|
|
145
144
|
);
|
|
146
|
-
return fixer.replaceText(
|
|
145
|
+
return fixer.replaceText(
|
|
146
|
+
isExport ? grandParent : declParent,
|
|
147
|
+
replacement,
|
|
148
|
+
);
|
|
147
149
|
},
|
|
148
150
|
});
|
|
149
151
|
}
|
|
@@ -156,7 +158,8 @@ function create(context) {
|
|
|
156
158
|
|
|
157
159
|
const parent = node.parent;
|
|
158
160
|
|
|
159
|
-
const isTopLevel
|
|
161
|
+
const isTopLevel
|
|
162
|
+
= parent.type === 'Program'
|
|
160
163
|
|| parent.type === 'ExportNamedDeclaration'
|
|
161
164
|
|| parent.type === 'ExportDefaultDeclaration';
|
|
162
165
|
|
|
@@ -164,15 +167,24 @@ function create(context) {
|
|
|
164
167
|
return;
|
|
165
168
|
}
|
|
166
169
|
|
|
170
|
+
const isExport
|
|
171
|
+
= parent.type === 'ExportNamedDeclaration'
|
|
172
|
+
|| parent.type === 'ExportDefaultDeclaration';
|
|
173
|
+
|
|
167
174
|
context.report({
|
|
168
175
|
node,
|
|
169
176
|
message: 'Top-level anonymous function declarations must be named.',
|
|
170
177
|
fix(fixer) {
|
|
171
178
|
const newName = 'defaultFunction';
|
|
172
|
-
const replacement = buildAnonymousFunctionDeclarationReplacement(
|
|
179
|
+
const replacement = buildAnonymousFunctionDeclarationReplacement(
|
|
180
|
+
sourceCode,
|
|
181
|
+
node,
|
|
182
|
+
newName,
|
|
183
|
+
isExport,
|
|
184
|
+
);
|
|
173
185
|
|
|
174
186
|
return fixer.replaceText(
|
|
175
|
-
|
|
187
|
+
isExport ? parent : node,
|
|
176
188
|
replacement,
|
|
177
189
|
);
|
|
178
190
|
},
|