eslint-plugin-crisp 1.4.2 → 1.4.4

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.2",
3
+ "version": "1.4.4",
4
4
  "description": "Custom ESLint Rules for Crisp",
5
5
  "author": "Crisp IM SAS",
6
6
  "main": "index.js",
@@ -1,3 +1,60 @@
1
+ const COMMENT_HEADER_FORMAT = (section) => {
2
+ return `/**************************************************************************\n * ${section.toUpperCase()}\n ***************************************************************************/`;
3
+ };
4
+
5
+ function isTypeComment(comment) {
6
+ if (comment.type !== "Block" || !comment.value.startsWith("*")) {
7
+ return false;
8
+ }
9
+
10
+ const content = comment.value;
11
+
12
+ return content.includes("@import") || content.includes("@typedef");
13
+ }
14
+
15
+ function isUppercaseConstant(declaration) {
16
+ return (
17
+ declaration &&
18
+ declaration.id &&
19
+ declaration.id.name &&
20
+ declaration.id.name === declaration.id.name.toUpperCase()
21
+ );
22
+ }
23
+
24
+ function isRegex(node) {
25
+ if (node.type !== "VariableDeclaration") {
26
+ return false;
27
+ }
28
+
29
+ for (const declaration of node.declarations) {
30
+ if (declaration.init.type === "Literal" && declaration.init.regex != null) {
31
+ return true;
32
+ }
33
+
34
+ if (
35
+ declaration.init.type === "NewExpression" &&
36
+ declaration.init.callee.name === "RegExp"
37
+ ) {
38
+ return true;
39
+ }
40
+ }
41
+
42
+ return false;
43
+ }
44
+
45
+ // Checks if a variable declaration is an import or require
46
+ function isImportOrRequire(declaration) {
47
+ return (
48
+ declaration.init &&
49
+ declaration.init.type === "CallExpression" &&
50
+ (
51
+ (declaration.init.callee.name && declaration.init.callee.name === "require") ||
52
+ (declaration.init.callee.type && declaration.init.callee.type === "Import") ||
53
+ (declaration.init.callee.object && (declaration.init.callee.object || {}).type === "MetaProperty" && declaration.init.callee.object.meta.type === "Identifier" && declaration.init.callee.object.meta.name === "import")
54
+ )
55
+ );
56
+ }
57
+
1
58
  export default {
2
59
  meta: {
3
60
  type: "suggestion",
@@ -6,13 +63,12 @@ export default {
6
63
  category: "Best Practices",
7
64
  recommended: false,
8
65
  },
9
- fixable: null, // This rule is not auto-fixable
66
+ fixable: null,
10
67
  },
11
68
 
12
69
  create(context) {
13
70
  const filename = context.getFilename();
14
71
 
15
- // Only apply this rule to .js and .ts files
16
72
  if (!filename.endsWith(".js") && !filename.endsWith(".ts")) {
17
73
  return {};
18
74
  }
@@ -20,63 +76,37 @@ export default {
20
76
  let lastNode = null;
21
77
  let groupStart = null;
22
78
 
23
- // Cache all block comments once at start (sorted by position for fast lookup)
24
79
  const sourceCode = context.sourceCode || context.getSourceCode();
25
80
  const allBlockComments = sourceCode.getAllComments()
26
81
  .filter(c => c.type === "Block")
27
82
  .sort((a, b) => a.range[0] - b.range[0]);
28
83
 
29
- // This function formats the section string into a comment block header
30
- const COMMENT_HEADER_FORMAT = (section) => {
31
- return `/**************************************************************************\n * ${section.toUpperCase()}\n ***************************************************************************/`;
32
- };
84
+ const typeComments = allBlockComments.filter(c => isTypeComment(c));
33
85
 
34
- function isUppercaseConstant(declaration) {
35
- return (
36
- declaration &&
37
- declaration.id &&
38
- declaration.id.name &&
39
- declaration.id.name === declaration.id.name.toUpperCase()
40
- );
41
- }
86
+ function checkTypeCommentsGroup() {
87
+ if (typeComments.length === 0) {
88
+ return;
89
+ }
42
90
 
43
- function isRegex(node) {
44
- // Check if the node is a variable declaration
45
- if (node.type !== "VariableDeclaration") {
46
- return false;
47
- };
48
-
49
- // For each of the declarations in the variable declaration
50
- for (const declaration of node.declarations) {
51
- // If the initializer is a regex literal, return true
52
- if (declaration.init.type === "Literal" && declaration.init.regex != null) {
53
- return true;
54
- }
91
+ const firstTypeComment = typeComments[0];
92
+ const typeCommentStart = firstTypeComment.range[0];
93
+
94
+ let comment = null;
55
95
 
56
- // If the initializer is a new RegExp expression, return true
57
- if (
58
- declaration.init.type === "NewExpression" &&
59
- declaration.init.callee.name === "RegExp"
60
- ) {
61
- return true;
96
+ for (let i = allBlockComments.length - 1; i >= 0; i--) {
97
+ if (allBlockComments[i].range[1] < typeCommentStart) {
98
+ comment = allBlockComments[i];
99
+
100
+ break;
62
101
  }
63
102
  }
64
103
 
65
- // If none of the declarations are regexes, return false
66
- return false;
67
- }
68
-
69
- // Checks if a variable declaration is an import or require
70
- function isImportOrRequire(declaration) {
71
- return (
72
- declaration.init &&
73
- declaration.init.type === "CallExpression" &&
74
- (
75
- (declaration.init.callee.name && declaration.init.callee.name === "require") ||
76
- (declaration.init.callee.type && declaration.init.callee.type === "Import") ||
77
- (declaration.init.callee.object && (declaration.init.callee.object || {}).type === "MetaProperty" && declaration.init.callee.object.meta.type === "Identifier" && declaration.init.callee.object.meta.name === "import")
78
- )
79
- );
104
+ if (!comment || `/*${comment.value.trim()}*/` !== COMMENT_HEADER_FORMAT("TYPES")) {
105
+ context.report({
106
+ loc: firstTypeComment.loc,
107
+ message: "Type comments group must be preceded by a 'TYPES' comment block",
108
+ });
109
+ }
80
110
  }
81
111
 
82
112
  function checkGroup(nodeType, startNode) {
@@ -180,6 +210,9 @@ export default {
180
210
  if (groupStart) {
181
211
  checkGroup(lastNode.type, groupStart);
182
212
  }
213
+
214
+ // Check type comments group
215
+ checkTypeCommentsGroup();
183
216
  }
184
217
  };
185
218
  }
@@ -12,6 +12,7 @@ export default {
12
12
 
13
13
  create(context) {
14
14
  const SEPARATOR_PATTERN = /^--> (ACTIONS|HELPERS|EVENT LISTENERS) <--$/;
15
+ const SEPARATOR_LIKE_PATTERN = /^--> .+ <--$/;
15
16
 
16
17
  return {
17
18
  'ExportDefaultDeclaration Property[key.name="methods"]'(node) {
@@ -35,11 +36,29 @@ export default {
35
36
  context.report({
36
37
  node,
37
38
  message:
38
- "Methods block must contain at least one separator comment " +
39
- "('// --> ACTIONS <--', '// --> HELPERS <--', " +
40
- "or '// --> EVENT LISTENERS <--')"
39
+ "Methods block must contain at least one separator comment: " +
40
+ "'// --> ACTIONS <--', '// --> HELPERS <--', " +
41
+ "or '// --> EVENT LISTENERS <--'."
41
42
  });
42
43
  }
44
+
45
+ comments.forEach((comment) => {
46
+ if (comment.type === "Line") {
47
+ const trimmed = comment.value.trim();
48
+
49
+ if (
50
+ SEPARATOR_LIKE_PATTERN.test(trimmed) &&
51
+ !SEPARATOR_PATTERN.test(trimmed)
52
+ ) {
53
+ context.report({
54
+ node: comment,
55
+ message:
56
+ "Invalid separator comment. Must be '// --> ACTIONS <--', " +
57
+ "'// --> HELPERS <--', or '// --> EVENT LISTENERS <--'."
58
+ });
59
+ }
60
+ }
61
+ });
43
62
  }
44
63
  };
45
64
  }