eslint-plugin-crisp 1.4.20 → 1.5.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/package.json +6 -5
- package/rules/import-group-comment.js +72 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-crisp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Custom ESLint Rules for Crisp",
|
|
5
5
|
"author": "Crisp IM SAS",
|
|
6
6
|
"main": "index.js",
|
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"doctrine": "3.0.0",
|
|
18
18
|
"lodash-es": "4.17.21",
|
|
19
|
-
"eslint-plugin-jsdoc": "50.8.0"
|
|
19
|
+
"eslint-plugin-jsdoc": "50.8.0",
|
|
20
|
+
"typescript": "5.9.2",
|
|
21
|
+
"typescript-eslint": "8.41.0"
|
|
20
22
|
},
|
|
21
23
|
"peerDependencies": {
|
|
22
24
|
"eslint": "9.39.1",
|
|
23
25
|
"eslint-plugin-vue": "10.8.0",
|
|
24
26
|
"eslint-plugin-vue-pug": "1.0.0-alpha.5",
|
|
25
|
-
"globals": "15.15.0"
|
|
26
|
-
"typescript-eslint": "8.41.0"
|
|
27
|
+
"globals": "15.15.0"
|
|
27
28
|
},
|
|
28
29
|
"keywords": [
|
|
29
30
|
"eslint",
|
|
@@ -31,4 +32,4 @@
|
|
|
31
32
|
"vue"
|
|
32
33
|
],
|
|
33
34
|
"license": "MIT"
|
|
34
|
-
}
|
|
35
|
+
}
|
|
@@ -50,7 +50,7 @@ export default {
|
|
|
50
50
|
meta: {
|
|
51
51
|
type: "suggestion",
|
|
52
52
|
docs: {
|
|
53
|
-
description: "Enforce import statements to be grouped and preceded by a comment",
|
|
53
|
+
description: "Enforce import statements to be grouped and preceded by a comment with no blank line",
|
|
54
54
|
category: "Best Practices",
|
|
55
55
|
recommended: false,
|
|
56
56
|
},
|
|
@@ -62,10 +62,11 @@ export default {
|
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
],
|
|
65
|
-
fixable:
|
|
65
|
+
fixable: "whitespace",
|
|
66
66
|
},
|
|
67
67
|
|
|
68
68
|
create(context) {
|
|
69
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
69
70
|
const customGroups = context.options[0] || {}; // Get custom groups from options
|
|
70
71
|
|
|
71
72
|
// Pre-compile custom regexes once instead of on every import
|
|
@@ -102,22 +103,61 @@ export default {
|
|
|
102
103
|
return "NPM";
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
function
|
|
106
|
-
const comments =
|
|
106
|
+
function findGroupComment(node) {
|
|
107
|
+
const comments = sourceCode.getCommentsBefore(node);
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
109
|
+
for (let i = comments.length - 1; i >= 0; i--) {
|
|
110
|
+
if (isIgnoreComment(comments[i])) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
if (isGroupComment(comments[i])) {
|
|
115
|
+
return comments[i];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hasBlankLineBetween(fromNode, toNode) {
|
|
123
|
+
const startLine = fromNode.loc.end.line;
|
|
124
|
+
const endLine = toNode.loc.start.line;
|
|
125
|
+
|
|
126
|
+
for (let i = startLine; i < endLine - 1; i++) {
|
|
127
|
+
if (sourceCode.lines[i].trim() === "") {
|
|
128
|
+
return true;
|
|
119
129
|
}
|
|
120
130
|
}
|
|
131
|
+
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function checkBlankLineAfterGroupComment(target, groupComment, message) {
|
|
136
|
+
if (!hasBlankLineBetween(groupComment, target)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
context.report({
|
|
141
|
+
loc: target.loc,
|
|
142
|
+
message,
|
|
143
|
+
|
|
144
|
+
fix(fixer) {
|
|
145
|
+
const textBetween = sourceCode.text.slice(
|
|
146
|
+
groupComment.range[1],
|
|
147
|
+
target.range[0]
|
|
148
|
+
);
|
|
149
|
+
const collapsed = textBetween.replace(/(\n[ \t]*)+\n/g, "\n");
|
|
150
|
+
|
|
151
|
+
if (collapsed === textBetween) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return fixer.replaceTextRange(
|
|
156
|
+
[groupComment.range[1], target.range[0]],
|
|
157
|
+
collapsed
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
121
161
|
}
|
|
122
162
|
|
|
123
163
|
function checkImportGroup(node) {
|
|
@@ -128,8 +168,17 @@ export default {
|
|
|
128
168
|
const expectedGroup = extractGroupFromPath(importPath, filePath);
|
|
129
169
|
const expectedComment = generateExpectedComment(expectedGroup);
|
|
130
170
|
|
|
131
|
-
|
|
132
|
-
|
|
171
|
+
const groupComment = findGroupComment(node);
|
|
172
|
+
|
|
173
|
+
if (groupComment) {
|
|
174
|
+
currentGroupComment = groupComment;
|
|
175
|
+
|
|
176
|
+
checkBlankLineAfterGroupComment(
|
|
177
|
+
node,
|
|
178
|
+
groupComment,
|
|
179
|
+
"Import group comment must be immediately followed by an import (no blank line)."
|
|
180
|
+
);
|
|
181
|
+
}
|
|
133
182
|
|
|
134
183
|
if (!currentGroupComment || !currentGroupComment.value.includes(expectedComment)) {
|
|
135
184
|
context.report({
|
|
@@ -139,7 +188,6 @@ export default {
|
|
|
139
188
|
}
|
|
140
189
|
}
|
|
141
190
|
|
|
142
|
-
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
143
191
|
const allComments = sourceCode.getAllComments();
|
|
144
192
|
const typeComments = allComments.filter(c => isTypeComment(c));
|
|
145
193
|
|
|
@@ -173,7 +221,15 @@ export default {
|
|
|
173
221
|
loc: firstTypeComment.loc,
|
|
174
222
|
message: "Type comments group must be preceded by a '// TYPES' comment",
|
|
175
223
|
});
|
|
224
|
+
|
|
225
|
+
return;
|
|
176
226
|
}
|
|
227
|
+
|
|
228
|
+
checkBlankLineAfterGroupComment(
|
|
229
|
+
firstTypeComment,
|
|
230
|
+
comment,
|
|
231
|
+
"Type group comment must be immediately followed by a type comment (no blank line)."
|
|
232
|
+
);
|
|
177
233
|
}
|
|
178
234
|
|
|
179
235
|
return {
|