eslint-plugin-crisp 1.5.12 → 1.6.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/.github/workflows/build.yml +6 -0
- package/README.md +2 -1
- package/index.js +2 -0
- package/package.json +16 -7
- package/recommended-ts.js +1 -1
- package/recommended-vue.js +3 -2
- package/rules/align-comments.js +6 -3
- package/rules/constructor-variables.js +17 -2
- package/rules/header-check.js +8 -2
- package/rules/header-comments-check.js +14 -3
- package/rules/import-group-comment.js +13 -4
- package/rules/jsdoc-enforce-access.js +16 -10
- package/rules/no-extra-line-within-function.js +8 -5
- package/rules/no-short-parameters.js +1 -1
- package/rules/no-snake-case.js +0 -24
- package/rules/no-space-in-optional-arguments.js +5 -2
- package/rules/one-space-after-operator.js +59 -14
- package/rules/vue-header-check.js +4 -3
- package/rules/vue-no-regex-data.js +1 -2
- package/rules/vue-pinia-action-single-parameter.js +158 -0
- package/rules/vue-props-declaration-line-break.js +8 -3
- package/rules/vue-watch-handler.js +34 -1
- package/tests/fixtures/vue-header-check/missing-script-style/TestComponent.vue +19 -0
- package/tests/fixtures/vue-header-check/missing-template/TestComponent.vue +3 -0
- package/tests/fixtures/vue-header-check/valid/TestComponent.vue +27 -0
- package/tests/rule-tester.js +78 -0
- package/tests/rules/align-comments.test.js +25 -0
- package/tests/rules/align-consecutive-class-assignements.test.js +24 -0
- package/tests/rules/align-one-var.test.js +31 -0
- package/tests/rules/align-requires.test.js +27 -0
- package/tests/rules/arrow-block-newline.test.js +23 -0
- package/tests/rules/consecutive-line-comments.test.js +27 -0
- package/tests/rules/const.test.js +52 -0
- package/tests/rules/constructor-variables.test.js +52 -0
- package/tests/rules/enforce-optional.test.js +24 -0
- package/tests/rules/header-check.test.js +69 -0
- package/tests/rules/header-comments-check.test.js +90 -0
- package/tests/rules/import-group-comment.test.js +88 -0
- package/tests/rules/import-group-order.test.js +58 -0
- package/tests/rules/jsdoc-align-params.test.js +32 -0
- package/tests/rules/jsdoc-check-indentation.test.js +45 -0
- package/tests/rules/jsdoc-check-optional-params.test.js +40 -0
- package/tests/rules/jsdoc-description-length.test.js +60 -0
- package/tests/rules/jsdoc-description-multiline.test.js +34 -0
- package/tests/rules/jsdoc-enforce-access.test.js +66 -0
- package/tests/rules/jsdoc-enforce-classdesc.test.js +39 -0
- package/tests/rules/jsdoc-no-param-return.test.js +47 -0
- package/tests/rules/jsdoc-require-description-uppercase.test.js +52 -0
- package/tests/rules/methods-naming.test.js +70 -0
- package/tests/rules/methods-ordering.test.js +75 -0
- package/tests/rules/multiline-comment-end-backslash.test.js +52 -0
- package/tests/rules/newline-after-switch-case.test.js +75 -0
- package/tests/rules/no-async.test.js +57 -0
- package/tests/rules/no-extra-line-within-function.test.js +87 -0
- package/tests/rules/no-inline-function-in-ternary.test.js +59 -0
- package/tests/rules/no-short-parameters.test.js +62 -0
- package/tests/rules/no-snake-case.test.js +81 -0
- package/tests/rules/no-space-in-optional-arguments.test.js +40 -0
- package/tests/rules/no-useless-template-literals.test.js +36 -0
- package/tests/rules/no-var-in-blocks.test.js +40 -0
- package/tests/rules/one-space-after-operator.test.js +69 -0
- package/tests/rules/regex-in-constructor.test.js +40 -0
- package/tests/rules/ternary-parenthesis.test.js +34 -0
- package/tests/rules/two-lines-between-class-members.test.js +62 -0
- package/tests/rules/variable-names.test.js +60 -0
- package/tests/rules/vue-attribute-comma.test.js +43 -0
- package/tests/rules/vue-attribute-linebreak.test.js +54 -0
- package/tests/rules/vue-class-attribute-last.test.js +59 -0
- package/tests/rules/vue-class-shorthand-max-len.test.js +67 -0
- package/tests/rules/vue-computed-order.test.js +27 -0
- package/tests/rules/vue-data-comment.test.js +61 -0
- package/tests/rules/vue-define-component.test.js +45 -0
- package/tests/rules/vue-emits-order.test.js +27 -0
- package/tests/rules/vue-header-check.test.js +49 -0
- package/tests/rules/vue-html-indent.test.js +77 -0
- package/tests/rules/vue-html-quotes.test.js +71 -0
- package/tests/rules/vue-methods-separator.test.js +55 -0
- package/tests/rules/vue-name-prop.test.js +59 -0
- package/tests/rules/vue-no-component-class-shorthand.test.js +49 -0
- package/tests/rules/vue-no-mixed-class.test.js +56 -0
- package/tests/rules/vue-no-name-option.test.js +44 -0
- package/tests/rules/vue-no-regex-data.test.js +39 -0
- package/tests/rules/vue-pinia-action-single-parameter.test.js +234 -0
- package/tests/rules/vue-props-declaration-line-break.test.js +68 -0
- package/tests/rules/vue-props-declaration-multiline.test.js +40 -0
- package/tests/rules/vue-props-declaration-order.test.js +27 -0
- package/tests/rules/vue-ref-case.test.js +40 -0
- package/tests/rules/vue-watch-handler.test.js +89 -0
- package/tests/rules-coverage.test.js +19 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const MESSAGE_ID = "singlePayloadArgument";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
meta: {
|
|
5
|
+
type: "problem",
|
|
6
|
+
docs: {
|
|
7
|
+
description: "Require Pinia actions to accept at most one payload argument",
|
|
8
|
+
category: "Possible Errors",
|
|
9
|
+
recommended: true
|
|
10
|
+
},
|
|
11
|
+
schema: [],
|
|
12
|
+
messages: {
|
|
13
|
+
[MESSAGE_ID]: "Pinia actions must accept at most one payload argument. Wrap multiple values in an object."
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
create(context) {
|
|
18
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
19
|
+
const defineStoreImports = collectDefineStoreImports(sourceCode.ast);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (!isImportedDefineStoreCall(node, sourceCode, defineStoreImports)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const options = node.arguments[1];
|
|
28
|
+
|
|
29
|
+
if (!options || options.type !== "ObjectExpression") {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const actions = findObjectProperty(options, "actions");
|
|
34
|
+
|
|
35
|
+
if (!actions || actions.value.type !== "ObjectExpression") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const property of actions.value.properties) {
|
|
40
|
+
const action = getActionFunction(property);
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
action &&
|
|
44
|
+
(
|
|
45
|
+
action.params.length > 1 ||
|
|
46
|
+
action.params.some((parameter) => parameter.type === "RestElement")
|
|
47
|
+
)
|
|
48
|
+
) {
|
|
49
|
+
context.report({
|
|
50
|
+
node: action,
|
|
51
|
+
messageId: MESSAGE_ID
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Collects local bindings for named defineStore imports from Pinia
|
|
61
|
+
function collectDefineStoreImports(program) {
|
|
62
|
+
const imports = new Map();
|
|
63
|
+
|
|
64
|
+
for (const node of program.body) {
|
|
65
|
+
if (node.type !== "ImportDeclaration" || node.source.value !== "pinia") {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const specifier of node.specifiers) {
|
|
70
|
+
if (
|
|
71
|
+
specifier.type === "ImportSpecifier" &&
|
|
72
|
+
getImportedName(specifier) === "defineStore"
|
|
73
|
+
) {
|
|
74
|
+
imports.set(specifier.local.name, specifier);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return imports;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Returns the imported name for JavaScript and TypeScript ESTree nodes
|
|
83
|
+
function getImportedName(specifier) {
|
|
84
|
+
return specifier.imported.name || specifier.imported.value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Checks that a call resolves to the collected Pinia import, rather than a shadow
|
|
88
|
+
function isImportedDefineStoreCall(node, sourceCode, defineStoreImports) {
|
|
89
|
+
if (
|
|
90
|
+
node.callee.type !== "Identifier" ||
|
|
91
|
+
!defineStoreImports.has(node.callee.name)
|
|
92
|
+
) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const expectedSpecifier = defineStoreImports.get(node.callee.name);
|
|
97
|
+
let scope = sourceCode.getScope(node);
|
|
98
|
+
|
|
99
|
+
while (scope) {
|
|
100
|
+
const variable = scope.variables.find(({ name }) => name === node.callee.name);
|
|
101
|
+
|
|
102
|
+
if (variable) {
|
|
103
|
+
return variable.defs.some((definition) => {
|
|
104
|
+
return (
|
|
105
|
+
definition.type === "ImportBinding" &&
|
|
106
|
+
definition.node === expectedSpecifier
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
scope = scope.upper;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Finds a direct, statically named property in an object expression
|
|
118
|
+
function findObjectProperty(object, name) {
|
|
119
|
+
return object.properties.find((property) => {
|
|
120
|
+
return (
|
|
121
|
+
property.type === "Property" &&
|
|
122
|
+
property.kind === "init" &&
|
|
123
|
+
getStaticPropertyName(property) === name
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Returns a property's static name, including quoted property names
|
|
129
|
+
function getStaticPropertyName(property) {
|
|
130
|
+
if (!property.computed && property.key.type === "Identifier") {
|
|
131
|
+
return property.key.name;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (property.key.type === "Literal") {
|
|
135
|
+
return property.key.value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Returns a directly declared action function
|
|
142
|
+
function getActionFunction(property) {
|
|
143
|
+
if (
|
|
144
|
+
property.type !== "Property" ||
|
|
145
|
+
property.kind !== "init"
|
|
146
|
+
) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
property.value.type === "FunctionExpression" ||
|
|
152
|
+
property.value.type === "ArrowFunctionExpression"
|
|
153
|
+
) {
|
|
154
|
+
return property.value;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
@@ -28,9 +28,14 @@ export default {
|
|
|
28
28
|
fix(fixer) {
|
|
29
29
|
const typeToken = sourceCode.getLastToken(typeProperty);
|
|
30
30
|
const defaultToken = sourceCode.getFirstToken(defaultProperty);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
31
|
+
const typeLine = sourceCode.lines[typeProperty.loc.start.line - 1];
|
|
32
|
+
const leadingText = typeLine.slice(0, typeProperty.loc.start.column);
|
|
33
|
+
const indent = leadingText.trim() === "" ? leadingText : "";
|
|
34
|
+
|
|
35
|
+
return fixer.replaceTextRange(
|
|
36
|
+
[typeToken.range[1], defaultToken.range[0]],
|
|
37
|
+
`,\n\n${indent}`
|
|
38
|
+
);
|
|
34
39
|
}
|
|
35
40
|
});
|
|
36
41
|
}
|
|
@@ -30,6 +30,29 @@ function hasValidSignature(handler) {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function isDefineComponentCall(node) {
|
|
34
|
+
if (!node || node.type !== "CallExpression") {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
(node.callee.type === "Identifier" && node.callee.name === "defineComponent") ||
|
|
40
|
+
(
|
|
41
|
+
node.callee.type === "MemberExpression" &&
|
|
42
|
+
!node.callee.computed &&
|
|
43
|
+
node.callee.property.type === "Identifier" &&
|
|
44
|
+
node.callee.property.name === "defineComponent"
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isVueOptionsObject(node) {
|
|
50
|
+
return (
|
|
51
|
+
node.parent.type === "ExportDefaultDeclaration" ||
|
|
52
|
+
isDefineComponentCall(node.parent)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
33
56
|
export default {
|
|
34
57
|
meta: {
|
|
35
58
|
type: "suggestion",
|
|
@@ -52,7 +75,17 @@ export default {
|
|
|
52
75
|
|
|
53
76
|
create(context) {
|
|
54
77
|
return {
|
|
55
|
-
|
|
78
|
+
"Property > ObjectExpression"(node) {
|
|
79
|
+
const watchProperty = node.parent;
|
|
80
|
+
const optionsObject = watchProperty.parent;
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
getPropertyName(watchProperty) !== "watch" ||
|
|
84
|
+
!isVueOptionsObject(optionsObject)
|
|
85
|
+
) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
56
89
|
node.properties.forEach((watcher) => {
|
|
57
90
|
if (watcher.type !== "Property") {
|
|
58
91
|
return;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<!-- **********************************************************************
|
|
4
|
+
TEMPLATE
|
|
5
|
+
********************************************************************** -->
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<main>Partial headers</main>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
const ready = false;
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style scoped>
|
|
16
|
+
main {
|
|
17
|
+
display: block;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- **********************************************************************
|
|
2
|
+
TEMPLATE
|
|
3
|
+
********************************************************************** -->
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<main>Ready</main>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<!-- **********************************************************************
|
|
11
|
+
SCRIPT
|
|
12
|
+
********************************************************************** -->
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
const ready = true;
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<!-- **********************************************************************
|
|
20
|
+
STYLE
|
|
21
|
+
********************************************************************** -->
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
main {
|
|
25
|
+
display: block;
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { RuleTester } from "eslint";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import vueParser from "vue-eslint-parser";
|
|
4
|
+
|
|
5
|
+
RuleTester.describe = describe;
|
|
6
|
+
RuleTester.it = it;
|
|
7
|
+
RuleTester.itOnly = it.only;
|
|
8
|
+
|
|
9
|
+
export default function createRuleTester({
|
|
10
|
+
languageOptions = {},
|
|
11
|
+
|
|
12
|
+
...options
|
|
13
|
+
} = {}) {
|
|
14
|
+
return new RuleTester({
|
|
15
|
+
...options,
|
|
16
|
+
|
|
17
|
+
languageOptions: {
|
|
18
|
+
ecmaVersion: "latest",
|
|
19
|
+
sourceType: "module",
|
|
20
|
+
|
|
21
|
+
...languageOptions
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createVueRuleTester(options = {}) {
|
|
27
|
+
return createRuleTester({
|
|
28
|
+
...options,
|
|
29
|
+
|
|
30
|
+
languageOptions: {
|
|
31
|
+
...options.languageOptions,
|
|
32
|
+
|
|
33
|
+
parser: vueParser
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createPugRuleTester(options = {}) {
|
|
39
|
+
return createVueRuleTester({
|
|
40
|
+
...options,
|
|
41
|
+
|
|
42
|
+
languageOptions: {
|
|
43
|
+
...options.languageOptions,
|
|
44
|
+
|
|
45
|
+
parserOptions: {
|
|
46
|
+
...options.languageOptions?.parserOptions,
|
|
47
|
+
|
|
48
|
+
templateTokenizer: {
|
|
49
|
+
pug: "vue-eslint-parser-template-tokenizer-pug"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function withoutFixes(rule) {
|
|
57
|
+
const { fixable, ...meta } = rule.meta || {};
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
...rule,
|
|
61
|
+
|
|
62
|
+
meta,
|
|
63
|
+
|
|
64
|
+
create(context) {
|
|
65
|
+
const reportOnlyContext = Object.create(context);
|
|
66
|
+
|
|
67
|
+
Object.defineProperty(reportOnlyContext, "report", {
|
|
68
|
+
value(descriptor) {
|
|
69
|
+
const { fix, ...report } = descriptor;
|
|
70
|
+
|
|
71
|
+
context.report(report);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return rule.create(reportOnlyContext);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import rule from "../../rules/align-comments.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("align-comments", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"// A top-level value\nconst value = 1;",
|
|
9
|
+
"function example() {\n // Return the value\n return true;\n}",
|
|
10
|
+
"const previous = 1; // Keep this inline\nconst next = 2;",
|
|
11
|
+
"const callback = () => {\n // Invoke the callback\n callback();\n};"
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
invalid: [
|
|
15
|
+
{
|
|
16
|
+
code: "function example() {\n// Misaligned\n return true;\n}",
|
|
17
|
+
output: "function example() {\n // Misaligned\n return true;\n}",
|
|
18
|
+
errors: [
|
|
19
|
+
{
|
|
20
|
+
message: "Comment should be aligned with the next line."
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import rule from "../../rules/align-consecutive-class-assignements.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("align-consecutive-class-assignements", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"class Example {\n constructor() {\n this.a = 1;\n this.long = 2;\n }\n}",
|
|
9
|
+
"class Example {\n constructor() {\n this.a = 1;\n\n this.long = 2;\n }\n}",
|
|
10
|
+
"class Example {\n method() {\n this.a = 1;\n this.long = 2;\n }\n}"
|
|
11
|
+
],
|
|
12
|
+
|
|
13
|
+
invalid: [
|
|
14
|
+
{
|
|
15
|
+
code: "class Example {\n constructor() {\n this.a = 1;\n this.long = 2;\n }\n}",
|
|
16
|
+
errors: [
|
|
17
|
+
{
|
|
18
|
+
message:
|
|
19
|
+
"Assignment of 'this.a' at line 3 column 12 should be aligned at column 15"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import rule from "../../rules/align-one-var.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("align-one-var", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"const first = 1,\n next = 2;",
|
|
9
|
+
"const first = 1, next = 2;",
|
|
10
|
+
"let first,\n next;"
|
|
11
|
+
],
|
|
12
|
+
|
|
13
|
+
invalid: [
|
|
14
|
+
{
|
|
15
|
+
code: "const first = 1,\n next = 2;",
|
|
16
|
+
errors: [
|
|
17
|
+
{
|
|
18
|
+
message: "Misaligned variable declaration."
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
code: "const first = 1,\n next = 2;",
|
|
24
|
+
errors: [
|
|
25
|
+
{
|
|
26
|
+
message: "Misaligned assignment operator."
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import rule from "../../rules/align-requires.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester({
|
|
5
|
+
languageOptions: {
|
|
6
|
+
sourceType: "commonjs"
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
ruleTester.run("align-requires", rule, {
|
|
11
|
+
valid: [
|
|
12
|
+
"const alpha = require(\"alpha\"),\n beta = require(\"beta\");",
|
|
13
|
+
"const alpha = require(\"alpha\");\nconst beta = require(\"beta\");",
|
|
14
|
+
"const alpha = require(\"alpha\"), value = 1,\n beta = require(\"beta\");"
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
invalid: [
|
|
18
|
+
{
|
|
19
|
+
code: "const alpha = require(\"alpha\"),\n beta = require(\"beta\");",
|
|
20
|
+
errors: [
|
|
21
|
+
{
|
|
22
|
+
message: "Misaligned require statement."
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import rule from "../../rules/arrow-block-newline.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("arrow-block-newline", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"const callback = () => {};",
|
|
9
|
+
"const callback = () => {\n return true;\n};",
|
|
10
|
+
"const callback = () => true;"
|
|
11
|
+
],
|
|
12
|
+
|
|
13
|
+
invalid: [
|
|
14
|
+
{
|
|
15
|
+
code: "const callback = () => { return true;\n};",
|
|
16
|
+
errors: [
|
|
17
|
+
{
|
|
18
|
+
messageId: "expectedNewline"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import rule from "../../rules/consecutive-line-comments.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
const lines = (...values) => values.join("\n");
|
|
7
|
+
|
|
8
|
+
ruleTester.run("consecutive-line-comments", rule, {
|
|
9
|
+
valid: [
|
|
10
|
+
lines("// First line \\", "// second line", "const value = 1;"),
|
|
11
|
+
lines("// First comment", "// Second comment", "const value = 1;"),
|
|
12
|
+
lines("// eslint-disable-next-line no-console", "console.log(\"value\");"),
|
|
13
|
+
lines("// Intro \\", "// Important: separate block", "const value = 1;")
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
invalid: [
|
|
17
|
+
{
|
|
18
|
+
code: lines("// First line \\", "// Second line", "const value = 1;"),
|
|
19
|
+
output: lines("// First line \\", "// Second line", "const value = 1;"),
|
|
20
|
+
errors: [
|
|
21
|
+
{
|
|
22
|
+
messageId: "format"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import rule from "../../rules/const.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("const", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"const MAXIMUM = 10;",
|
|
9
|
+
"const client = createClient();",
|
|
10
|
+
"const callback = () => true;",
|
|
11
|
+
"function example() {\n const __CACHE = 1;\n}",
|
|
12
|
+
{
|
|
13
|
+
code: "function example() {\n const cache = 1;\n}",
|
|
14
|
+
options: [
|
|
15
|
+
{
|
|
16
|
+
exceptions: ["cache"]
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"export const publicValue = 1;"
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
invalid: [
|
|
24
|
+
{
|
|
25
|
+
code: "const value = 1;",
|
|
26
|
+
errors: [
|
|
27
|
+
{
|
|
28
|
+
message:
|
|
29
|
+
"Consts should be uppercase and defined at the top level or be replaced with let _variable (Crisp convention)."
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
code: "function example() {\n const _cache = 1;\n}",
|
|
35
|
+
output: "function example() {\n let _cache = 1;\n}",
|
|
36
|
+
errors: [
|
|
37
|
+
{
|
|
38
|
+
message: "Local variables prefixed with \"_\" should use \"let\"."
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: "function example() {\n const value = 1;\n}",
|
|
44
|
+
errors: [
|
|
45
|
+
{
|
|
46
|
+
message:
|
|
47
|
+
"Consts should be uppercase and defined at the top level or be replaced with let _variable (Crisp convention)."
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import rule from "../../rules/constructor-variables.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("constructor-variables", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"class Example {\n constructor() {\n this._value = 1;\n }\n}",
|
|
9
|
+
{
|
|
10
|
+
code: "class Example {\n constructor() {\n this.value = 1;\n }\n}",
|
|
11
|
+
options: [
|
|
12
|
+
{
|
|
13
|
+
variableExceptions: ["value"]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
code: "class Example {\n constructor() {\n this.value = 1;\n }\n}",
|
|
19
|
+
filename: "/project/special-file.js",
|
|
20
|
+
options: [
|
|
21
|
+
{
|
|
22
|
+
filenameExceptions: ["special-file.js"]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"class Example {\n method() {\n this.value = 1;\n }\n}",
|
|
27
|
+
"class Example {\n constructor() {\n this[\"_value\"] = 1;\n }\n}",
|
|
28
|
+
"class Example {\n constructor() {\n this[propertyName] = 1;\n }\n}"
|
|
29
|
+
],
|
|
30
|
+
|
|
31
|
+
invalid: [
|
|
32
|
+
{
|
|
33
|
+
code: "class Example {\n constructor() {\n this.value = 1;\n }\n}",
|
|
34
|
+
filename: "/project/example.js",
|
|
35
|
+
errors: [
|
|
36
|
+
{
|
|
37
|
+
message:
|
|
38
|
+
"Class properties in the constructor should start with '_', except for specified exceptions"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: "class Example {\n constructor() {\n this[\"value\"] = 1;\n }\n}",
|
|
44
|
+
errors: [
|
|
45
|
+
{
|
|
46
|
+
message:
|
|
47
|
+
"Class properties in the constructor should start with '_', except for specified exceptions"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import rule from "../../rules/enforce-optional.js";
|
|
2
|
+
import createRuleTester from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createRuleTester();
|
|
5
|
+
|
|
6
|
+
ruleTester.run("enforce-optional", rule, {
|
|
7
|
+
valid: [
|
|
8
|
+
"const result = foo?.bar;",
|
|
9
|
+
"const result = foo && foo.bar !== null;",
|
|
10
|
+
"const keys = Object.keys(foo || {});",
|
|
11
|
+
"const filtered = (foo || []).filter(Boolean);"
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
invalid: [
|
|
15
|
+
{
|
|
16
|
+
code: "const result = foo && foo.bar;",
|
|
17
|
+
errors: [
|
|
18
|
+
{
|
|
19
|
+
message: /Prefer using optional chaining rather than/
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
});
|