eslint-plugin-crisp 1.6.6 → 1.7.1
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 +5 -5
- package/recommended-vue.js +1 -0
- package/rules/align-comments.js +1 -1
- package/rules/align-consecutive-class-assignements.js +1 -1
- package/rules/align-one-var.js +1 -1
- package/rules/arrow-block-newline.js +1 -1
- package/rules/consecutive-line-comments.js +1 -1
- package/rules/const.js +1 -1
- package/rules/constructor-variables.js +1 -1
- package/rules/enforce-optional.js +1 -1
- package/rules/header-check.js +2 -2
- package/rules/header-comments-check.js +2 -2
- package/rules/import-group-comment.js +3 -3
- package/rules/import-group-order.js +1 -1
- package/rules/jsdoc-align-params.js +1 -1
- package/rules/jsdoc-check-indentation.js +1 -1
- package/rules/jsdoc-check-optional-params.js +4 -1
- package/rules/jsdoc-description-length.js +1 -1
- package/rules/jsdoc-description-multiline.js +1 -1
- package/rules/jsdoc-enforce-access.js +1 -1
- package/rules/jsdoc-enforce-classdesc.js +5 -1
- package/rules/jsdoc-no-param-return.js +1 -1
- package/rules/jsdoc-require-description-uppercase.js +1 -1
- package/rules/logger-arguments.js +1 -1
- package/rules/methods-naming.js +1 -1
- package/rules/methods-ordering.js +1 -1
- package/rules/multiline-comment-end-backslash.js +1 -1
- package/rules/newline-after-switch-case.js +4 -2
- package/rules/no-extra-line-within-function.js +1 -1
- package/rules/no-space-in-optional-arguments.js +1 -1
- package/rules/one-space-after-operator.js +1 -1
- package/rules/regex-in-constructor.js +1 -1
- package/rules/ternary-parenthesis.js +1 -1
- package/rules/two-lines-between-class-members.js +1 -1
- package/rules/utils/get-jsdoc-comment.js +72 -0
- package/rules/vue-attribute-comma.js +1 -1
- package/rules/vue-class-attribute-last.js +1 -1
- package/rules/vue-class-shorthand-max-len.js +1 -1
- package/rules/vue-computed-order.js +1 -1
- package/rules/vue-data-comment.js +1 -1
- package/rules/vue-define-component.js +2 -2
- package/rules/vue-emits-order.js +1 -1
- package/rules/vue-header-check.js +1 -1
- package/rules/vue-html-indent.js +1 -1
- package/rules/vue-html-quotes.js +1 -1
- package/rules/vue-methods-separator.js +1 -1
- package/rules/vue-no-component-class-shorthand.js +1 -1
- package/rules/vue-no-mixed-class-shorthand.js +65 -0
- package/rules/vue-no-name-option.js +2 -2
- package/rules/vue-pinia-action-single-parameter.js +1 -1
- package/rules/vue-props-declaration-line-break.js +1 -1
- package/rules/vue-props-declaration-multiline.js +1 -1
- package/rules/vue-props-declaration-order.js +1 -1
- package/tests/rules/jsdoc-check-optional-params.test.js +11 -0
- package/tests/rules/jsdoc-enforce-classdesc.test.js +11 -0
- package/tests/rules/vue-no-mixed-class-shorthand.test.js +57 -0
package/index.js
CHANGED
|
@@ -57,6 +57,7 @@ import ruleVueMethodsSeparator from "./rules/vue-methods-separator.js";
|
|
|
57
57
|
import ruleVueNameProp from "./rules/vue-name-prop.js";
|
|
58
58
|
import ruleVueNoComponentClassShorthand from "./rules/vue-no-component-class-shorthand.js";
|
|
59
59
|
import ruleVueNoMixedClass from "./rules/vue-no-mixed-class.js";
|
|
60
|
+
import ruleVueNoMixedClassShorthand from "./rules/vue-no-mixed-class-shorthand.js";
|
|
60
61
|
import ruleVueNoNameOption from "./rules/vue-no-name-option.js";
|
|
61
62
|
import ruleVueNoRegexData from "./rules/vue-no-regex-data.js";
|
|
62
63
|
import ruleVuePiniaActionSingleParameter from "./rules/vue-pinia-action-single-parameter.js";
|
|
@@ -135,6 +136,7 @@ const plugin = {
|
|
|
135
136
|
"vue-name-prop": ruleVueNameProp,
|
|
136
137
|
"vue-no-component-class-shorthand": ruleVueNoComponentClassShorthand,
|
|
137
138
|
"vue-no-mixed-class": ruleVueNoMixedClass,
|
|
139
|
+
"vue-no-mixed-class-shorthand": ruleVueNoMixedClassShorthand,
|
|
138
140
|
"vue-no-name-option": ruleVueNoNameOption,
|
|
139
141
|
"vue-no-regex-data": ruleVueNoRegexData,
|
|
140
142
|
"vue-pinia-action-single-parameter": ruleVuePiniaActionSingleParameter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-crisp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "Custom ESLint Rules for Crisp",
|
|
5
5
|
"author": "Crisp IM SAS",
|
|
6
6
|
"main": "index.js",
|
|
@@ -17,20 +17,20 @@
|
|
|
17
17
|
"test": "node --test"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@eslint/js": "
|
|
20
|
+
"@eslint/js": "10.0.1",
|
|
21
21
|
"doctrine": "3.0.0",
|
|
22
|
-
"eslint-plugin-jsdoc": "
|
|
22
|
+
"eslint-plugin-jsdoc": "65.4.0",
|
|
23
23
|
"lodash-es": "4.18.1",
|
|
24
24
|
"typescript": "5.9.3",
|
|
25
25
|
"typescript-eslint": "8.72.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"eslint": "
|
|
28
|
+
"eslint": "10.13.0",
|
|
29
29
|
"vue-eslint-parser": "10.4.1",
|
|
30
30
|
"vue-eslint-parser-template-tokenizer-pug": "1.0.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"eslint": "^
|
|
33
|
+
"eslint": "^10.13.0",
|
|
34
34
|
"eslint-plugin-vue": "^10.11.1",
|
|
35
35
|
"eslint-plugin-vue-pug": "1.0.0-alpha.6",
|
|
36
36
|
"globals": "15.15.0"
|
package/recommended-vue.js
CHANGED
|
@@ -391,6 +391,7 @@ export default function configRecommendedVue(pluginCrisp) {
|
|
|
391
391
|
"crisp/vue-name-prop": "error",
|
|
392
392
|
"crisp/vue-no-component-class-shorthand": "error",
|
|
393
393
|
"crisp/vue-no-mixed-class": "error",
|
|
394
|
+
"crisp/vue-no-mixed-class-shorthand": "error",
|
|
394
395
|
"crisp/vue-no-name-option": "error",
|
|
395
396
|
"crisp/vue-no-regex-data": "error",
|
|
396
397
|
"crisp/vue-pinia-action-single-parameter": "error",
|
package/rules/align-comments.js
CHANGED
package/rules/align-one-var.js
CHANGED
|
@@ -64,7 +64,7 @@ export default {
|
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
create(context) {
|
|
67
|
-
const sourceCode = context.sourceCode
|
|
67
|
+
const sourceCode = context.sourceCode;
|
|
68
68
|
|
|
69
69
|
function isStandalone(comment) {
|
|
70
70
|
const lineText = sourceCode.lines[comment.loc.start.line - 1] || "";
|
package/rules/const.js
CHANGED
|
@@ -50,7 +50,7 @@ export default {
|
|
|
50
50
|
create(context) {
|
|
51
51
|
const options = context.options[0] || {};
|
|
52
52
|
const exceptions = options.exceptions || [];
|
|
53
|
-
const sourceCode = context.sourceCode
|
|
53
|
+
const sourceCode = context.sourceCode;
|
|
54
54
|
|
|
55
55
|
const isTopLevelCallArgument = (identifier) => {
|
|
56
56
|
let scope = sourceCode.getScope(identifier);
|
|
@@ -25,7 +25,7 @@ export default {
|
|
|
25
25
|
|
|
26
26
|
create(context) {
|
|
27
27
|
const options = context.options[0] || {};
|
|
28
|
-
const filename = context.filename
|
|
28
|
+
const filename = context.filename;
|
|
29
29
|
const filenameExceptions = options.filenameExceptions || [];
|
|
30
30
|
const variableExceptions = options.variableExceptions || [];
|
|
31
31
|
|
package/rules/header-check.js
CHANGED
|
@@ -27,8 +27,8 @@ export default {
|
|
|
27
27
|
return {
|
|
28
28
|
Program(node) {
|
|
29
29
|
const options = context.options[0] || {};
|
|
30
|
-
const fileName = context.
|
|
31
|
-
const sourceCode = context.sourceCode
|
|
30
|
+
const fileName = context.filename;
|
|
31
|
+
const sourceCode = context.sourceCode;
|
|
32
32
|
|
|
33
33
|
let fileContent = sourceCode.getText().trim();
|
|
34
34
|
|
|
@@ -119,7 +119,7 @@ export default {
|
|
|
119
119
|
},
|
|
120
120
|
|
|
121
121
|
create(context) {
|
|
122
|
-
const filename = context.filename
|
|
122
|
+
const filename = context.filename;
|
|
123
123
|
|
|
124
124
|
if (!filename.endsWith(".js") && !filename.endsWith(".ts")) {
|
|
125
125
|
return {};
|
|
@@ -128,7 +128,7 @@ export default {
|
|
|
128
128
|
let lastNode = null;
|
|
129
129
|
let groupStart = null;
|
|
130
130
|
|
|
131
|
-
const sourceCode = context.sourceCode
|
|
131
|
+
const sourceCode = context.sourceCode;
|
|
132
132
|
const allBlockComments = sourceCode.getAllComments()
|
|
133
133
|
.filter(c => c.type === "Block")
|
|
134
134
|
.sort((a, b) => a.range[0] - b.range[0]);
|
|
@@ -71,7 +71,7 @@ export default {
|
|
|
71
71
|
},
|
|
72
72
|
|
|
73
73
|
create(context) {
|
|
74
|
-
const sourceCode = context.sourceCode
|
|
74
|
+
const sourceCode = context.sourceCode;
|
|
75
75
|
const customGroups = context.options[0] || {}; // Get custom groups from options
|
|
76
76
|
|
|
77
77
|
// Pre-compile custom regexes once instead of on every import
|
|
@@ -171,7 +171,7 @@ export default {
|
|
|
171
171
|
|
|
172
172
|
function checkImportGroup(node) {
|
|
173
173
|
const importPath = node.source.value;
|
|
174
|
-
const filePath = context.
|
|
174
|
+
const filePath = context.filename;
|
|
175
175
|
|
|
176
176
|
// Get group from import path
|
|
177
177
|
const expectedGroup = extractGroupFromPath(importPath, filePath);
|
|
@@ -201,7 +201,7 @@ export default {
|
|
|
201
201
|
const typeComments = allComments.filter(c => isTypeComment(c));
|
|
202
202
|
|
|
203
203
|
function checkTypeCommentsGroup() {
|
|
204
|
-
const filename = context.
|
|
204
|
+
const filename = context.filename;
|
|
205
205
|
|
|
206
206
|
// Only check for // TYPES in .vue files (block header is checked by header-comments-check rule for .js/.ts)
|
|
207
207
|
if (!filename.endsWith(".vue")) {
|
|
@@ -71,7 +71,7 @@ export default {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function updateAndCheckGroup(node) {
|
|
74
|
-
const comments = context.
|
|
74
|
+
const comments = context.sourceCode.getCommentsBefore(node);
|
|
75
75
|
for (let i = comments.length - 1; i >= 0; i--) {
|
|
76
76
|
const comment = comments[i];
|
|
77
77
|
if (isGroupComment(comment)) {
|
|
@@ -182,7 +182,7 @@ export default {
|
|
|
182
182
|
create: function(context) {
|
|
183
183
|
return {
|
|
184
184
|
Program: function(node) {
|
|
185
|
-
const comments = context.
|
|
185
|
+
const comments = context.sourceCode.getAllComments(node);
|
|
186
186
|
|
|
187
187
|
comments
|
|
188
188
|
.filter(comment => comment.type === "Block" && comment.value.startsWith("*"))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import doctrine from "doctrine";
|
|
2
|
+
import getJSDocComment from "./utils/get-jsdoc-comment.js";
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
meta: {
|
|
@@ -11,9 +12,11 @@ export default {
|
|
|
11
12
|
},
|
|
12
13
|
|
|
13
14
|
create(context) {
|
|
15
|
+
const sourceCode = context.sourceCode;
|
|
16
|
+
|
|
14
17
|
function checkOptionalParams(node) {
|
|
15
18
|
// Get JSDoc comments
|
|
16
|
-
const jsDocComment =
|
|
19
|
+
const jsDocComment = getJSDocComment(sourceCode, node);
|
|
17
20
|
|
|
18
21
|
if (!jsDocComment) {
|
|
19
22
|
return;
|
|
@@ -23,7 +23,7 @@ export default {
|
|
|
23
23
|
create(context) {
|
|
24
24
|
const options = context.options[0] || {};
|
|
25
25
|
const maxLines = options.maxLines || 2;
|
|
26
|
-
const sourceCode = context.sourceCode
|
|
26
|
+
const sourceCode = context.sourceCode;
|
|
27
27
|
|
|
28
28
|
function checkComment(comment) {
|
|
29
29
|
if (comment.type !== "Block" || !comment.value.startsWith("*")) {
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
},
|
|
13
13
|
|
|
14
14
|
create: function(context) {
|
|
15
|
-
const sourceCode = context.sourceCode
|
|
15
|
+
const sourceCode = context.sourceCode;
|
|
16
16
|
|
|
17
17
|
function checkNodeForJSDoc(node) {
|
|
18
18
|
const comments = sourceCode.getCommentsBefore(node);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import getJSDocComment from "./utils/get-jsdoc-comment.js";
|
|
2
|
+
|
|
1
3
|
export default {
|
|
2
4
|
meta: {
|
|
3
5
|
type: "suggestion",
|
|
@@ -9,9 +11,11 @@ export default {
|
|
|
9
11
|
},
|
|
10
12
|
|
|
11
13
|
create(context) {
|
|
14
|
+
const sourceCode = context.sourceCode;
|
|
15
|
+
|
|
12
16
|
return {
|
|
13
17
|
ClassDeclaration(node) {
|
|
14
|
-
const jsdoc =
|
|
18
|
+
const jsdoc = getJSDocComment(sourceCode, node);
|
|
15
19
|
|
|
16
20
|
if (jsdoc) {
|
|
17
21
|
const hasClassdesc = /@classdesc/.test(jsdoc.value);
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
},
|
|
19
19
|
|
|
20
20
|
create(context) {
|
|
21
|
-
const sourceCode = context.sourceCode
|
|
21
|
+
const sourceCode = context.sourceCode;
|
|
22
22
|
|
|
23
23
|
function checkComment(comment) {
|
|
24
24
|
if (comment.type !== "Block" || !comment.value.startsWith("*")) {
|
package/rules/methods-naming.js
CHANGED
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
create: function(context) {
|
|
13
13
|
return {
|
|
14
14
|
MethodDefinition: function(node) {
|
|
15
|
-
const sourceCode = context.
|
|
15
|
+
const sourceCode = context.sourceCode;
|
|
16
16
|
const commentsBefore = sourceCode.getCommentsBefore(node);
|
|
17
17
|
|
|
18
18
|
const jsDocComment = commentsBefore.find(comment =>
|
|
@@ -6,7 +6,7 @@ const SECTION_COMMENT_PATTERN = /--> (.*) <--/;
|
|
|
6
6
|
export default {
|
|
7
7
|
create(context) {
|
|
8
8
|
let methodOrder = []; // Keep track of method order
|
|
9
|
-
const sourceCode = context.sourceCode
|
|
9
|
+
const sourceCode = context.sourceCode;
|
|
10
10
|
|
|
11
11
|
return {
|
|
12
12
|
MethodDefinition(node) {
|
|
@@ -6,7 +6,9 @@ function getTokensWithNewlineBetween(sourceCode, startNode, endNode) {
|
|
|
6
6
|
|
|
7
7
|
do {
|
|
8
8
|
previous = next;
|
|
9
|
-
next = sourceCode.
|
|
9
|
+
next = sourceCode.getTokenAfter(next, {
|
|
10
|
+
includeComments: true
|
|
11
|
+
});
|
|
10
12
|
|
|
11
13
|
if (next.loc.start.line > previous.loc.end.line + 1) {
|
|
12
14
|
return [previous, next];
|
|
@@ -24,7 +26,7 @@ export default {
|
|
|
24
26
|
|
|
25
27
|
create: function newlineBetweenSwitchCase(context) {
|
|
26
28
|
let currentCodePath = null;
|
|
27
|
-
const sourceCode = context.
|
|
29
|
+
const sourceCode = context.sourceCode;
|
|
28
30
|
|
|
29
31
|
return {
|
|
30
32
|
onCodePathStart(codePath) {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
"FunctionDeclaration, FunctionExpression, ArrowFunctionExpression, MethodDefinition": function(node) {
|
|
5
5
|
(node.params || []).forEach(param => {
|
|
6
6
|
if (param.type === "AssignmentPattern") {
|
|
7
|
-
const sourceCode = context.sourceCode
|
|
7
|
+
const sourceCode = context.sourceCode;
|
|
8
8
|
const operatorToken = sourceCode.getFirstTokenBetween(param.left, param.right, token => token.value === "=");
|
|
9
9
|
|
|
10
10
|
if (
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
create(context) {
|
|
12
12
|
return {
|
|
13
13
|
'MethodDefinition[kind!="constructor"] > FunctionExpression > BlockStatement': function(node) {
|
|
14
|
-
const regexes = context.
|
|
14
|
+
const regexes = context.sourceCode.getTokens(node).filter(token => token.type === "RegularExpression");
|
|
15
15
|
|
|
16
16
|
if (regexes.length > 0) {
|
|
17
17
|
context.report({
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
return {
|
|
14
14
|
ConditionalExpression(node) {
|
|
15
15
|
if (node.test.type === "BinaryExpression" || node.test.type === "LogicalExpression") {
|
|
16
|
-
const sourceCode = context.
|
|
16
|
+
const sourceCode = context.sourceCode;
|
|
17
17
|
const beforeOperatorToken = sourceCode.getTokenBefore(node.test);
|
|
18
18
|
const afterOperatorToken = sourceCode.getTokenAfter(node.test);
|
|
19
19
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
function findJSDocComment(sourceCode, node) {
|
|
2
|
+
const comments = sourceCode.getCommentsBefore(node);
|
|
3
|
+
const comment = comments.at(-1);
|
|
4
|
+
|
|
5
|
+
if (
|
|
6
|
+
!comment ||
|
|
7
|
+
comment.type !== "Block" ||
|
|
8
|
+
!comment.value.startsWith("*") ||
|
|
9
|
+
node.loc.start.line - comment.loc.end.line > 1
|
|
10
|
+
) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const tokenBefore = sourceCode.getTokenBefore(node, {
|
|
15
|
+
includeComments: true
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return tokenBefore === comment ? comment : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function getJSDocComment(sourceCode, node) {
|
|
22
|
+
let parent = node.parent;
|
|
23
|
+
|
|
24
|
+
switch (node.type) {
|
|
25
|
+
case "ClassDeclaration":
|
|
26
|
+
case "FunctionDeclaration":
|
|
27
|
+
if (
|
|
28
|
+
parent?.type === "ExportDefaultDeclaration" ||
|
|
29
|
+
parent?.type === "ExportNamedDeclaration"
|
|
30
|
+
) {
|
|
31
|
+
return findJSDocComment(sourceCode, parent);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return findJSDocComment(sourceCode, node);
|
|
35
|
+
|
|
36
|
+
case "ClassExpression":
|
|
37
|
+
return findJSDocComment(sourceCode, parent.parent);
|
|
38
|
+
|
|
39
|
+
case "ArrowFunctionExpression":
|
|
40
|
+
case "FunctionExpression":
|
|
41
|
+
if (
|
|
42
|
+
parent.type !== "CallExpression" &&
|
|
43
|
+
parent.type !== "NewExpression"
|
|
44
|
+
) {
|
|
45
|
+
while (
|
|
46
|
+
!sourceCode.getCommentsBefore(parent).length &&
|
|
47
|
+
!/Function/u.test(parent.type) &&
|
|
48
|
+
parent.type !== "MethodDefinition" &&
|
|
49
|
+
parent.type !== "Property"
|
|
50
|
+
) {
|
|
51
|
+
parent = parent.parent;
|
|
52
|
+
|
|
53
|
+
if (!parent) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (
|
|
59
|
+
parent &&
|
|
60
|
+
parent.type !== "FunctionDeclaration" &&
|
|
61
|
+
parent.type !== "Program"
|
|
62
|
+
) {
|
|
63
|
+
return findJSDocComment(sourceCode, parent);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return findJSDocComment(sourceCode, node);
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -15,7 +15,7 @@ export default {
|
|
|
15
15
|
create(context) {
|
|
16
16
|
return utils.default.defineTemplateBodyVisitor(context, {
|
|
17
17
|
"VAttribute"(node) {
|
|
18
|
-
const sourceCode = context.
|
|
18
|
+
const sourceCode = context.sourceCode;
|
|
19
19
|
const attributeText = sourceCode.getText(node);
|
|
20
20
|
const attributeEndIndex = node.range[1];
|
|
21
21
|
const nextChar = sourceCode.getText().slice(attributeEndIndex, attributeEndIndex + 1);
|
|
@@ -43,7 +43,7 @@ export default {
|
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
create(context) {
|
|
46
|
-
const sourceCode = context.
|
|
46
|
+
const sourceCode = context.sourceCode;
|
|
47
47
|
|
|
48
48
|
// Reports attributes declared after the class attribute they should precede
|
|
49
49
|
function reportAttributesAfter(attributes, classIndex, className, isMisplaced) {
|
|
@@ -38,7 +38,7 @@ export default {
|
|
|
38
38
|
},
|
|
39
39
|
|
|
40
40
|
create(context) {
|
|
41
|
-
const sourceCode = context.
|
|
41
|
+
const sourceCode = context.sourceCode;
|
|
42
42
|
const maxLength = context.options[0]?.max ?? DEFAULT_MAX_LENGTH;
|
|
43
43
|
|
|
44
44
|
return utils.default.defineTemplateBodyVisitor(context, {
|
|
@@ -29,7 +29,7 @@ export default {
|
|
|
29
29
|
message: "Computed properties should be in alphabetical order.",
|
|
30
30
|
|
|
31
31
|
fix(fixer) {
|
|
32
|
-
const sourceCode = context.
|
|
32
|
+
const sourceCode = context.sourceCode;
|
|
33
33
|
const propertyText = sourceCode.getText(property);
|
|
34
34
|
const nextPropertyText = sourceCode.getText(nextProperty);
|
|
35
35
|
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
create(context) {
|
|
14
|
-
const fileName =
|
|
14
|
+
const fileName = context.filename.replace(/\\/g, "/");
|
|
15
15
|
|
|
16
16
|
if (fileName.endsWith("/index.js") || !isVueComponentOrMixin(fileName)) {
|
|
17
17
|
return {};
|
|
@@ -68,7 +68,7 @@ function buildFixes(fixer, context, exportNode) {
|
|
|
68
68
|
return null;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const sourceCode = context.sourceCode
|
|
71
|
+
const sourceCode = context.sourceCode;
|
|
72
72
|
const importFix = buildDefineComponentImportFix(fixer, sourceCode);
|
|
73
73
|
|
|
74
74
|
if (importFix === false) {
|
package/rules/vue-emits-order.js
CHANGED
|
@@ -23,7 +23,7 @@ export default {
|
|
|
23
23
|
message: "Emits should be in alphabetical order.",
|
|
24
24
|
|
|
25
25
|
fix(fixer) {
|
|
26
|
-
const sourceCode = context.
|
|
26
|
+
const sourceCode = context.sourceCode;
|
|
27
27
|
const elementText = sourceCode.getText(element);
|
|
28
28
|
const nextElementText = sourceCode.getText(nextElement);
|
|
29
29
|
|
|
@@ -15,7 +15,7 @@ export default {
|
|
|
15
15
|
create(context) {
|
|
16
16
|
return {
|
|
17
17
|
Program(node) {
|
|
18
|
-
const fileName = context.physicalFilename || context.filename
|
|
18
|
+
const fileName = context.physicalFilename || context.filename;
|
|
19
19
|
|
|
20
20
|
// Determine the file extension
|
|
21
21
|
const fileExtension = path.extname(fileName);
|
package/rules/vue-html-indent.js
CHANGED
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
},
|
|
13
13
|
|
|
14
14
|
create(context) {
|
|
15
|
-
const sourceCode = context.
|
|
15
|
+
const sourceCode = context.sourceCode
|
|
16
16
|
const template = (
|
|
17
17
|
sourceCode.parserServices.getTemplateBodyTokenStore &&
|
|
18
18
|
sourceCode.parserServices.getTemplateBodyTokenStore()
|
package/rules/vue-html-quotes.js
CHANGED
|
@@ -26,7 +26,7 @@ export default {
|
|
|
26
26
|
},
|
|
27
27
|
|
|
28
28
|
create(context) {
|
|
29
|
-
const sourceCode = context.
|
|
29
|
+
const sourceCode = context.sourceCode
|
|
30
30
|
const double = context.options[0] !== "single"
|
|
31
31
|
const avoidEscape =
|
|
32
32
|
context.options[1] && context.options[1].avoidEscape === true
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import utils from "eslint-plugin-vue/dist/utils/index.js";
|
|
2
|
+
|
|
3
|
+
const CLASS_SHORTHAND_PATTERN = /\.[A-Za-z_][\w-]*/;
|
|
4
|
+
|
|
5
|
+
// Checks whether a Pug element name belongs to a Vue component
|
|
6
|
+
function isComponent(node) {
|
|
7
|
+
return node.name.includes("-") || /^[A-Z]/.test(node.rawName);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Checks whether an attribute is a class attribute
|
|
11
|
+
function isClassAttribute(attribute) {
|
|
12
|
+
if (attribute.directive === false) {
|
|
13
|
+
return attribute.key.name === "class";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
attribute.key.name.name === "bind" &&
|
|
18
|
+
attribute.key.argument !== null &&
|
|
19
|
+
attribute.key.argument.type === "VIdentifier" &&
|
|
20
|
+
attribute.key.argument.name === "class"
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
meta: {
|
|
26
|
+
type: "suggestion",
|
|
27
|
+
docs: {
|
|
28
|
+
description: "disallow mixing Pug class shorthand and class attributes",
|
|
29
|
+
category: "Stylistic Issues",
|
|
30
|
+
recommended: false,
|
|
31
|
+
},
|
|
32
|
+
fixable: null,
|
|
33
|
+
schema: [], // no options
|
|
34
|
+
messages: {
|
|
35
|
+
useClassAttribute:
|
|
36
|
+
"Move all Pug class shorthands to the class attribute.",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
create(context) {
|
|
41
|
+
const sourceCode = context.sourceCode;
|
|
42
|
+
|
|
43
|
+
return utils.default.defineTemplateBodyVisitor(context, {
|
|
44
|
+
VElement(node) {
|
|
45
|
+
if (isComponent(node)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const startTagText = sourceCode.getText(node.startTag);
|
|
50
|
+
const elementHead = startTagText.split(/[\s(]/, 1)[0];
|
|
51
|
+
const classAttribute = node.startTag.attributes.find(isClassAttribute);
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
classAttribute &&
|
|
55
|
+
CLASS_SHORTHAND_PATTERN.test(elementHead)
|
|
56
|
+
) {
|
|
57
|
+
context.report({
|
|
58
|
+
node: classAttribute,
|
|
59
|
+
messageId: "useClassAttribute",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
create(context) {
|
|
14
|
-
const fileName =
|
|
14
|
+
const fileName = context.filename.replace(/\\/g, "/");
|
|
15
15
|
|
|
16
16
|
if (!fileName.endsWith(".vue")) {
|
|
17
17
|
return {};
|
|
@@ -87,7 +87,7 @@ function isNameProperty(property) {
|
|
|
87
87
|
|
|
88
88
|
// Removes a property and its adjacent comma
|
|
89
89
|
function removeProperty(fixer, context, options, property) {
|
|
90
|
-
const sourceCode = context.sourceCode
|
|
90
|
+
const sourceCode = context.sourceCode;
|
|
91
91
|
const nextToken = sourceCode.getTokenAfter(property);
|
|
92
92
|
|
|
93
93
|
if (nextToken?.value === ",") {
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
create(context) {
|
|
14
|
-
const sourceCode = context.
|
|
14
|
+
const sourceCode = context.sourceCode;
|
|
15
15
|
|
|
16
16
|
function checkPropDefinition(propNode) {
|
|
17
17
|
const typeProperty = propNode.properties.find(p => p.key.name === "type");
|
|
@@ -25,7 +25,7 @@ export default {
|
|
|
25
25
|
message: "Props should be declared in multiple lines.",
|
|
26
26
|
|
|
27
27
|
fix(fixer) {
|
|
28
|
-
const sourceCode = context.
|
|
28
|
+
const sourceCode = context.sourceCode;
|
|
29
29
|
const propText = sourceCode.getText(propDefinition);
|
|
30
30
|
|
|
31
31
|
// Construct the multi-line version of the prop
|
|
@@ -23,7 +23,7 @@ export default {
|
|
|
23
23
|
message: "Props should be in alphabetical order.",
|
|
24
24
|
|
|
25
25
|
fix(fixer) {
|
|
26
|
-
const sourceCode = context.
|
|
26
|
+
const sourceCode = context.sourceCode;
|
|
27
27
|
const propertyText = sourceCode.getText(property);
|
|
28
28
|
const nextPropertyText = sourceCode.getText(nextProperty);
|
|
29
29
|
|
|
@@ -6,8 +6,11 @@ const ruleTester = createRuleTester();
|
|
|
6
6
|
ruleTester.run("jsdoc-check-optional-params", rule, {
|
|
7
7
|
valid: [
|
|
8
8
|
"/** @param {string} value */\nfunction required(value) {}",
|
|
9
|
+
"/** @param {string} value */\nexport function required(value) {}",
|
|
9
10
|
"/** @param {string} [value] */\nfunction optional(value = \"default\") {}",
|
|
10
11
|
"/** @param {number} [count=1] */\nconst optional = function(count = 1) {};",
|
|
12
|
+
"/* @param {string} value */\nfunction optional(value = \"default\") {}",
|
|
13
|
+
"/** @param {string} value */\nconst unrelated = true;\nfunction optional(value = \"default\") {}",
|
|
11
14
|
"function undocumented(value) {}"
|
|
12
15
|
],
|
|
13
16
|
|
|
@@ -20,6 +23,14 @@ ruleTester.run("jsdoc-check-optional-params", rule, {
|
|
|
20
23
|
}
|
|
21
24
|
]
|
|
22
25
|
},
|
|
26
|
+
{
|
|
27
|
+
code: "/** @param {string} value */\nexport function optional(value = \"default\") {}",
|
|
28
|
+
errors: [
|
|
29
|
+
{
|
|
30
|
+
message: "Optional parameters in JSDoc should be surrounded by brackets"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
23
34
|
{
|
|
24
35
|
code: "/** @param {string} [value] */\nfunction required(value) {}",
|
|
25
36
|
errors: [
|
|
@@ -6,7 +6,10 @@ const ruleTester = createRuleTester();
|
|
|
6
6
|
ruleTester.run("jsdoc-enforce-classdesc", rule, {
|
|
7
7
|
valid: [
|
|
8
8
|
"/**\n * @classdesc Represents an example.\n */\nclass Example {}",
|
|
9
|
+
"/**\n * @classdesc Represents an example.\n */\nexport default class Example {}",
|
|
9
10
|
"class Undocumented {}",
|
|
11
|
+
"/* Represents an example. */\nclass Example {}",
|
|
12
|
+
"/** Represents an unrelated value. */\nconst value = 1;\nclass Example {}",
|
|
10
13
|
"/** A factory function. */\nfunction createExample() {}"
|
|
11
14
|
],
|
|
12
15
|
|
|
@@ -19,6 +22,14 @@ ruleTester.run("jsdoc-enforce-classdesc", rule, {
|
|
|
19
22
|
}
|
|
20
23
|
]
|
|
21
24
|
},
|
|
25
|
+
{
|
|
26
|
+
code: "/** Represents an example. */\nexport class Example {}",
|
|
27
|
+
errors: [
|
|
28
|
+
{
|
|
29
|
+
message: "JSDoc class header should include @classdesc"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
22
33
|
{
|
|
23
34
|
code: "/**\n * @classdesc\n */\nclass Example {}",
|
|
24
35
|
errors: [
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import rule from "../../rules/vue-no-mixed-class-shorthand.js";
|
|
2
|
+
import { createPugRuleTester } from "../rule-tester.js";
|
|
3
|
+
|
|
4
|
+
const ruleTester = createPugRuleTester();
|
|
5
|
+
const filename = "TestComponent.vue";
|
|
6
|
+
|
|
7
|
+
ruleTester.run("vue-no-mixed-class-shorthand", rule, {
|
|
8
|
+
valid: [
|
|
9
|
+
{
|
|
10
|
+
filename,
|
|
11
|
+
code: `<template lang="pug">
|
|
12
|
+
.panel
|
|
13
|
+
div(:class="classes")
|
|
14
|
+
div(class="panel")
|
|
15
|
+
</template>`
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
filename,
|
|
19
|
+
code: `<template lang="pug">
|
|
20
|
+
UserCard.panel(:class="classes")
|
|
21
|
+
user-card.panel(class="card")
|
|
22
|
+
</template>`
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
|
|
26
|
+
invalid: [
|
|
27
|
+
{
|
|
28
|
+
filename,
|
|
29
|
+
code: `<template lang="pug">
|
|
30
|
+
.c-conversation-box-content-message-controls__action(
|
|
31
|
+
@click="onActionTranscribeClick"
|
|
32
|
+
:class="\`js-audio-transcription-action-\${fingerprint}\`"
|
|
33
|
+
)
|
|
34
|
+
</template>`,
|
|
35
|
+
errors: [
|
|
36
|
+
{
|
|
37
|
+
messageId: "useClassAttribute"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
filename,
|
|
43
|
+
code: `<template lang="pug">
|
|
44
|
+
div.panel(class="active")
|
|
45
|
+
section#details.panel(v-bind:class="classes")
|
|
46
|
+
</template>`,
|
|
47
|
+
errors: [
|
|
48
|
+
{
|
|
49
|
+
messageId: "useClassAttribute"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
messageId: "useClassAttribute"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
});
|