eslint-plugin-svelte 2.9.0 → 2.10.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 +1 -0
- package/lib/rules/prefer-destructured-store-props.d.ts +2 -0
- package/lib/rules/prefer-destructured-store-props.js +182 -0
- package/lib/shared/svelte-compile-warns/transform/babel.js +1 -1
- package/lib/shared/svelte-compile-warns/transform/less.js +1 -1
- package/lib/shared/svelte-compile-warns/transform/postcss.js +1 -1
- package/lib/shared/svelte-compile-warns/transform/sass.js +1 -1
- package/lib/shared/svelte-compile-warns/transform/stylus.js +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/utils/ast-utils.d.ts +4 -2
- package/lib/utils/ast-utils.js +46 -2
- package/lib/utils/rules.js +2 -0
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -294,6 +294,7 @@ These rules relate to better ways of doing things to help you avoid problems:
|
|
|
294
294
|
| [svelte/no-reactive-literals](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-reactive-literals/) | don't assign literal values in reactive statements | :bulb: |
|
|
295
295
|
| [svelte/no-unused-svelte-ignore](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/) | disallow unused svelte-ignore comments | :star: |
|
|
296
296
|
| [svelte/no-useless-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-useless-mustaches/) | disallow unnecessary mustache interpolations | :wrench: |
|
|
297
|
+
| [svelte/prefer-destructured-store-props](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-destructured-store-props/) | destructure values from object stores for better change tracking & fewer redraws | :bulb: |
|
|
297
298
|
| [svelte/require-optimized-style-attribute](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-optimized-style-attribute/) | require style attributes that can be optimized | |
|
|
298
299
|
| [svelte/require-stores-init](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-stores-init/) | require initial value in store | |
|
|
299
300
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const eslint_utils_1 = require("eslint-utils");
|
|
4
|
+
const esutils_1 = require("esutils");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const ast_utils_1 = require("../utils/ast-utils");
|
|
7
|
+
exports.default = (0, utils_1.createRule)("prefer-destructured-store-props", {
|
|
8
|
+
meta: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: "destructure values from object stores for better change tracking & fewer redraws",
|
|
11
|
+
category: "Best Practices",
|
|
12
|
+
recommended: false,
|
|
13
|
+
},
|
|
14
|
+
hasSuggestions: true,
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
useDestructuring: `Destructure {{property}} from {{store}} for better change tracking & fewer redraws`,
|
|
18
|
+
fixUseDestructuring: `Using destructuring like $: ({ {{property}} } = {{store}}); will run faster`,
|
|
19
|
+
fixUseVariable: `Using the predefined reactive variable {{variable}}`,
|
|
20
|
+
},
|
|
21
|
+
type: "suggestion",
|
|
22
|
+
},
|
|
23
|
+
create(context) {
|
|
24
|
+
let mainScript = null;
|
|
25
|
+
const reports = [];
|
|
26
|
+
let inScriptElement = false;
|
|
27
|
+
const storeMemberAccessStack = [];
|
|
28
|
+
function* findReactiveVariable(object, propName) {
|
|
29
|
+
const storeVar = (0, ast_utils_1.findVariable)(context, object);
|
|
30
|
+
if (!storeVar) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const reference of storeVar.references) {
|
|
34
|
+
const id = reference.identifier;
|
|
35
|
+
if (id.name !== object.name)
|
|
36
|
+
continue;
|
|
37
|
+
if (isReactiveVariableDefinitionWithMemberExpression(id)) {
|
|
38
|
+
yield id.parent.parent.left;
|
|
39
|
+
}
|
|
40
|
+
else if (isReactiveVariableDefinitionWithDestructuring(id)) {
|
|
41
|
+
const prop = id.parent.left.properties.find((prop) => prop.type === "Property" &&
|
|
42
|
+
prop.value.type === "Identifier" &&
|
|
43
|
+
(0, eslint_utils_1.getPropertyName)(prop) === propName);
|
|
44
|
+
if (prop) {
|
|
45
|
+
yield prop.value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function isReactiveVariableDefinitionWithMemberExpression(node) {
|
|
50
|
+
return (node.parent?.type === "MemberExpression" &&
|
|
51
|
+
node.parent.object === node &&
|
|
52
|
+
(0, eslint_utils_1.getPropertyName)(node.parent) === propName &&
|
|
53
|
+
node.parent.parent?.type === "AssignmentExpression" &&
|
|
54
|
+
node.parent.parent.right === node.parent &&
|
|
55
|
+
node.parent.parent.left.type === "Identifier" &&
|
|
56
|
+
node.parent.parent.parent?.type === "ExpressionStatement" &&
|
|
57
|
+
node.parent.parent.parent
|
|
58
|
+
.parent?.type === "SvelteReactiveStatement");
|
|
59
|
+
}
|
|
60
|
+
function isReactiveVariableDefinitionWithDestructuring(node) {
|
|
61
|
+
return (node.parent?.type === "AssignmentExpression" &&
|
|
62
|
+
node.parent.right === node &&
|
|
63
|
+
node.parent.left.type === "ObjectPattern" &&
|
|
64
|
+
node.parent.parent?.type === "ExpressionStatement" &&
|
|
65
|
+
node.parent.parent.parent
|
|
66
|
+
?.type === "SvelteReactiveStatement");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function hasTopLevelVariable(name) {
|
|
70
|
+
const scopeManager = context.getSourceCode().scopeManager;
|
|
71
|
+
if (scopeManager.globalScope?.set.has(name)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const moduleScope = scopeManager.globalScope?.childScopes.find((s) => s.type === "module");
|
|
75
|
+
return moduleScope?.set.has(name) || false;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
SvelteScriptElement(node) {
|
|
79
|
+
inScriptElement = true;
|
|
80
|
+
const scriptContext = (0, ast_utils_1.findAttribute)(node, "context");
|
|
81
|
+
const contextValue = scriptContext?.value.length === 1 && scriptContext.value[0];
|
|
82
|
+
if (contextValue &&
|
|
83
|
+
contextValue.type === "SvelteLiteral" &&
|
|
84
|
+
contextValue.value === "module") {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
mainScript = node;
|
|
88
|
+
},
|
|
89
|
+
"SvelteScriptElement:exit"() {
|
|
90
|
+
inScriptElement = false;
|
|
91
|
+
},
|
|
92
|
+
"MemberExpression[object.type='Identifier'][object.name=/^\\$/]"(node) {
|
|
93
|
+
if (inScriptElement)
|
|
94
|
+
return;
|
|
95
|
+
storeMemberAccessStack.unshift({ node, identifiers: [] });
|
|
96
|
+
},
|
|
97
|
+
Identifier(node) {
|
|
98
|
+
storeMemberAccessStack[0]?.identifiers.push(node);
|
|
99
|
+
},
|
|
100
|
+
"MemberExpression[object.type='Identifier'][object.name=/^\\$/]:exit"(node) {
|
|
101
|
+
if (storeMemberAccessStack[0]?.node !== node)
|
|
102
|
+
return;
|
|
103
|
+
const { identifiers } = storeMemberAccessStack.shift();
|
|
104
|
+
for (const id of identifiers) {
|
|
105
|
+
if (!(0, ast_utils_1.isExpressionIdentifier)(id))
|
|
106
|
+
continue;
|
|
107
|
+
const variable = (0, ast_utils_1.findVariable)(context, id);
|
|
108
|
+
const isTopLevel = !variable ||
|
|
109
|
+
variable.scope.type === "module" ||
|
|
110
|
+
variable.scope.type === "global";
|
|
111
|
+
if (!isTopLevel) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
reports.push(node);
|
|
116
|
+
},
|
|
117
|
+
"Program:exit"() {
|
|
118
|
+
const scriptEndTag = mainScript && mainScript.endTag;
|
|
119
|
+
for (const node of reports) {
|
|
120
|
+
const store = node.object.name;
|
|
121
|
+
const suggest = [];
|
|
122
|
+
if (!node.computed) {
|
|
123
|
+
for (const variable of findReactiveVariable(node.object, node.property.name)) {
|
|
124
|
+
suggest.push({
|
|
125
|
+
messageId: "fixUseVariable",
|
|
126
|
+
data: {
|
|
127
|
+
variable: variable.name,
|
|
128
|
+
},
|
|
129
|
+
fix(fixer) {
|
|
130
|
+
return fixer.replaceText(node, variable.name);
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (scriptEndTag) {
|
|
135
|
+
suggest.push({
|
|
136
|
+
messageId: "fixUseDestructuring",
|
|
137
|
+
data: {
|
|
138
|
+
store,
|
|
139
|
+
property: node.property.name,
|
|
140
|
+
},
|
|
141
|
+
fix(fixer) {
|
|
142
|
+
const propName = node.property.name;
|
|
143
|
+
let varName = propName;
|
|
144
|
+
if (varName.startsWith("$")) {
|
|
145
|
+
varName = varName.slice(1);
|
|
146
|
+
}
|
|
147
|
+
const baseName = varName;
|
|
148
|
+
let suffix = 0;
|
|
149
|
+
if (esutils_1.keyword.isReservedWordES6(varName, true) ||
|
|
150
|
+
esutils_1.keyword.isRestrictedWord(varName)) {
|
|
151
|
+
varName = `${baseName}${++suffix}`;
|
|
152
|
+
}
|
|
153
|
+
while (hasTopLevelVariable(varName)) {
|
|
154
|
+
varName = `${baseName}${++suffix}`;
|
|
155
|
+
}
|
|
156
|
+
return [
|
|
157
|
+
fixer.insertTextAfterRange([scriptEndTag.range[0], scriptEndTag.range[0]], `$: ({ ${propName}${propName !== varName ? `: ${varName}` : ""} } = ${store});\n`),
|
|
158
|
+
fixer.replaceText(node, varName),
|
|
159
|
+
];
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
context.report({
|
|
165
|
+
node,
|
|
166
|
+
messageId: "useDestructuring",
|
|
167
|
+
data: {
|
|
168
|
+
store,
|
|
169
|
+
property: !node.computed
|
|
170
|
+
? node.property.name
|
|
171
|
+
: context
|
|
172
|
+
.getSourceCode()
|
|
173
|
+
.getText(node.property)
|
|
174
|
+
.replace(/\s+/g, " "),
|
|
175
|
+
},
|
|
176
|
+
suggest,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
});
|
package/lib/types.d.ts
CHANGED
|
@@ -114,7 +114,7 @@ declare type SuggestionDescriptorMessage = {
|
|
|
114
114
|
} | {
|
|
115
115
|
messageId: string;
|
|
116
116
|
};
|
|
117
|
-
declare type SuggestionReportDescriptor = SuggestionDescriptorMessage & ReportDescriptorOptionsBase;
|
|
117
|
+
export declare type SuggestionReportDescriptor = SuggestionDescriptorMessage & ReportDescriptorOptionsBase;
|
|
118
118
|
interface ReportDescriptorOptions extends ReportDescriptorOptionsBase {
|
|
119
119
|
suggest?: SuggestionReportDescriptor[] | null;
|
|
120
120
|
}
|
package/lib/utils/ast-utils.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { ASTNode, RuleContext, SourceCode } from "../types";
|
|
2
2
|
import type * as ESTree from "estree";
|
|
3
|
+
import type { TSESTree } from "@typescript-eslint/types";
|
|
3
4
|
import type { AST as SvAST } from "svelte-eslint-parser";
|
|
4
5
|
import type { Scope } from "eslint";
|
|
5
6
|
export declare function equalTokens(left: ASTNode, right: ASTNode, sourceCode: SourceCode): boolean;
|
|
6
|
-
export declare function getStringIfConstant(node: ESTree.Expression): string | null;
|
|
7
|
+
export declare function getStringIfConstant(node: ESTree.Expression | TSESTree.Expression): string | null;
|
|
7
8
|
export declare function needParentheses(node: ESTree.Expression, kind: "not" | "logical"): boolean;
|
|
8
9
|
export declare function isHTMLElementLike(node: SvAST.SvelteElement | SvAST.SvelteScriptElement | SvAST.SvelteStyleElement): node is SvAST.SvelteHTMLElement | (SvAST.SvelteSpecialElement & {
|
|
9
10
|
name: SvAST.SvelteName & {
|
|
@@ -29,7 +30,7 @@ export declare function findBindDirective<N extends string>(node: SvAST.SvelteEl
|
|
|
29
30
|
}) | null;
|
|
30
31
|
export declare function getStaticAttributeValue(node: SvAST.SvelteAttribute): string | null;
|
|
31
32
|
export declare function getLangValue(node: SvAST.SvelteScriptElement | SvAST.SvelteStyleElement): string | null;
|
|
32
|
-
export declare function findVariable(context: RuleContext, node: ESTree.Identifier): Scope.Variable | null;
|
|
33
|
+
export declare function findVariable(context: RuleContext, node: ESTree.Identifier | TSESTree.Identifier): Scope.Variable | null;
|
|
33
34
|
export declare function getScope(context: RuleContext, currentNode: ESTree.Node): Scope.Scope;
|
|
34
35
|
export declare type QuoteAndRange = {
|
|
35
36
|
quote: "unquoted" | "double" | "single";
|
|
@@ -50,3 +51,4 @@ export declare function getAttributeKeyText(node: SvAST.SvelteAttribute | SvAST.
|
|
|
50
51
|
export declare function getDirectiveName(node: SvAST.SvelteDirective): string;
|
|
51
52
|
export declare function getNodeName(node: SvAST.SvelteElement): string;
|
|
52
53
|
export declare function isVoidHtmlElement(node: SvAST.SvelteElement): boolean;
|
|
54
|
+
export declare function isExpressionIdentifier(node: TSESTree.Identifier): boolean;
|
package/lib/utils/ast-utils.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.isVoidHtmlElement = exports.getNodeName = exports.getDirectiveName = exports.getAttributeKeyText = exports.getMustacheTokens = exports.getAttributeValueQuoteAndRange = exports.getScope = exports.findVariable = exports.getLangValue = exports.getStaticAttributeValue = exports.findBindDirective = exports.findShorthandAttribute = exports.findAttribute = exports.isHTMLElementLike = exports.needParentheses = exports.getStringIfConstant = exports.equalTokens = void 0;
|
|
29
|
+
exports.isExpressionIdentifier = exports.isVoidHtmlElement = exports.getNodeName = exports.getDirectiveName = exports.getAttributeKeyText = exports.getMustacheTokens = exports.getAttributeValueQuoteAndRange = exports.getScope = exports.findVariable = exports.getLangValue = exports.getStaticAttributeValue = exports.findBindDirective = exports.findShorthandAttribute = exports.findAttribute = exports.isHTMLElementLike = exports.needParentheses = exports.getStringIfConstant = exports.equalTokens = void 0;
|
|
30
30
|
const eslintUtils = __importStar(require("eslint-utils"));
|
|
31
31
|
const void_elements_1 = __importDefault(require("./void-elements"));
|
|
32
32
|
function equalTokens(left, right, sourceCode) {
|
|
@@ -168,7 +168,15 @@ function getLangValue(node) {
|
|
|
168
168
|
}
|
|
169
169
|
exports.getLangValue = getLangValue;
|
|
170
170
|
function findVariable(context, node) {
|
|
171
|
-
|
|
171
|
+
const initialScope = eslintUtils.getInnermostScope(getScope(context, node), node);
|
|
172
|
+
const variable = eslintUtils.findVariable(initialScope, node);
|
|
173
|
+
if (variable) {
|
|
174
|
+
return variable;
|
|
175
|
+
}
|
|
176
|
+
if (!node.name.startsWith("$")) {
|
|
177
|
+
return variable;
|
|
178
|
+
}
|
|
179
|
+
return eslintUtils.findVariable(initialScope, node.name.slice(1));
|
|
172
180
|
}
|
|
173
181
|
exports.findVariable = findVariable;
|
|
174
182
|
function getScope(context, currentNode) {
|
|
@@ -346,3 +354,39 @@ function isVoidHtmlElement(node) {
|
|
|
346
354
|
return void_elements_1.default.includes(getNodeName(node));
|
|
347
355
|
}
|
|
348
356
|
exports.isVoidHtmlElement = isVoidHtmlElement;
|
|
357
|
+
function isExpressionIdentifier(node) {
|
|
358
|
+
const parent = node.parent;
|
|
359
|
+
if (!parent) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
if (parent.type === "MemberExpression") {
|
|
363
|
+
return !parent.computed || parent.property !== node;
|
|
364
|
+
}
|
|
365
|
+
if (parent.type === "Property" ||
|
|
366
|
+
parent.type === "MethodDefinition" ||
|
|
367
|
+
parent.type === "PropertyDefinition") {
|
|
368
|
+
return !parent.computed || parent.key !== node;
|
|
369
|
+
}
|
|
370
|
+
if (parent.type === "FunctionDeclaration" ||
|
|
371
|
+
parent.type === "FunctionExpression" ||
|
|
372
|
+
parent.type === "ClassDeclaration" ||
|
|
373
|
+
parent.type === "ClassExpression") {
|
|
374
|
+
return parent.id !== node;
|
|
375
|
+
}
|
|
376
|
+
if (parent.type === "LabeledStatement" ||
|
|
377
|
+
parent.type === "BreakStatement" ||
|
|
378
|
+
parent.type === "ContinueStatement") {
|
|
379
|
+
return parent.label !== node;
|
|
380
|
+
}
|
|
381
|
+
if (parent.type === "MetaProperty") {
|
|
382
|
+
return parent.property !== node;
|
|
383
|
+
}
|
|
384
|
+
if (parent.type === "ImportSpecifier") {
|
|
385
|
+
return parent.imported !== node;
|
|
386
|
+
}
|
|
387
|
+
if (parent.type === "ExportSpecifier") {
|
|
388
|
+
return parent.exported !== node;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
exports.isExpressionIdentifier = isExpressionIdentifier;
|
package/lib/utils/rules.js
CHANGED
|
@@ -35,6 +35,7 @@ const no_unknown_style_directive_property_1 = __importDefault(require("../rules/
|
|
|
35
35
|
const no_unused_svelte_ignore_1 = __importDefault(require("../rules/no-unused-svelte-ignore"));
|
|
36
36
|
const no_useless_mustaches_1 = __importDefault(require("../rules/no-useless-mustaches"));
|
|
37
37
|
const prefer_class_directive_1 = __importDefault(require("../rules/prefer-class-directive"));
|
|
38
|
+
const prefer_destructured_store_props_1 = __importDefault(require("../rules/prefer-destructured-store-props"));
|
|
38
39
|
const prefer_style_directive_1 = __importDefault(require("../rules/prefer-style-directive"));
|
|
39
40
|
const require_optimized_style_attribute_1 = __importDefault(require("../rules/require-optimized-style-attribute"));
|
|
40
41
|
const require_stores_init_1 = __importDefault(require("../rules/require-stores-init"));
|
|
@@ -76,6 +77,7 @@ exports.rules = [
|
|
|
76
77
|
no_unused_svelte_ignore_1.default,
|
|
77
78
|
no_useless_mustaches_1.default,
|
|
78
79
|
prefer_class_directive_1.default,
|
|
80
|
+
prefer_destructured_store_props_1.default,
|
|
79
81
|
prefer_style_directive_1.default,
|
|
80
82
|
require_optimized_style_attribute_1.default,
|
|
81
83
|
require_stores_init_1.default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-svelte",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.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",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"debug": "^4.3.1",
|
|
69
69
|
"eslint-utils": "^3.0.0",
|
|
70
|
+
"esutils": "^2.0.3",
|
|
70
71
|
"known-css-properties": "^0.25.0",
|
|
71
72
|
"postcss": "^8.4.5",
|
|
72
73
|
"postcss-load-config": "^3.1.4",
|
|
@@ -88,7 +89,7 @@
|
|
|
88
89
|
"@changesets/changelog-github": "^0.4.6",
|
|
89
90
|
"@changesets/cli": "^2.24.2",
|
|
90
91
|
"@fontsource/fira-mono": "^4.5.0",
|
|
91
|
-
"@ota-meshi/eslint-plugin": "^0.
|
|
92
|
+
"@ota-meshi/eslint-plugin": "^0.13.0",
|
|
92
93
|
"@sindresorhus/slugify": "^2.1.0",
|
|
93
94
|
"@sveltejs/adapter-static": "^1.0.0-next.40",
|
|
94
95
|
"@sveltejs/kit": "^1.0.0-next.456",
|
|
@@ -100,11 +101,12 @@
|
|
|
100
101
|
"@types/eslint-utils": "^3.0.1",
|
|
101
102
|
"@types/eslint-visitor-keys": "^1.0.0",
|
|
102
103
|
"@types/estree": "^1.0.0",
|
|
104
|
+
"@types/esutils": "^2.0.0",
|
|
103
105
|
"@types/less": "^3.0.3",
|
|
104
106
|
"@types/markdown-it": "^12.2.3",
|
|
105
107
|
"@types/markdown-it-container": "^2.0.5",
|
|
106
108
|
"@types/markdown-it-emoji": "^2.0.2",
|
|
107
|
-
"@types/mocha": "^
|
|
109
|
+
"@types/mocha": "^10.0.0",
|
|
108
110
|
"@types/node": "^16.0.0",
|
|
109
111
|
"@types/postcss-safe-parser": "^5.0.1",
|
|
110
112
|
"@types/prismjs": "^1.26.0",
|
|
@@ -172,7 +174,7 @@
|
|
|
172
174
|
"access": "public"
|
|
173
175
|
},
|
|
174
176
|
"typeCoverage": {
|
|
175
|
-
"atLeast": 98.
|
|
177
|
+
"atLeast": 98.71,
|
|
176
178
|
"cache": true,
|
|
177
179
|
"detail": true,
|
|
178
180
|
"ignoreAsAssertion": true,
|