eslint-plugin-svelte 2.13.0 → 2.14.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/README.md +2 -0
- package/lib/rules/indent-helpers/ast.d.ts +1 -1
- package/lib/rules/indent-helpers/commons.d.ts +4 -4
- package/lib/rules/indent-helpers/es.d.ts +1 -1
- package/lib/rules/indent-helpers/es.js +11 -5
- package/lib/rules/indent-helpers/offset-context.d.ts +1 -1
- package/lib/rules/indent-helpers/svelte.d.ts +1 -1
- package/lib/rules/indent-helpers/ts.d.ts +1 -1
- package/lib/rules/indent-helpers/ts.js +40 -5
- package/lib/rules/no-dupe-on-directives.d.ts +2 -0
- package/lib/rules/no-dupe-on-directives.js +72 -0
- package/lib/rules/no-dupe-use-directives.d.ts +2 -0
- package/lib/rules/no-dupe-use-directives.js +73 -0
- package/lib/rules/reference-helpers/svelte-store.d.ts +2 -2
- package/lib/rules/sort-attributes.js +1 -1
- package/lib/shared/comment-directives.d.ts +1 -1
- package/lib/shared/svelte-compile-warns/ignore-comment.d.ts +2 -2
- package/lib/shared/svelte-compile-warns/index.d.ts +3 -3
- package/lib/shared/svelte-compile-warns/transform/types.d.ts +1 -1
- package/lib/types-for-node.d.ts +12 -6
- package/lib/types.d.ts +8 -8
- package/lib/utils/ast-utils.d.ts +2 -2
- package/lib/utils/ast-utils.js +16 -13
- package/lib/utils/css-utils/style-attribute.d.ts +2 -2
- package/lib/utils/css-utils/template-tokenize.d.ts +1 -1
- package/lib/utils/get-package-json.d.ts +1 -1
- package/lib/utils/rules.js +4 -0
- package/lib/utils/ts-utils/index.d.ts +2 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -300,7 +300,9 @@ These rules relate to possible syntax or logic errors in Svelte code:
|
|
|
300
300
|
|:--------|:------------|:---|
|
|
301
301
|
| [svelte/no-dom-manipulating](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/) | disallow DOM manipulating | |
|
|
302
302
|
| [svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
|
|
303
|
+
| [svelte/no-dupe-on-directives](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-on-directives/) | disallow duplicate `on:` directives | |
|
|
303
304
|
| [svelte/no-dupe-style-properties](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-style-properties/) | disallow duplicate style properties | :star: |
|
|
305
|
+
| [svelte/no-dupe-use-directives](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-use-directives/) | disallow duplicate `use:` directives | |
|
|
304
306
|
| [svelte/no-dynamic-slot-name](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dynamic-slot-name/) | disallow dynamic slot name | :star::wrench: |
|
|
305
307
|
| [svelte/no-export-load-in-svelte-module-in-kit-pages](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-export-load-in-svelte-module-in-kit-pages/) | disallow exporting load functions in `*.svelte` module in Svelte Kit page components. | |
|
|
306
308
|
| [svelte/no-not-function-handler](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-not-function-handler/) | disallow use of not function in event handler | :star: |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
3
|
-
|
|
3
|
+
type AnyToken = AST.Token | AST.Comment;
|
|
4
4
|
export declare function isWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
5
5
|
export declare function isNotWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
6
6
|
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { ASTNode, SourceCode } from "../../types";
|
|
2
2
|
import type { AST } from "svelte-eslint-parser";
|
|
3
3
|
import type { OffsetContext } from "./offset-context";
|
|
4
|
-
export
|
|
5
|
-
export
|
|
4
|
+
export type AnyToken = AST.Token | AST.Comment;
|
|
5
|
+
export type MaybeNode = {
|
|
6
6
|
type: string;
|
|
7
7
|
range: [number, number];
|
|
8
8
|
loc: AST.SourceLocation;
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type IndentOptions = {
|
|
11
11
|
indentChar: " " | "\t";
|
|
12
12
|
indentScript: boolean;
|
|
13
13
|
indentSize: number;
|
|
@@ -15,7 +15,7 @@ export declare type IndentOptions = {
|
|
|
15
15
|
alignAttributesVertically: boolean;
|
|
16
16
|
ignoredNodes: string[];
|
|
17
17
|
};
|
|
18
|
-
export
|
|
18
|
+
export type IndentContext = {
|
|
19
19
|
sourceCode: SourceCode;
|
|
20
20
|
options: IndentOptions;
|
|
21
21
|
offsets: OffsetContext;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IndentContext } from "./commons";
|
|
2
2
|
import type { ESNodeListener } from "../../types-for-node";
|
|
3
|
-
|
|
3
|
+
type NodeListener = ESNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -111,12 +111,15 @@ function defineVisitor(context) {
|
|
|
111
111
|
},
|
|
112
112
|
CallExpression(node) {
|
|
113
113
|
const firstToken = sourceCode.getFirstToken(node);
|
|
114
|
-
const leftParenToken = sourceCode.getTokenAfter(node.callee, {
|
|
114
|
+
const leftParenToken = sourceCode.getTokenAfter(node.typeParameters || node.callee, {
|
|
115
115
|
filter: eslint_utils_1.isOpeningParenToken,
|
|
116
116
|
includeComments: false,
|
|
117
117
|
});
|
|
118
118
|
const rightParenToken = sourceCode.getLastToken(node);
|
|
119
|
-
|
|
119
|
+
if (node.typeParameters) {
|
|
120
|
+
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
|
|
121
|
+
}
|
|
122
|
+
for (const optionalToken of sourceCode.getTokensBetween(sourceCode.getLastToken(node.typeParameters || node.callee), leftParenToken, { filter: isOptionalToken, includeComments: false })) {
|
|
120
123
|
offsets.setOffsetToken(optionalToken, 1, firstToken);
|
|
121
124
|
}
|
|
122
125
|
offsets.setOffsetToken(leftParenToken, 1, firstToken);
|
|
@@ -543,10 +546,13 @@ function defineVisitor(context) {
|
|
|
543
546
|
const newToken = sourceCode.getFirstToken(node);
|
|
544
547
|
const calleeTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.callee);
|
|
545
548
|
offsets.setOffsetToken(calleeTokens.firstToken, 1, newToken);
|
|
546
|
-
if (node.
|
|
547
|
-
|
|
549
|
+
if (node.typeParameters) {
|
|
550
|
+
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, calleeTokens.firstToken);
|
|
551
|
+
}
|
|
552
|
+
const leftParenBefore = node.typeParameters || calleeTokens.lastToken;
|
|
553
|
+
if (node.arguments.length || leftParenBefore.range[1] < node.range[1]) {
|
|
548
554
|
const rightParenToken = sourceCode.getLastToken(node);
|
|
549
|
-
const leftParenToken = sourceCode.getTokenAfter(
|
|
555
|
+
const leftParenToken = sourceCode.getTokenAfter(leftParenBefore);
|
|
550
556
|
offsets.setOffsetToken(leftParenToken, 1, calleeTokens.firstToken);
|
|
551
557
|
offsets.setOffsetElementList(node.arguments, leftParenToken, rightParenToken, 1);
|
|
552
558
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SvelteNodeListener } from "../../types-for-node";
|
|
2
2
|
import type { IndentContext } from "./commons";
|
|
3
|
-
|
|
3
|
+
type NodeListener = SvelteNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IndentContext } from "./commons";
|
|
2
2
|
import type { TSNodeListener } from "../../types-for-node";
|
|
3
|
-
|
|
3
|
+
type NodeListener = TSNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -21,18 +21,24 @@ function defineVisitor(context) {
|
|
|
21
21
|
},
|
|
22
22
|
TSAsExpression(node) {
|
|
23
23
|
const expressionTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression);
|
|
24
|
-
const
|
|
24
|
+
const asOrSatisfiesToken = sourceCode.getTokenAfter(expressionTokens.lastToken);
|
|
25
25
|
offsets.setOffsetToken([
|
|
26
|
-
|
|
26
|
+
asOrSatisfiesToken,
|
|
27
27
|
(0, commons_2.getFirstAndLastTokens)(sourceCode, node.typeAnnotation).firstToken,
|
|
28
28
|
], 1, expressionTokens.firstToken);
|
|
29
29
|
},
|
|
30
|
+
TSSatisfiesExpression(node) {
|
|
31
|
+
visitor.TSAsExpression(node);
|
|
32
|
+
},
|
|
30
33
|
TSTypeReference(node) {
|
|
31
34
|
if (node.typeParameters) {
|
|
32
|
-
const
|
|
33
|
-
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1,
|
|
35
|
+
const firstToken = sourceCode.getFirstToken(node);
|
|
36
|
+
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
|
|
34
37
|
}
|
|
35
38
|
},
|
|
39
|
+
TSInstantiationExpression(node) {
|
|
40
|
+
visitor.TSTypeReference(node);
|
|
41
|
+
},
|
|
36
42
|
TSTypeParameterInstantiation(node) {
|
|
37
43
|
offsets.setOffsetElementList(node.params, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
|
|
38
44
|
},
|
|
@@ -433,6 +439,9 @@ function defineVisitor(context) {
|
|
|
433
439
|
TSEnumMember(node) {
|
|
434
440
|
visitor.TSAbstractMethodDefinition(node);
|
|
435
441
|
},
|
|
442
|
+
TSAbstractAccessorProperty(node) {
|
|
443
|
+
visitor.TSAbstractMethodDefinition(node);
|
|
444
|
+
},
|
|
436
445
|
TSOptionalType(node) {
|
|
437
446
|
offsets.setOffsetToken(sourceCode.getLastToken(node), 1, sourceCode.getFirstToken(node));
|
|
438
447
|
},
|
|
@@ -559,6 +568,32 @@ function defineVisitor(context) {
|
|
|
559
568
|
offsets.setOffsetToken(atToken, 0, sourceCode.getFirstToken(decorators[0]));
|
|
560
569
|
}
|
|
561
570
|
},
|
|
571
|
+
AccessorProperty(node) {
|
|
572
|
+
const keyNode = node.key;
|
|
573
|
+
const valueNode = node.value;
|
|
574
|
+
const firstToken = sourceCode.getFirstToken(node);
|
|
575
|
+
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, keyNode);
|
|
576
|
+
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
|
|
577
|
+
if (node.computed) {
|
|
578
|
+
prefixTokens.pop();
|
|
579
|
+
}
|
|
580
|
+
offsets.setOffsetToken(prefixTokens, 0, firstToken);
|
|
581
|
+
let lastKeyToken;
|
|
582
|
+
if (node.computed) {
|
|
583
|
+
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
|
|
584
|
+
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
|
|
585
|
+
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
|
|
586
|
+
offsets.setOffsetElementList([keyNode], leftBracketToken, rightBracketToken, 1);
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
|
|
590
|
+
lastKeyToken = keyTokens.lastToken;
|
|
591
|
+
}
|
|
592
|
+
if (valueNode != null) {
|
|
593
|
+
const initToken = sourceCode.getFirstToken(valueNode);
|
|
594
|
+
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
|
|
595
|
+
}
|
|
596
|
+
},
|
|
562
597
|
StaticBlock(node) {
|
|
563
598
|
const firstToken = sourceCode.getFirstToken(node);
|
|
564
599
|
let next = sourceCode.getTokenAfter(firstToken);
|
|
@@ -632,7 +667,7 @@ function defineVisitor(context) {
|
|
|
632
667
|
};
|
|
633
668
|
const commonsVisitor = {
|
|
634
669
|
["TSTypeAliasDeclaration, TSCallSignatureDeclaration, TSConstructSignatureDeclaration, TSImportEqualsDeclaration," +
|
|
635
|
-
"TSAbstractMethodDefinition, TSAbstractPropertyDefinition, TSEnumMember," +
|
|
670
|
+
"TSAbstractMethodDefinition, TSAbstractPropertyDefinition, AccessorProperty, TSAbstractAccessorProperty, TSEnumMember," +
|
|
636
671
|
"TSPropertySignature, TSIndexSignature, TSMethodSignature," +
|
|
637
672
|
"TSAbstractClassProperty, ClassProperty"](node) {
|
|
638
673
|
const firstToken = sourceCode.getFirstToken(node);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const ast_utils_1 = require("../utils/ast-utils");
|
|
5
|
+
exports.default = (0, utils_1.createRule)("no-dupe-on-directives", {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
description: "disallow duplicate `on:` directives",
|
|
9
|
+
category: "Possible Errors",
|
|
10
|
+
recommended: false,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
duplication: "This `on:{{type}}` directive is the same and duplicate directives in L{{lineNo}}.",
|
|
15
|
+
},
|
|
16
|
+
type: "problem",
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
const sourceCode = context.getSourceCode();
|
|
20
|
+
const directiveDataMap = new Map();
|
|
21
|
+
return {
|
|
22
|
+
SvelteDirective(node) {
|
|
23
|
+
if (node.kind !== "EventHandler")
|
|
24
|
+
return;
|
|
25
|
+
const directiveDataList = directiveDataMap.get(node.key.name.name);
|
|
26
|
+
if (!directiveDataList) {
|
|
27
|
+
directiveDataMap.set(node.key.name.name, [
|
|
28
|
+
{
|
|
29
|
+
expression: node.expression,
|
|
30
|
+
nodes: [node],
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const directiveData = directiveDataList.find((data) => {
|
|
36
|
+
if (!data.expression || !node.expression) {
|
|
37
|
+
return data.expression === node.expression;
|
|
38
|
+
}
|
|
39
|
+
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
|
|
40
|
+
});
|
|
41
|
+
if (!directiveData) {
|
|
42
|
+
directiveDataList.push({
|
|
43
|
+
expression: node.expression,
|
|
44
|
+
nodes: [node],
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
directiveData.nodes.push(node);
|
|
49
|
+
},
|
|
50
|
+
"SvelteStartTag:exit"() {
|
|
51
|
+
for (const [type, directiveDataList] of directiveDataMap) {
|
|
52
|
+
for (const { nodes } of directiveDataList) {
|
|
53
|
+
if (nodes.length < 2) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (const node of nodes) {
|
|
57
|
+
context.report({
|
|
58
|
+
node,
|
|
59
|
+
messageId: "duplication",
|
|
60
|
+
data: {
|
|
61
|
+
type,
|
|
62
|
+
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line),
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
directiveDataMap.clear();
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const ast_utils_1 = require("../utils/ast-utils");
|
|
5
|
+
exports.default = (0, utils_1.createRule)("no-dupe-use-directives", {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
description: "disallow duplicate `use:` directives",
|
|
9
|
+
category: "Possible Errors",
|
|
10
|
+
recommended: false,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
duplication: "This `{{keyText}}` directive is the same and duplicate directives in L{{lineNo}}.",
|
|
15
|
+
},
|
|
16
|
+
type: "problem",
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
const sourceCode = context.getSourceCode();
|
|
20
|
+
const directiveDataMap = new Map();
|
|
21
|
+
return {
|
|
22
|
+
SvelteDirective(node) {
|
|
23
|
+
if (node.kind !== "Action")
|
|
24
|
+
return;
|
|
25
|
+
const keyText = (0, ast_utils_1.getAttributeKeyText)(node, context);
|
|
26
|
+
const directiveDataList = directiveDataMap.get(keyText);
|
|
27
|
+
if (!directiveDataList) {
|
|
28
|
+
directiveDataMap.set(keyText, [
|
|
29
|
+
{
|
|
30
|
+
expression: node.expression,
|
|
31
|
+
nodes: [node],
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const directiveData = directiveDataList.find((data) => {
|
|
37
|
+
if (!data.expression || !node.expression) {
|
|
38
|
+
return data.expression === node.expression;
|
|
39
|
+
}
|
|
40
|
+
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
|
|
41
|
+
});
|
|
42
|
+
if (!directiveData) {
|
|
43
|
+
directiveDataList.push({
|
|
44
|
+
expression: node.expression,
|
|
45
|
+
nodes: [node],
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
directiveData.nodes.push(node);
|
|
50
|
+
},
|
|
51
|
+
"SvelteStartTag:exit"() {
|
|
52
|
+
for (const [keyText, directiveDataList] of directiveDataMap) {
|
|
53
|
+
for (const { nodes } of directiveDataList) {
|
|
54
|
+
if (nodes.length < 2) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const node of nodes) {
|
|
58
|
+
context.report({
|
|
59
|
+
node,
|
|
60
|
+
messageId: "duplication",
|
|
61
|
+
data: {
|
|
62
|
+
keyText,
|
|
63
|
+
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
directiveDataMap.clear();
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
|
-
|
|
3
|
+
type StoreName = "writable" | "readable" | "derived";
|
|
4
4
|
export declare function extractStoreReferences(context: RuleContext, storeNames?: StoreName[]): Generator<{
|
|
5
5
|
node: TSESTree.CallExpression;
|
|
6
6
|
name: string;
|
|
7
7
|
}, void>;
|
|
8
|
-
export
|
|
8
|
+
export type StoreChecker = (node: TSESTree.Expression, options?: {
|
|
9
9
|
consistent?: boolean;
|
|
10
10
|
}) => boolean;
|
|
11
11
|
export declare function createStoreChecker(context: RuleContext): StoreChecker;
|
|
@@ -176,7 +176,7 @@ exports.default = (0, utils_1.createRule)("sort-attributes", {
|
|
|
176
176
|
const k = cacheKeyText.get(node);
|
|
177
177
|
if (k != null)
|
|
178
178
|
return k;
|
|
179
|
-
const result = (0, ast_utils_1.getAttributeKeyText)(node);
|
|
179
|
+
const result = (0, ast_utils_1.getAttributeKeyText)(node, context);
|
|
180
180
|
cacheKeyText.set(node, result);
|
|
181
181
|
return result;
|
|
182
182
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
|
-
export
|
|
3
|
+
export type IgnoreItemWithoutCode = {
|
|
4
4
|
range: [number, number];
|
|
5
5
|
code: null;
|
|
6
6
|
token: AST.Token | AST.Comment;
|
|
7
7
|
};
|
|
8
|
-
export
|
|
8
|
+
export type IgnoreItem = {
|
|
9
9
|
range: [number, number];
|
|
10
10
|
code: string;
|
|
11
11
|
token: AST.Token | AST.Comment;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
3
|
import type { IgnoreItem } from "./ignore-comment";
|
|
4
|
-
export
|
|
4
|
+
export type SvelteCompileWarnings = {
|
|
5
5
|
warnings: Warning[];
|
|
6
6
|
unusedIgnores: IgnoreItem[];
|
|
7
7
|
kind: "warn" | "error";
|
|
8
8
|
stripStyleElements: AST.SvelteStyleElement[];
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type Loc = {
|
|
11
11
|
start?: {
|
|
12
12
|
line: number;
|
|
13
13
|
column: number;
|
|
@@ -17,7 +17,7 @@ export declare type Loc = {
|
|
|
17
17
|
column: number;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
|
-
export
|
|
20
|
+
export type Warning = {
|
|
21
21
|
code?: string;
|
|
22
22
|
message: string;
|
|
23
23
|
} & Loc;
|
package/lib/types-for-node.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { TSESTree, AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
2
2
|
import type { AST } from "svelte-eslint-parser";
|
|
3
|
-
export
|
|
3
|
+
export type ASTNode = AST.SvelteNode | Exclude<Omit<TSESTree.Node, "parent">, {
|
|
4
4
|
type: AST.SvelteNode["type"];
|
|
5
5
|
}>;
|
|
6
|
-
export
|
|
6
|
+
export type ASTNodeWithParent = (Exclude<ASTNode, AST.SvelteProgram> & {
|
|
7
7
|
parent: ASTNodeWithParent;
|
|
8
8
|
}) | AST.SvelteProgram;
|
|
9
|
-
export
|
|
9
|
+
export type ASTNodeListener = {
|
|
10
|
+
AccessorProperty?: (node: TSESTree.AccessorProperty & ASTNodeWithParent) => void;
|
|
10
11
|
ArrayExpression?: (node: TSESTree.ArrayExpression & ASTNodeWithParent) => void;
|
|
11
12
|
ArrayPattern?: (node: TSESTree.ArrayPattern & ASTNodeWithParent) => void;
|
|
12
13
|
ArrowFunctionExpression?: (node: TSESTree.ArrowFunctionExpression & ASTNodeWithParent) => void;
|
|
@@ -94,6 +95,7 @@ export declare type ASTNodeListener = {
|
|
|
94
95
|
WhileStatement?: (node: TSESTree.WhileStatement & ASTNodeWithParent) => void;
|
|
95
96
|
WithStatement?: (node: TSESTree.WithStatement & ASTNodeWithParent) => void;
|
|
96
97
|
YieldExpression?: (node: TSESTree.YieldExpression & ASTNodeWithParent) => void;
|
|
98
|
+
TSAbstractAccessorProperty?: (node: TSESTree.TSAbstractAccessorProperty & ASTNodeWithParent) => void;
|
|
97
99
|
TSAbstractKeyword?: (node: TSESTree.TSAbstractKeyword & ASTNodeWithParent) => void;
|
|
98
100
|
TSAbstractMethodDefinition?: (node: TSESTree.TSAbstractMethodDefinition & ASTNodeWithParent) => void;
|
|
99
101
|
TSAbstractPropertyDefinition?: (node: TSESTree.TSAbstractPropertyDefinition & ASTNodeWithParent) => void;
|
|
@@ -151,6 +153,7 @@ export declare type ASTNodeListener = {
|
|
|
151
153
|
TSQualifiedName?: (node: TSESTree.TSQualifiedName & ASTNodeWithParent) => void;
|
|
152
154
|
TSReadonlyKeyword?: (node: TSESTree.TSReadonlyKeyword & ASTNodeWithParent) => void;
|
|
153
155
|
TSRestType?: (node: TSESTree.TSRestType & ASTNodeWithParent) => void;
|
|
156
|
+
TSSatisfiesExpression?: (node: TSESTree.TSSatisfiesExpression & ASTNodeWithParent) => void;
|
|
154
157
|
TSStaticKeyword?: (node: TSESTree.TSStaticKeyword & ASTNodeWithParent) => void;
|
|
155
158
|
TSStringKeyword?: (node: TSESTree.TSStringKeyword & ASTNodeWithParent) => void;
|
|
156
159
|
TSSymbolKeyword?: (node: TSESTree.TSSymbolKeyword & ASTNodeWithParent) => void;
|
|
@@ -204,7 +207,8 @@ export declare type ASTNodeListener = {
|
|
|
204
207
|
SvelteHTMLComment?: (node: AST.SvelteHTMLComment & ASTNodeWithParent) => void;
|
|
205
208
|
SvelteReactiveStatement?: (node: AST.SvelteReactiveStatement & ASTNodeWithParent) => void;
|
|
206
209
|
};
|
|
207
|
-
export
|
|
210
|
+
export type ESNodeListener = {
|
|
211
|
+
AccessorProperty?: (node: TSESTree.AccessorProperty & ASTNodeWithParent) => void;
|
|
208
212
|
ArrayExpression?: (node: TSESTree.ArrayExpression & ASTNodeWithParent) => void;
|
|
209
213
|
ArrayPattern?: (node: TSESTree.ArrayPattern & ASTNodeWithParent) => void;
|
|
210
214
|
ArrowFunctionExpression?: (node: TSESTree.ArrowFunctionExpression & ASTNodeWithParent) => void;
|
|
@@ -277,10 +281,11 @@ export declare type ESNodeListener = {
|
|
|
277
281
|
Program?: (node: AST.SvelteProgram & ASTNodeWithParent) => void;
|
|
278
282
|
SvelteReactiveStatement?: (node: AST.SvelteReactiveStatement & ASTNodeWithParent) => void;
|
|
279
283
|
};
|
|
280
|
-
export
|
|
284
|
+
export type TSNodeListener = {
|
|
281
285
|
Decorator?: (node: TSESTree.Decorator & ASTNodeWithParent) => void;
|
|
282
286
|
ImportAttribute?: (node: TSESTree.ImportAttribute & ASTNodeWithParent) => void;
|
|
283
287
|
StaticBlock?: (node: TSESTree.StaticBlock & ASTNodeWithParent) => void;
|
|
288
|
+
TSAbstractAccessorProperty?: (node: TSESTree.TSAbstractAccessorProperty & ASTNodeWithParent) => void;
|
|
284
289
|
TSAbstractKeyword?: (node: TSESTree.TSAbstractKeyword & ASTNodeWithParent) => void;
|
|
285
290
|
TSAbstractMethodDefinition?: (node: TSESTree.TSAbstractMethodDefinition & ASTNodeWithParent) => void;
|
|
286
291
|
TSAbstractPropertyDefinition?: (node: TSESTree.TSAbstractPropertyDefinition & ASTNodeWithParent) => void;
|
|
@@ -338,6 +343,7 @@ export declare type TSNodeListener = {
|
|
|
338
343
|
TSQualifiedName?: (node: TSESTree.TSQualifiedName & ASTNodeWithParent) => void;
|
|
339
344
|
TSReadonlyKeyword?: (node: TSESTree.TSReadonlyKeyword & ASTNodeWithParent) => void;
|
|
340
345
|
TSRestType?: (node: TSESTree.TSRestType & ASTNodeWithParent) => void;
|
|
346
|
+
TSSatisfiesExpression?: (node: TSESTree.TSSatisfiesExpression & ASTNodeWithParent) => void;
|
|
341
347
|
TSStaticKeyword?: (node: TSESTree.TSStaticKeyword & ASTNodeWithParent) => void;
|
|
342
348
|
TSStringKeyword?: (node: TSESTree.TSStringKeyword & ASTNodeWithParent) => void;
|
|
343
349
|
TSSymbolKeyword?: (node: TSESTree.TSSymbolKeyword & ASTNodeWithParent) => void;
|
|
@@ -360,7 +366,7 @@ export declare type TSNodeListener = {
|
|
|
360
366
|
TSUnknownKeyword?: (node: TSESTree.TSUnknownKeyword & ASTNodeWithParent) => void;
|
|
361
367
|
TSVoidKeyword?: (node: TSESTree.TSVoidKeyword & ASTNodeWithParent) => void;
|
|
362
368
|
};
|
|
363
|
-
export
|
|
369
|
+
export type SvelteNodeListener = {
|
|
364
370
|
SvelteScriptElement?: (node: AST.SvelteScriptElement & ASTNodeWithParent) => void;
|
|
365
371
|
SvelteStyleElement?: (node: AST.SvelteStyleElement & ASTNodeWithParent) => void;
|
|
366
372
|
SvelteElement?: (node: AST.SvelteElement & ASTNodeWithParent) => void;
|
package/lib/types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface RuleModule {
|
|
|
17
17
|
meta: RuleMetaData;
|
|
18
18
|
create: (context: RuleContext) => RuleListener;
|
|
19
19
|
}
|
|
20
|
-
export
|
|
20
|
+
export type RuleCategory = "Possible Errors" | "Security Vulnerability" | "Best Practices" | "Stylistic Issues" | "Extension Rules" | "System";
|
|
21
21
|
export interface RuleMetaData {
|
|
22
22
|
docs: {
|
|
23
23
|
description: string;
|
|
@@ -77,7 +77,7 @@ export interface PartialRuleMetaData {
|
|
|
77
77
|
};
|
|
78
78
|
type: "problem" | "suggestion" | "layout";
|
|
79
79
|
}
|
|
80
|
-
export
|
|
80
|
+
export type RuleContext = {
|
|
81
81
|
id: string;
|
|
82
82
|
options: any[];
|
|
83
83
|
settings?: {
|
|
@@ -108,7 +108,7 @@ export declare type RuleContext = {
|
|
|
108
108
|
report(descriptor: ReportDescriptor): void;
|
|
109
109
|
getCwd?: () => string;
|
|
110
110
|
};
|
|
111
|
-
export
|
|
111
|
+
export type NodeOrToken = {
|
|
112
112
|
type: string;
|
|
113
113
|
loc?: AST.SourceLocation | null;
|
|
114
114
|
range?: [number, number];
|
|
@@ -119,22 +119,22 @@ interface ReportDescriptorOptionsBase {
|
|
|
119
119
|
};
|
|
120
120
|
fix?: null | ((fixer: RuleFixer) => null | Rule.Fix | IterableIterator<Rule.Fix> | Rule.Fix[]);
|
|
121
121
|
}
|
|
122
|
-
|
|
122
|
+
type SuggestionDescriptorMessage = {
|
|
123
123
|
desc: string;
|
|
124
124
|
} | {
|
|
125
125
|
messageId: string;
|
|
126
126
|
};
|
|
127
|
-
export
|
|
127
|
+
export type SuggestionReportDescriptor = SuggestionDescriptorMessage & ReportDescriptorOptionsBase;
|
|
128
128
|
interface ReportDescriptorOptions extends ReportDescriptorOptionsBase {
|
|
129
129
|
suggest?: SuggestionReportDescriptor[] | null;
|
|
130
130
|
}
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions;
|
|
132
|
+
type ReportDescriptorMessage = {
|
|
133
133
|
message: string;
|
|
134
134
|
} | {
|
|
135
135
|
messageId: string;
|
|
136
136
|
};
|
|
137
|
-
|
|
137
|
+
type ReportDescriptorLocation = {
|
|
138
138
|
node: NodeOrToken;
|
|
139
139
|
} | {
|
|
140
140
|
loc: AST.SourceLocation | {
|
package/lib/utils/ast-utils.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export declare function getLangValue(node: SvAST.SvelteScriptElement | SvAST.Sve
|
|
|
32
32
|
export declare function findVariable(context: RuleContext, node: TSESTree.Identifier): Variable | null;
|
|
33
33
|
export declare function getScope(context: RuleContext, currentNode: TSESTree.Node): Scope;
|
|
34
34
|
export declare function getParent(node: TSESTree.Node): TSESTree.Node | null;
|
|
35
|
-
export
|
|
35
|
+
export type QuoteAndRange = {
|
|
36
36
|
quote: "unquoted" | "double" | "single";
|
|
37
37
|
range: [number, number];
|
|
38
38
|
firstToken: SvAST.Token | SvAST.Comment;
|
|
@@ -47,7 +47,7 @@ export declare function getMustacheTokens(node: SvAST.SvelteDirective | SvAST.Sv
|
|
|
47
47
|
openToken: SvAST.Token;
|
|
48
48
|
closeToken: SvAST.Token;
|
|
49
49
|
} | null;
|
|
50
|
-
export declare function getAttributeKeyText(node: SvAST.SvelteAttribute | SvAST.SvelteShorthandAttribute | SvAST.SvelteStyleDirective | SvAST.SvelteDirective | SvAST.SvelteSpecialDirective): string;
|
|
50
|
+
export declare function getAttributeKeyText(node: SvAST.SvelteAttribute | SvAST.SvelteShorthandAttribute | SvAST.SvelteStyleDirective | SvAST.SvelteDirective | SvAST.SvelteSpecialDirective, context: RuleContext): string;
|
|
51
51
|
export declare function getDirectiveName(node: SvAST.SvelteDirective): string;
|
|
52
52
|
export declare function getNodeName(node: SvAST.SvelteElement): string;
|
|
53
53
|
export declare function isVoidHtmlElement(node: SvAST.SvelteElement): boolean;
|
package/lib/utils/ast-utils.js
CHANGED
|
@@ -276,7 +276,7 @@ function getMustacheTokens(node, sourceCode) {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
exports.getMustacheTokens = getMustacheTokens;
|
|
279
|
-
function getAttributeKeyText(node) {
|
|
279
|
+
function getAttributeKeyText(node, context) {
|
|
280
280
|
switch (node.type) {
|
|
281
281
|
case "SvelteAttribute":
|
|
282
282
|
case "SvelteShorthandAttribute":
|
|
@@ -287,7 +287,7 @@ function getAttributeKeyText(node) {
|
|
|
287
287
|
return node.kind;
|
|
288
288
|
case "SvelteDirective": {
|
|
289
289
|
const dir = getDirectiveName(node);
|
|
290
|
-
return `${dir}:${node.key.name
|
|
290
|
+
return `${dir}:${getSimpleNameFromNode(node.key.name, context)}${node.key.modifiers.length ? `|${node.key.modifiers.join("|")}` : ""}`;
|
|
291
291
|
}
|
|
292
292
|
default:
|
|
293
293
|
throw new Error(`Unknown node type: ${node.type}`);
|
|
@@ -339,17 +339,7 @@ function getAttributeValueRangeTokens(attr, sourceCode) {
|
|
|
339
339
|
};
|
|
340
340
|
}
|
|
341
341
|
function getNodeName(node) {
|
|
342
|
-
|
|
343
|
-
return node.name.name;
|
|
344
|
-
}
|
|
345
|
-
const memberPath = [node.name.property.name];
|
|
346
|
-
let currentObject = node.name.object;
|
|
347
|
-
while (currentObject.type === "SvelteMemberExpressionName") {
|
|
348
|
-
memberPath.unshift(currentObject.property.name);
|
|
349
|
-
currentObject = currentObject.object;
|
|
350
|
-
}
|
|
351
|
-
memberPath.unshift(currentObject.name);
|
|
352
|
-
return memberPath.join(".");
|
|
342
|
+
return getSimpleNameFromNode(node.name);
|
|
353
343
|
}
|
|
354
344
|
exports.getNodeName = getNodeName;
|
|
355
345
|
function isVoidHtmlElement(node) {
|
|
@@ -392,3 +382,16 @@ function isExpressionIdentifier(node) {
|
|
|
392
382
|
return true;
|
|
393
383
|
}
|
|
394
384
|
exports.isExpressionIdentifier = isExpressionIdentifier;
|
|
385
|
+
function getSimpleNameFromNode(node, context) {
|
|
386
|
+
if (node.type === "Identifier" || node.type === "SvelteName") {
|
|
387
|
+
return node.name;
|
|
388
|
+
}
|
|
389
|
+
if (node.type === "SvelteMemberExpressionName" ||
|
|
390
|
+
(node.type === "MemberExpression" && !node.computed)) {
|
|
391
|
+
return `${getSimpleNameFromNode(node.object, context)}.${getSimpleNameFromNode(node.property, context)}`;
|
|
392
|
+
}
|
|
393
|
+
if (!context) {
|
|
394
|
+
throw new Error("Rule context is required");
|
|
395
|
+
}
|
|
396
|
+
return context.getSourceCode().getText(node);
|
|
397
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { AST } from "svelte-eslint-parser";
|
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
3
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
4
4
|
export declare function parseStyleAttributeValue(node: AST.SvelteAttribute, context: RuleContext): SvelteStyleRoot<AST.SvelteMustacheTagText> | null;
|
|
5
|
-
export
|
|
5
|
+
export type SvelteStyleInterpolation = AST.SvelteMustacheTagText | TSESTree.Expression;
|
|
6
6
|
export interface SvelteStyleNode<E extends SvelteStyleInterpolation> {
|
|
7
7
|
nodes?: SvelteStyleChildNode<E>[];
|
|
8
8
|
range: AST.Range;
|
|
@@ -40,4 +40,4 @@ export interface SvelteStyleComment extends SvelteStyleNode<never> {
|
|
|
40
40
|
type: "comment";
|
|
41
41
|
addInterpolation: (tagOrExpr: SvelteStyleInterpolation) => void;
|
|
42
42
|
}
|
|
43
|
-
export
|
|
43
|
+
export type SvelteStyleChildNode<E extends SvelteStyleInterpolation = SvelteStyleInterpolation> = SvelteStyleDeclaration<E> | SvelteStyleComment;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tokenizer } from "postcss/lib/tokenize";
|
|
2
2
|
import tokenize from "postcss/lib/tokenize";
|
|
3
|
-
|
|
3
|
+
type Tokenize = typeof tokenize;
|
|
4
4
|
declare function templateTokenize(...args: Parameters<Tokenize>): Tokenizer;
|
|
5
5
|
export default templateTokenize;
|
package/lib/utils/rules.js
CHANGED
|
@@ -19,7 +19,9 @@ const no_at_debug_tags_1 = __importDefault(require("../rules/no-at-debug-tags"))
|
|
|
19
19
|
const no_at_html_tags_1 = __importDefault(require("../rules/no-at-html-tags"));
|
|
20
20
|
const no_dom_manipulating_1 = __importDefault(require("../rules/no-dom-manipulating"));
|
|
21
21
|
const no_dupe_else_if_blocks_1 = __importDefault(require("../rules/no-dupe-else-if-blocks"));
|
|
22
|
+
const no_dupe_on_directives_1 = __importDefault(require("../rules/no-dupe-on-directives"));
|
|
22
23
|
const no_dupe_style_properties_1 = __importDefault(require("../rules/no-dupe-style-properties"));
|
|
24
|
+
const no_dupe_use_directives_1 = __importDefault(require("../rules/no-dupe-use-directives"));
|
|
23
25
|
const no_dynamic_slot_name_1 = __importDefault(require("../rules/no-dynamic-slot-name"));
|
|
24
26
|
const no_export_load_in_svelte_module_in_kit_pages_1 = __importDefault(require("../rules/no-export-load-in-svelte-module-in-kit-pages"));
|
|
25
27
|
const no_extra_reactive_curlies_1 = __importDefault(require("../rules/no-extra-reactive-curlies"));
|
|
@@ -66,7 +68,9 @@ exports.rules = [
|
|
|
66
68
|
no_at_html_tags_1.default,
|
|
67
69
|
no_dom_manipulating_1.default,
|
|
68
70
|
no_dupe_else_if_blocks_1.default,
|
|
71
|
+
no_dupe_on_directives_1.default,
|
|
69
72
|
no_dupe_style_properties_1.default,
|
|
73
|
+
no_dupe_use_directives_1.default,
|
|
70
74
|
no_dynamic_slot_name_1.default,
|
|
71
75
|
no_export_load_in_svelte_module_in_kit_pages_1.default,
|
|
72
76
|
no_extra_reactive_curlies_1.default,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { RuleContext, ASTNode } from "../../types";
|
|
2
2
|
import type * as TS from "typescript";
|
|
3
|
-
export
|
|
3
|
+
export type TypeScript = typeof TS;
|
|
4
4
|
export type { TS };
|
|
5
|
-
export
|
|
5
|
+
export type TSTools = {
|
|
6
6
|
service: {
|
|
7
7
|
esTreeNodeToTSNodeMap: ReadonlyMap<unknown, TS.Node>;
|
|
8
8
|
tsNodeToESTreeNodeMap: ReadonlyMap<TS.Node, ASTNode>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-svelte",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "ESLint plugin for Svelte using AST",
|
|
5
5
|
"repository": "git+https://github.com/ota-meshi/eslint-plugin-svelte.git",
|
|
6
6
|
"homepage": "https://ota-meshi.github.io/eslint-plugin-svelte",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"postcss-load-config": "^3.1.4",
|
|
74
74
|
"postcss-safe-parser": "^6.0.0",
|
|
75
75
|
"sourcemap-codec": "^1.4.8",
|
|
76
|
-
"svelte-eslint-parser": "^0.
|
|
76
|
+
"svelte-eslint-parser": "^0.22.0"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@1stg/browserslist-config": "^1.2.3",
|
|
@@ -110,8 +110,8 @@
|
|
|
110
110
|
"@types/postcss-safe-parser": "^5.0.1",
|
|
111
111
|
"@types/prismjs": "^1.26.0",
|
|
112
112
|
"@types/stylus": "^0.48.38",
|
|
113
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
114
|
-
"@typescript-eslint/parser": "^5.
|
|
113
|
+
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
114
|
+
"@typescript-eslint/parser": "^5.45.0",
|
|
115
115
|
"@typescript-eslint/parser-v4": "npm:@typescript-eslint/parser@4",
|
|
116
116
|
"@typescript/vfs": "^1.4.0",
|
|
117
117
|
"assert": "^2.0.0",
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"less": "^4.1.2",
|
|
141
141
|
"lint-staged": "^13.0.3",
|
|
142
142
|
"locate-character": "^2.0.5",
|
|
143
|
-
"magic-string": "^0.
|
|
143
|
+
"magic-string": "^0.27.0",
|
|
144
144
|
"markdown-it-anchor": "^8.4.1",
|
|
145
145
|
"markdown-it-container": "^3.0.0",
|
|
146
146
|
"markdown-it-emoji": "^2.0.0",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"svelte-adapter-ghpages": "0.0.2",
|
|
165
165
|
"svelte-i18n": "^3.4.0",
|
|
166
166
|
"type-coverage": "^2.22.0",
|
|
167
|
-
"typescript": "^4.
|
|
167
|
+
"typescript": "^4.9.3",
|
|
168
168
|
"vite": "^3.1.0-0",
|
|
169
169
|
"vite-plugin-svelte-md": "^0.1.5",
|
|
170
170
|
"yaml": "^2.1.1",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"access": "public"
|
|
175
175
|
},
|
|
176
176
|
"typeCoverage": {
|
|
177
|
-
"atLeast":
|
|
177
|
+
"atLeast": 99.05,
|
|
178
178
|
"cache": true,
|
|
179
179
|
"detail": true,
|
|
180
180
|
"ignoreAsAssertion": true,
|