eslint-plugin-crisp 1.4.16 → 1.4.18
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/index.js +2 -0
- package/package.json +1 -1
- package/recommended-ts.js +1 -0
- package/recommended-vue.js +2 -0
- package/recommended.js +1 -0
- package/rules/const.js +144 -12
- package/rules/no-inline-function-in-ternary.js +49 -0
- package/rules/variable-names.js +35 -100
package/index.js
CHANGED
|
@@ -29,6 +29,7 @@ import ruleMultilineCommentEndBackslash from "./rules/multiline-comment-end-back
|
|
|
29
29
|
import ruleNewlineAfterSwitchCase from "./rules/newline-after-switch-case.js";
|
|
30
30
|
import ruleNoAsync from "./rules/no-async.js";
|
|
31
31
|
import ruleNoExtraLineWithinFunction from "./rules/no-extra-line-within-function.js";
|
|
32
|
+
import ruleNoInlineFunctionInTernary from "./rules/no-inline-function-in-ternary.js";
|
|
32
33
|
import ruleNoSpaceInOptionalArguments from "./rules/no-space-in-optional-arguments.js";
|
|
33
34
|
import ruleNoUselessTemplateLiterals from "./rules/no-useless-template-literals.js";
|
|
34
35
|
import ruleNoVarInBlocks from "./rules/no-var-in-blocks.js";
|
|
@@ -96,6 +97,7 @@ const plugin = {
|
|
|
96
97
|
"newline-after-switch-case": ruleNewlineAfterSwitchCase,
|
|
97
98
|
"no-async": ruleNoAsync,
|
|
98
99
|
"no-extra-line-within-function": ruleNoExtraLineWithinFunction,
|
|
100
|
+
"no-inline-function-in-ternary": ruleNoInlineFunctionInTernary,
|
|
99
101
|
"no-space-in-optional-arguments": ruleNoSpaceInOptionalArguments,
|
|
100
102
|
"no-var-in-blocks": ruleNoVarInBlocks,
|
|
101
103
|
"no-useless-template-literals": ruleNoUselessTemplateLiterals,
|
package/package.json
CHANGED
package/recommended-ts.js
CHANGED
|
@@ -163,6 +163,7 @@ export default function configRecommendedTS(pluginCrisp) {
|
|
|
163
163
|
"crisp/newline-after-switch-case": "error",
|
|
164
164
|
"crisp/no-async": "off",
|
|
165
165
|
"crisp/no-extra-line-within-function": "error",
|
|
166
|
+
"crisp/no-inline-function-in-ternary": "error",
|
|
166
167
|
"crisp/no-short-parameters": [
|
|
167
168
|
"error",
|
|
168
169
|
{
|
package/recommended-vue.js
CHANGED
|
@@ -168,6 +168,7 @@ export default function configRecommendedVue(pluginCrisp) {
|
|
|
168
168
|
// Crisp JS rules
|
|
169
169
|
"crisp/align-comments": "error",
|
|
170
170
|
"crisp/consecutive-line-comments": "error",
|
|
171
|
+
"crisp/const": "error",
|
|
171
172
|
"crisp/enforce-optional": "error",
|
|
172
173
|
"crisp/header-check": "error",
|
|
173
174
|
"crisp/header-comments-check": "error",
|
|
@@ -179,6 +180,7 @@ export default function configRecommendedVue(pluginCrisp) {
|
|
|
179
180
|
"crisp/newline-after-switch-case": "error",
|
|
180
181
|
"crisp/no-async": "error",
|
|
181
182
|
"crisp/no-extra-line-within-function": "error",
|
|
183
|
+
"crisp/no-inline-function-in-ternary": "error",
|
|
182
184
|
"crisp/no-short-parameters": [
|
|
183
185
|
"error",
|
|
184
186
|
|
package/recommended.js
CHANGED
|
@@ -171,6 +171,7 @@ export default function configRecommended(pluginCrisp) {
|
|
|
171
171
|
"crisp/newline-after-switch-case": "error",
|
|
172
172
|
"crisp/no-async": "error",
|
|
173
173
|
"crisp/no-extra-line-within-function": "error",
|
|
174
|
+
"crisp/no-inline-function-in-ternary": "error",
|
|
174
175
|
"crisp/no-var-in-blocks": "error",
|
|
175
176
|
"crisp/no-short-parameters": [
|
|
176
177
|
"error",
|
package/rules/const.js
CHANGED
|
@@ -1,27 +1,159 @@
|
|
|
1
|
+
const isTopLevelDeclaration = (node) => {
|
|
2
|
+
let parent = node.parent;
|
|
3
|
+
|
|
4
|
+
if (parent?.type === "ExportNamedDeclaration") {
|
|
5
|
+
parent = parent.parent;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return parent?.type === "Program";
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const isExportedDeclaration = (node) => {
|
|
12
|
+
return node.parent?.type === "ExportNamedDeclaration";
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const isCallOrConstruction = (node) => {
|
|
16
|
+
return node?.type === "CallExpression" || node?.type === "NewExpression";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const isFunctionExpression = (node) => {
|
|
20
|
+
return (
|
|
21
|
+
node?.type === "ArrowFunctionExpression" ||
|
|
22
|
+
node?.type === "FunctionExpression"
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
1
26
|
export default {
|
|
2
27
|
meta: {
|
|
3
28
|
type: "suggestion",
|
|
4
29
|
docs: {
|
|
5
|
-
description:
|
|
30
|
+
description:
|
|
31
|
+
"Enforce top-level uppercase or double-underscore constant names.",
|
|
6
32
|
category: "Stylistic Issues",
|
|
7
|
-
recommended: false
|
|
33
|
+
recommended: false
|
|
8
34
|
},
|
|
9
|
-
|
|
35
|
+
fixable: "code",
|
|
36
|
+
|
|
37
|
+
schema: [{
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
exceptions: {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: { type: "string" },
|
|
43
|
+
uniqueItems: true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
additionalProperties: false
|
|
47
|
+
}]
|
|
10
48
|
},
|
|
49
|
+
|
|
11
50
|
create(context) {
|
|
51
|
+
const options = context.options[0] || {};
|
|
52
|
+
const exceptions = options.exceptions || [];
|
|
53
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
54
|
+
|
|
55
|
+
const isTopLevelCallArgument = (identifier) => {
|
|
56
|
+
let scope = sourceCode.getScope(identifier);
|
|
57
|
+
let variable;
|
|
58
|
+
|
|
59
|
+
while (scope && !variable) {
|
|
60
|
+
variable = scope.set.get(identifier.name);
|
|
61
|
+
scope = scope.upper;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return variable?.references.some((reference) => {
|
|
65
|
+
const parent = reference.identifier.parent;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
isCallOrConstruction(parent) &&
|
|
69
|
+
parent.arguments.includes(reference.identifier)
|
|
70
|
+
);
|
|
71
|
+
}) || false;
|
|
72
|
+
};
|
|
73
|
+
|
|
12
74
|
return {
|
|
13
75
|
VariableDeclaration(node) {
|
|
14
|
-
if (node.kind
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
76
|
+
if (node.kind !== "const") {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const isTopLevel = isTopLevelDeclaration(node);
|
|
81
|
+
const isExported = isExportedDeclaration(node);
|
|
82
|
+
const hasOnlyDestructuring = node.declarations.every((declaration) => {
|
|
83
|
+
return declaration.id.type !== "Identifier";
|
|
84
|
+
});
|
|
85
|
+
const canReplaceWithLet = node.declarations.every((declaration) => {
|
|
86
|
+
if (declaration.id.type !== "Identifier") {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const name = declaration.id.name;
|
|
91
|
+
const isValidConst =
|
|
92
|
+
exceptions.includes(name) ||
|
|
93
|
+
(
|
|
94
|
+
name.startsWith("__") &&
|
|
95
|
+
name.toUpperCase() === name
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return name.startsWith("_") && !isValidConst;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!isTopLevel && !isExported && canReplaceWithLet) {
|
|
102
|
+
context.report({
|
|
103
|
+
node,
|
|
104
|
+
message: hasOnlyDestructuring
|
|
105
|
+
? "Local destructuring declarations should use \"let\"."
|
|
106
|
+
: "Local variables prefixed with \"_\" should use \"let\".",
|
|
107
|
+
fix(fixer) {
|
|
108
|
+
return fixer.replaceText(sourceCode.getFirstToken(node), "let");
|
|
21
109
|
}
|
|
22
110
|
});
|
|
111
|
+
|
|
112
|
+
return;
|
|
23
113
|
}
|
|
24
|
-
|
|
114
|
+
|
|
115
|
+
node.declarations.forEach((declaration) => {
|
|
116
|
+
if (declaration.id.type !== "Identifier") {
|
|
117
|
+
if (isTopLevel || isExported) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
context.report({
|
|
122
|
+
node: declaration,
|
|
123
|
+
message: "Local destructuring declarations should use \"let\"."
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const name = declaration.id.name;
|
|
130
|
+
const isUppercase = name.toUpperCase() === name;
|
|
131
|
+
const hasValidPlacement =
|
|
132
|
+
isTopLevel || name.startsWith("__");
|
|
133
|
+
const isTopLevelBuilder =
|
|
134
|
+
isTopLevel && isCallOrConstruction(declaration.init);
|
|
135
|
+
const isTopLevelBuilderArgument =
|
|
136
|
+
isTopLevel && isTopLevelCallArgument(declaration.id);
|
|
137
|
+
const isFunction = isFunctionExpression(declaration.init);
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
isExported ||
|
|
141
|
+
isTopLevelBuilder ||
|
|
142
|
+
isTopLevelBuilderArgument ||
|
|
143
|
+
isFunction ||
|
|
144
|
+
exceptions.includes(name) ||
|
|
145
|
+
(isUppercase && hasValidPlacement)
|
|
146
|
+
) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
context.report({
|
|
151
|
+
node: declaration.id,
|
|
152
|
+
message:
|
|
153
|
+
"Consts should be uppercase and defined at the top level or be replaced with let _variable (Crisp convention)."
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
25
157
|
};
|
|
26
|
-
}
|
|
158
|
+
}
|
|
27
159
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const findContainingTernaryBranch = (node) => {
|
|
2
|
+
let child = node;
|
|
3
|
+
let parent = node.parent;
|
|
4
|
+
|
|
5
|
+
while (parent) {
|
|
6
|
+
if (
|
|
7
|
+
parent.type === "ConditionalExpression" &&
|
|
8
|
+
(parent.consequent === child || parent.alternate === child)
|
|
9
|
+
) {
|
|
10
|
+
return parent;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
child = parent;
|
|
14
|
+
parent = parent.parent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
meta: {
|
|
22
|
+
type: "suggestion",
|
|
23
|
+
docs: {
|
|
24
|
+
description: "Disallow inline functions in ternary branches."
|
|
25
|
+
},
|
|
26
|
+
schema: [],
|
|
27
|
+
messages: {
|
|
28
|
+
inlineFunction: "Extract this inline function from the ternary expression."
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
create(context) {
|
|
33
|
+
const checkFunction = (node) => {
|
|
34
|
+
if (!findContainingTernaryBranch(node)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
context.report({
|
|
39
|
+
node,
|
|
40
|
+
messageId: "inlineFunction"
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
ArrowFunctionExpression: checkFunction,
|
|
46
|
+
FunctionExpression: checkFunction
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
package/rules/variable-names.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
|
+
const isLocalDeclaration = (node) => {
|
|
2
|
+
let parent = node.parent;
|
|
3
|
+
|
|
4
|
+
while (parent) {
|
|
5
|
+
if (
|
|
6
|
+
parent.type === "ArrowFunctionExpression" ||
|
|
7
|
+
parent.type === "FunctionDeclaration" ||
|
|
8
|
+
parent.type === "FunctionExpression"
|
|
9
|
+
) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
parent = parent.parent;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
|
|
1
19
|
export default {
|
|
2
20
|
meta: {
|
|
3
21
|
type: "suggestion",
|
|
4
22
|
docs: {
|
|
5
|
-
description: "
|
|
23
|
+
description: "Enforce that local variable names follow internal conventions.",
|
|
6
24
|
category: "Stylistic Issues",
|
|
7
25
|
recommended: false
|
|
8
26
|
},
|
|
@@ -24,110 +42,27 @@ export default {
|
|
|
24
42
|
const options = context.options[0] || {};
|
|
25
43
|
const variableExceptions = options.variableExceptions || [];
|
|
26
44
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
switch(node.type) {
|
|
33
|
-
// In case of a variable declaration, it checks if the variable name \
|
|
34
|
-
// starts with "_" or is an exception
|
|
35
|
-
case "VariableDeclaration": {
|
|
36
|
-
node.declarations.forEach((declaration) => {
|
|
37
|
-
if (declaration.id.name && !declaration.id.name.startsWith("_") && !variableExceptions.includes(declaration.id.name)) {
|
|
38
|
-
context.report({
|
|
39
|
-
node: declaration,
|
|
40
|
-
message: `Variables defined within a method should start with "_" ({${declaration.id.name}})`,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// BlockStatement and Program nodes contain lists of statements \
|
|
49
|
-
// (node.body), so we check each statement
|
|
50
|
-
case "BlockStatement":
|
|
51
|
-
case "Program": {
|
|
52
|
-
node.body.forEach(checkDeclaration);
|
|
53
|
-
|
|
54
|
-
break;
|
|
45
|
+
return {
|
|
46
|
+
VariableDeclaration(node) {
|
|
47
|
+
// Constant names are validated by the const rule.
|
|
48
|
+
if (node.kind === "const" || !isLocalDeclaration(node)) {
|
|
49
|
+
return;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
checkDeclaration(node.consequent);
|
|
61
|
-
|
|
62
|
-
if (node.alternate) {
|
|
63
|
-
checkDeclaration(node.alternate);
|
|
52
|
+
for (const declaration of node.declarations) {
|
|
53
|
+
if (declaration.id.type !== "Identifier") {
|
|
54
|
+
continue;
|
|
64
55
|
}
|
|
65
56
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
case "ForOfStatement": {
|
|
75
|
-
if (node.body) {
|
|
76
|
-
checkDeclaration(node.body);
|
|
57
|
+
if (
|
|
58
|
+
!declaration.id.name.startsWith("_") &&
|
|
59
|
+
!variableExceptions.includes(declaration.id.name)
|
|
60
|
+
) {
|
|
61
|
+
context.report({
|
|
62
|
+
node: declaration.id,
|
|
63
|
+
message: `Local variables should start with "_" ({${declaration.id.name}})`
|
|
64
|
+
});
|
|
77
65
|
}
|
|
78
|
-
|
|
79
|
-
// Check the loop condition itself
|
|
80
|
-
checkDeclaration(node.left);
|
|
81
|
-
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// SwitchStatement nodes contain an array of SwitchCase nodes that \
|
|
86
|
-
// represent each case in the switch statement
|
|
87
|
-
case "SwitchStatement": {
|
|
88
|
-
node.cases.forEach(checkDeclaration);
|
|
89
|
-
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// SwitchCase nodes contain a consequent which is an array of \
|
|
94
|
-
// Statements to be checked
|
|
95
|
-
case "SwitchCase": {
|
|
96
|
-
node.consequent.forEach(checkDeclaration);
|
|
97
|
-
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
default: {
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
// For each property in an object, if it's a function / arrow function, \
|
|
109
|
-
// check its body (usefull for Vue.js components, in which methods and \
|
|
110
|
-
// computed are defined as properties of a parent object)
|
|
111
|
-
Property(node) {
|
|
112
|
-
if (node.value.type === "FunctionExpression" ||
|
|
113
|
-
node.value.type === "ArrowFunctionExpression") {
|
|
114
|
-
checkDeclaration(node);
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
MethodDefinition(node) {
|
|
119
|
-
checkDeclaration(node.value.body);
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
ArrowFunctionExpression(node) {
|
|
123
|
-
if (node.body.type === "BlockStatement") {
|
|
124
|
-
checkDeclaration(node.body);
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
FunctionExpression(node) {
|
|
129
|
-
if (node.body.type === "BlockStatement") {
|
|
130
|
-
checkDeclaration(node.body);
|
|
131
66
|
}
|
|
132
67
|
}
|
|
133
68
|
};
|