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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-crisp",
3
- "version": "1.4.20",
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: null, // This rule is not auto-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 updateCurrentGroupComment(node) {
106
- const comments = context.getSourceCode().getCommentsBefore(node);
106
+ function findGroupComment(node) {
107
+ const comments = sourceCode.getCommentsBefore(node);
107
108
 
108
- if (comments.length > 0) {
109
- for (let i = comments.length - 1; i >= 0; i--) {
110
- if (isIgnoreComment(comments[i])) {
111
- continue;
112
- }
109
+ for (let i = comments.length - 1; i >= 0; i--) {
110
+ if (isIgnoreComment(comments[i])) {
111
+ continue;
112
+ }
113
113
 
114
- if (isGroupComment(comments[i])) {
115
- currentGroupComment = comments[i];
114
+ if (isGroupComment(comments[i])) {
115
+ return comments[i];
116
+ }
117
+ }
116
118
 
117
- break;
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
- // Get comment for current group
132
- updateCurrentGroupComment(node);
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 {