@typescript-eslint/eslint-plugin 8.27.1-alpha.2 → 8.28.1-alpha.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/dist/rules/consistent-type-exports.d.ts.map +1 -1
- package/dist/rules/consistent-type-exports.js +4 -6
- package/dist/rules/no-unnecessary-condition.d.ts.map +1 -1
- package/dist/rules/no-unnecessary-condition.js +8 -6
- package/dist/rules/no-unsafe-function-type.d.ts.map +1 -1
- package/dist/rules/no-unsafe-function-type.js +0 -1
- package/dist/rules/no-unsafe-return.d.ts.map +1 -1
- package/dist/rules/no-unsafe-return.js +1 -3
- package/dist/rules/prefer-nullish-coalescing.d.ts +2 -1
- package/dist/rules/prefer-nullish-coalescing.d.ts.map +1 -1
- package/dist/rules/prefer-nullish-coalescing.js +237 -132
- package/dist/rules/use-unknown-in-catch-callback-variable.d.ts.map +1 -1
- package/dist/rules/use-unknown-in-catch-callback-variable.js +0 -1
- package/dist/util/isAssignee.d.ts.map +1 -1
- package/dist/util/isAssignee.js +8 -0
- package/docs/rules/prefer-nullish-coalescing.mdx +92 -0
- package/package.json +7 -7
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"consistent-type-exports.d.ts","sourceRoot":"","sources":["../../src/rules/consistent-type-exports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAgBnE,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,sCAAsC,EAAE,OAAO,CAAC;KACjD;CACF,CAAC;AAgBF,MAAM,MAAM,UAAU,GAClB,yBAAyB,GACzB,oBAAoB,GACpB,eAAe,CAAC;;AAEpB,
|
1
|
+
{"version":3,"file":"consistent-type-exports.d.ts","sourceRoot":"","sources":["../../src/rules/consistent-type-exports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAgBnE,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,sCAAsC,EAAE,OAAO,CAAC;KACjD;CACF,CAAC;AAgBF,MAAM,MAAM,UAAU,GAClB,yBAAyB,GACzB,oBAAoB,GACpB,eAAe,CAAC;;AAEpB,wBA8RG"}
|
@@ -158,14 +158,12 @@ exports.default = (0, util_1.createRule)({
|
|
158
158
|
// Cache the first encountered exports for the package. We will need to come
|
159
159
|
// back to these later when fixing the problems.
|
160
160
|
if (node.exportKind === 'type') {
|
161
|
-
|
162
|
-
|
163
|
-
sourceExports.typeOnlyNamedExport = node;
|
164
|
-
}
|
161
|
+
// The export is a type export
|
162
|
+
sourceExports.typeOnlyNamedExport ??= node;
|
165
163
|
}
|
166
|
-
else
|
164
|
+
else {
|
167
165
|
// The export is a value export
|
168
|
-
sourceExports.valueOnlyNamedExport
|
166
|
+
sourceExports.valueOnlyNamedExport ??= node;
|
169
167
|
}
|
170
168
|
// Next for the current export, we will separate type/value specifiers.
|
171
169
|
const typeBasedSpecifiers = [];
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"no-unnecessary-condition.d.ts","sourceRoot":"","sources":["../../src/rules/no-unnecessary-condition.ts"],"names":[],"mappings":"AAyHA,KAAK,iCAAiC,GAAG,OAAO,CAAC;AAEjD,KAAK,2BAA2B,GAAG,QAAQ,GAAG,OAAO,GAAG,uBAAuB,CAAC;AAShF,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,2BAA2B,CAAC,EACxB,2BAA2B,GAC3B,iCAAiC,CAAC;QACtC,sDAAsD,CAAC,EAAE,OAAO,CAAC;QACjE,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B;CACF,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,iBAAiB,GACjB,eAAe,GACf,cAAc,GACd,kBAAkB,GAClB,+BAA+B,GAC/B,OAAO,GACP,cAAc,GACd,oBAAoB,GACpB,4BAA4B,GAC5B,mBAAmB,GACnB,wBAAwB,CAAC;;AAE7B,
|
1
|
+
{"version":3,"file":"no-unnecessary-condition.d.ts","sourceRoot":"","sources":["../../src/rules/no-unnecessary-condition.ts"],"names":[],"mappings":"AAyHA,KAAK,iCAAiC,GAAG,OAAO,CAAC;AAEjD,KAAK,2BAA2B,GAAG,QAAQ,GAAG,OAAO,GAAG,uBAAuB,CAAC;AAShF,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,2BAA2B,CAAC,EACxB,2BAA2B,GAC3B,iCAAiC,CAAC;QACtC,sDAAsD,CAAC,EAAE,OAAO,CAAC;QACjE,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B;CACF,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,iBAAiB,GACjB,eAAe,GACf,cAAc,GACd,kBAAkB,GAClB,+BAA+B,GAC/B,OAAO,GACP,cAAc,GACd,oBAAoB,GACpB,4BAA4B,GAC5B,mBAAmB,GACnB,wBAAwB,CAAC;;AAE7B,wBAowBG"}
|
@@ -258,7 +258,7 @@ exports.default = (0, util_1.createRule)({
|
|
258
258
|
// Since typescript array index signature types don't represent the
|
259
259
|
// possibility of out-of-bounds access, if we're indexing into an array
|
260
260
|
// just skip the check, to avoid false positives
|
261
|
-
if (isArrayIndexExpression(expression)) {
|
261
|
+
if (!isNoUncheckedIndexedAccess && isArrayIndexExpression(expression)) {
|
262
262
|
return;
|
263
263
|
}
|
264
264
|
// When checking logical expressions, only check the right side
|
@@ -308,10 +308,11 @@ exports.default = (0, util_1.createRule)({
|
|
308
308
|
// Since typescript array index signature types don't represent the
|
309
309
|
// possibility of out-of-bounds access, if we're indexing into an array
|
310
310
|
// just skip the check, to avoid false positives
|
311
|
-
if (
|
312
|
-
!(node
|
313
|
-
node.
|
314
|
-
|
311
|
+
if (isNoUncheckedIndexedAccess ||
|
312
|
+
(!isArrayIndexExpression(node) &&
|
313
|
+
!(node.type === utils_1.AST_NODE_TYPES.ChainExpression &&
|
314
|
+
node.expression.type !== utils_1.AST_NODE_TYPES.TSNonNullExpression &&
|
315
|
+
optionChainContainsOptionArrayIndex(node.expression)))) {
|
315
316
|
messageId = 'neverNullish';
|
316
317
|
}
|
317
318
|
}
|
@@ -598,7 +599,8 @@ exports.default = (0, util_1.createRule)({
|
|
598
599
|
// Since typescript array index signature types don't represent the
|
599
600
|
// possibility of out-of-bounds access, if we're indexing into an array
|
600
601
|
// just skip the check, to avoid false positives
|
601
|
-
if (
|
602
|
+
if (!isNoUncheckedIndexedAccess &&
|
603
|
+
optionChainContainsOptionArrayIndex(node)) {
|
602
604
|
return;
|
603
605
|
}
|
604
606
|
const nodeToCheck = node.type === utils_1.AST_NODE_TYPES.CallExpression ? node.callee : node.object;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"no-unsafe-function-type.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsafe-function-type.ts"],"names":[],"mappings":";AAMA,
|
1
|
+
{"version":3,"file":"no-unsafe-function-type.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsafe-function-type.ts"],"names":[],"mappings":";AAMA,wBA2CG"}
|
@@ -10,7 +10,6 @@ exports.default = (0, util_1.createRule)({
|
|
10
10
|
description: 'Disallow using the unsafe built-in Function type',
|
11
11
|
recommended: 'recommended',
|
12
12
|
},
|
13
|
-
fixable: 'code',
|
14
13
|
messages: {
|
15
14
|
bannedFunctionType: [
|
16
15
|
'The `Function` type accepts any function-like value.',
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"no-unsafe-return.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsafe-return.ts"],"names":[],"mappings":";AAqBA,
|
1
|
+
{"version":3,"file":"no-unsafe-return.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsafe-return.ts"],"names":[],"mappings":";AAqBA,wBAsMG"}
|
@@ -81,9 +81,7 @@ exports.default = (0, util_1.createRule)({
|
|
81
81
|
ts.isArrowFunction(functionTSNode)
|
82
82
|
? (0, util_1.getContextualType)(checker, functionTSNode)
|
83
83
|
: services.getTypeAtLocation(functionNode);
|
84
|
-
|
85
|
-
functionType = services.getTypeAtLocation(functionNode);
|
86
|
-
}
|
84
|
+
functionType ??= services.getTypeAtLocation(functionNode);
|
87
85
|
const callSignatures = tsutils.getCallSignaturesOfType(functionType);
|
88
86
|
// If there is an explicit type annotation *and* that type matches the actual
|
89
87
|
// function return type, we shouldn't complain (it's intentional, even if unsafe)
|
@@ -4,6 +4,7 @@ export type Options = [
|
|
4
4
|
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
|
5
5
|
ignoreBooleanCoercion?: boolean;
|
6
6
|
ignoreConditionalTests?: boolean;
|
7
|
+
ignoreIfStatements?: boolean;
|
7
8
|
ignoreMixedLogicalExpressions?: boolean;
|
8
9
|
ignorePrimitives?: {
|
9
10
|
bigint?: boolean;
|
@@ -14,7 +15,7 @@ export type Options = [
|
|
14
15
|
ignoreTernaryTests?: boolean;
|
15
16
|
}
|
16
17
|
];
|
17
|
-
export type MessageIds = 'noStrictNullCheck' | 'preferNullishOverOr' | 'preferNullishOverTernary' | 'suggestNullish';
|
18
|
+
export type MessageIds = 'noStrictNullCheck' | 'preferNullishOverAssignment' | 'preferNullishOverOr' | 'preferNullishOverTernary' | 'suggestNullish';
|
18
19
|
declare const _default: TSESLint.RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
19
20
|
export default _default;
|
20
21
|
//# sourceMappingURL=prefer-nullish-coalescing.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"prefer-nullish-coalescing.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-nullish-coalescing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;
|
1
|
+
{"version":3,"file":"prefer-nullish-coalescing.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-nullish-coalescing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAqCnE,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,sDAAsD,CAAC,EAAE,OAAO,CAAC;QACjE,qBAAqB,CAAC,EAAE,OAAO,CAAC;QAChC,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,6BAA6B,CAAC,EAAE,OAAO,CAAC;QACxC,gBAAgB,CAAC,EACb;YACE,MAAM,CAAC,EAAE,OAAO,CAAC;YACjB,OAAO,CAAC,EAAE,OAAO,CAAC;YAClB,MAAM,CAAC,EAAE,OAAO,CAAC;YACjB,MAAM,CAAC,EAAE,OAAO,CAAC;SAClB,GACD,IAAI,CAAC;QACT,kBAAkB,CAAC,EAAE,OAAO,CAAC;KAC9B;CACF,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,mBAAmB,GACnB,6BAA6B,GAC7B,qBAAqB,GACrB,0BAA0B,GAC1B,gBAAgB,CAAC;;AAErB,wBA8jBG"}
|
@@ -37,11 +37,14 @@ const utils_1 = require("@typescript-eslint/utils");
|
|
37
37
|
const tsutils = __importStar(require("ts-api-utils"));
|
38
38
|
const ts = __importStar(require("typescript"));
|
39
39
|
const util_1 = require("../util");
|
40
|
-
const
|
40
|
+
const isMemberAccessLike = (0, util_1.isNodeOfTypes)([
|
41
41
|
utils_1.AST_NODE_TYPES.ChainExpression,
|
42
42
|
utils_1.AST_NODE_TYPES.Identifier,
|
43
43
|
utils_1.AST_NODE_TYPES.MemberExpression,
|
44
44
|
]);
|
45
|
+
const isNullLiteralOrUndefinedIdentifier = (node) => (0, util_1.isNullLiteral)(node) || (0, util_1.isUndefinedIdentifier)(node);
|
46
|
+
const isNodeNullishComparison = (node) => isNullLiteralOrUndefinedIdentifier(node.left) &&
|
47
|
+
isNullLiteralOrUndefinedIdentifier(node.right);
|
45
48
|
exports.default = (0, util_1.createRule)({
|
46
49
|
name: 'prefer-nullish-coalescing',
|
47
50
|
meta: {
|
@@ -54,6 +57,7 @@ exports.default = (0, util_1.createRule)({
|
|
54
57
|
hasSuggestions: true,
|
55
58
|
messages: {
|
56
59
|
noStrictNullCheck: 'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.',
|
60
|
+
preferNullishOverAssignment: 'Prefer using nullish coalescing operator (`??{{ equals }}`) instead of an assignment expression, as it is simpler to read.',
|
57
61
|
preferNullishOverOr: 'Prefer using nullish coalescing operator (`??{{ equals }}`) instead of a logical {{ description }} (`||{{ equals }}`), as it is a safer operator.',
|
58
62
|
preferNullishOverTernary: 'Prefer using nullish coalescing operator (`??{{ equals }}`) instead of a ternary expression, as it is simpler to read.',
|
59
63
|
suggestNullish: 'Fix to nullish coalescing operator (`??{{ equals }}`).',
|
@@ -75,6 +79,10 @@ exports.default = (0, util_1.createRule)({
|
|
75
79
|
type: 'boolean',
|
76
80
|
description: 'Whether to ignore cases that are located within a conditional test.',
|
77
81
|
},
|
82
|
+
ignoreIfStatements: {
|
83
|
+
type: 'boolean',
|
84
|
+
description: 'Whether to ignore any if statements that could be simplified by using the nullish coalescing operator.',
|
85
|
+
},
|
78
86
|
ignoreMixedLogicalExpressions: {
|
79
87
|
type: 'boolean',
|
80
88
|
description: 'Whether to ignore any logical or expressions that are part of a mixed logical expression (with `&&`).',
|
@@ -124,6 +132,7 @@ exports.default = (0, util_1.createRule)({
|
|
124
132
|
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
|
125
133
|
ignoreBooleanCoercion: false,
|
126
134
|
ignoreConditionalTests: true,
|
135
|
+
ignoreIfStatements: false,
|
127
136
|
ignoreMixedLogicalExpressions: false,
|
128
137
|
ignorePrimitives: {
|
129
138
|
bigint: false,
|
@@ -134,7 +143,7 @@ exports.default = (0, util_1.createRule)({
|
|
134
143
|
ignoreTernaryTests: false,
|
135
144
|
},
|
136
145
|
],
|
137
|
-
create(context, [{ allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing, ignoreBooleanCoercion, ignoreConditionalTests, ignoreMixedLogicalExpressions, ignorePrimitives, ignoreTernaryTests, },]) {
|
146
|
+
create(context, [{ allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing, ignoreBooleanCoercion, ignoreConditionalTests, ignoreIfStatements, ignoreMixedLogicalExpressions, ignorePrimitives, ignoreTernaryTests, },]) {
|
138
147
|
const parserServices = (0, util_1.getParserServices)(context);
|
139
148
|
const compilerOptions = parserServices.program.getCompilerOptions();
|
140
149
|
const isStrictNullChecks = tsutils.isStrictCompilerOptionEnabled(compilerOptions, 'strictNullChecks');
|
@@ -258,6 +267,81 @@ exports.default = (0, util_1.createRule)({
|
|
258
267
|
],
|
259
268
|
});
|
260
269
|
}
|
270
|
+
function getNullishCoalescingParams(node, nonNullishNode, nodesInsideTestExpression, operator) {
|
271
|
+
let nullishCoalescingLeftNode;
|
272
|
+
let hasTruthinessCheck = false;
|
273
|
+
let hasNullCheckWithoutTruthinessCheck = false;
|
274
|
+
let hasUndefinedCheckWithoutTruthinessCheck = false;
|
275
|
+
if (!nodesInsideTestExpression.length) {
|
276
|
+
hasTruthinessCheck = true;
|
277
|
+
nullishCoalescingLeftNode =
|
278
|
+
node.test.type === utils_1.AST_NODE_TYPES.UnaryExpression
|
279
|
+
? node.test.argument
|
280
|
+
: node.test;
|
281
|
+
if (!areNodesSimilarMemberAccess(nullishCoalescingLeftNode, nonNullishNode)) {
|
282
|
+
return { isFixable: false };
|
283
|
+
}
|
284
|
+
}
|
285
|
+
else {
|
286
|
+
// we check that the test only contains null, undefined and the identifier
|
287
|
+
for (const testNode of nodesInsideTestExpression) {
|
288
|
+
if ((0, util_1.isNullLiteral)(testNode)) {
|
289
|
+
hasNullCheckWithoutTruthinessCheck = true;
|
290
|
+
}
|
291
|
+
else if ((0, util_1.isUndefinedIdentifier)(testNode)) {
|
292
|
+
hasUndefinedCheckWithoutTruthinessCheck = true;
|
293
|
+
}
|
294
|
+
else if (areNodesSimilarMemberAccess(testNode, nonNullishNode)) {
|
295
|
+
// Only consider the first expression in a multi-part nullish check,
|
296
|
+
// as subsequent expressions might not require all the optional chaining operators.
|
297
|
+
// For example: a?.b?.c !== undefined && a.b.c !== null ? a.b.c : 'foo';
|
298
|
+
// This works because `node.test` is always evaluated first in the loop
|
299
|
+
// and has the same or more necessary optional chaining operators
|
300
|
+
// than `node.alternate` or `node.consequent`.
|
301
|
+
nullishCoalescingLeftNode ??= testNode;
|
302
|
+
}
|
303
|
+
else {
|
304
|
+
return { isFixable: false };
|
305
|
+
}
|
306
|
+
}
|
307
|
+
}
|
308
|
+
if (!nullishCoalescingLeftNode) {
|
309
|
+
return { isFixable: false };
|
310
|
+
}
|
311
|
+
const isFixable = (() => {
|
312
|
+
if (hasTruthinessCheck) {
|
313
|
+
return isTruthinessCheckEligibleForPreferNullish({
|
314
|
+
node,
|
315
|
+
testNode: nullishCoalescingLeftNode,
|
316
|
+
});
|
317
|
+
}
|
318
|
+
// it is fixable if we check for both null and undefined, or not if neither
|
319
|
+
if (hasUndefinedCheckWithoutTruthinessCheck ===
|
320
|
+
hasNullCheckWithoutTruthinessCheck) {
|
321
|
+
return hasUndefinedCheckWithoutTruthinessCheck;
|
322
|
+
}
|
323
|
+
// it is fixable if we loosely check for either null or undefined
|
324
|
+
if (['==', '!='].includes(operator)) {
|
325
|
+
return true;
|
326
|
+
}
|
327
|
+
const type = parserServices.getTypeAtLocation(nullishCoalescingLeftNode);
|
328
|
+
const flags = (0, util_1.getTypeFlags)(type);
|
329
|
+
if (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
|
330
|
+
return false;
|
331
|
+
}
|
332
|
+
const hasNullType = (flags & ts.TypeFlags.Null) !== 0;
|
333
|
+
// it is fixable if we check for undefined and the type is not nullable
|
334
|
+
if (hasUndefinedCheckWithoutTruthinessCheck && !hasNullType) {
|
335
|
+
return true;
|
336
|
+
}
|
337
|
+
const hasUndefinedType = (flags & ts.TypeFlags.Undefined) !== 0;
|
338
|
+
// it is fixable if we check for null and the type can't be undefined
|
339
|
+
return hasNullCheckWithoutTruthinessCheck && !hasUndefinedType;
|
340
|
+
})();
|
341
|
+
return isFixable
|
342
|
+
? { isFixable: true, nullishCoalescingLeftNode }
|
343
|
+
: { isFixable: false };
|
344
|
+
}
|
261
345
|
return {
|
262
346
|
'AssignmentExpression[operator = "||="]'(node) {
|
263
347
|
checkAndFixWithPreferNullishOverOr(node, 'assignment', '=');
|
@@ -266,134 +350,12 @@ exports.default = (0, util_1.createRule)({
|
|
266
350
|
if (ignoreTernaryTests) {
|
267
351
|
return;
|
268
352
|
}
|
269
|
-
|
270
|
-
|
271
|
-
if (node.test.type === utils_1.AST_NODE_TYPES.BinaryExpression) {
|
272
|
-
nodesInsideTestExpression = [node.test.left, node.test.right];
|
273
|
-
if (node.test.operator === '==' ||
|
274
|
-
node.test.operator === '!=' ||
|
275
|
-
node.test.operator === '===' ||
|
276
|
-
node.test.operator === '!==') {
|
277
|
-
operator = node.test.operator;
|
278
|
-
}
|
279
|
-
}
|
280
|
-
else if (node.test.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
281
|
-
node.test.left.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
|
282
|
-
node.test.right.type === utils_1.AST_NODE_TYPES.BinaryExpression) {
|
283
|
-
nodesInsideTestExpression = [
|
284
|
-
node.test.left.left,
|
285
|
-
node.test.left.right,
|
286
|
-
node.test.right.left,
|
287
|
-
node.test.right.right,
|
288
|
-
];
|
289
|
-
if (['||', '||='].includes(node.test.operator)) {
|
290
|
-
if (node.test.left.operator === '===' &&
|
291
|
-
node.test.right.operator === '===') {
|
292
|
-
operator = '===';
|
293
|
-
}
|
294
|
-
else if (((node.test.left.operator === '===' ||
|
295
|
-
node.test.right.operator === '===') &&
|
296
|
-
(node.test.left.operator === '==' ||
|
297
|
-
node.test.right.operator === '==')) ||
|
298
|
-
(node.test.left.operator === '==' &&
|
299
|
-
node.test.right.operator === '==')) {
|
300
|
-
operator = '==';
|
301
|
-
}
|
302
|
-
}
|
303
|
-
else if (node.test.operator === '&&') {
|
304
|
-
if (node.test.left.operator === '!==' &&
|
305
|
-
node.test.right.operator === '!==') {
|
306
|
-
operator = '!==';
|
307
|
-
}
|
308
|
-
else if (((node.test.left.operator === '!==' ||
|
309
|
-
node.test.right.operator === '!==') &&
|
310
|
-
(node.test.left.operator === '!=' ||
|
311
|
-
node.test.right.operator === '!=')) ||
|
312
|
-
(node.test.left.operator === '!=' &&
|
313
|
-
node.test.right.operator === '!=')) {
|
314
|
-
operator = '!=';
|
315
|
-
}
|
316
|
-
}
|
317
|
-
}
|
318
|
-
let nullishCoalescingLeftNode;
|
319
|
-
let hasTruthinessCheck = false;
|
320
|
-
let hasNullCheckWithoutTruthinessCheck = false;
|
321
|
-
let hasUndefinedCheckWithoutTruthinessCheck = false;
|
322
|
-
if (!operator) {
|
323
|
-
let testNode;
|
324
|
-
hasTruthinessCheck = true;
|
325
|
-
if (isIdentifierOrMemberOrChainExpression(node.test)) {
|
326
|
-
testNode = node.test;
|
327
|
-
}
|
328
|
-
else if (node.test.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
|
329
|
-
isIdentifierOrMemberOrChainExpression(node.test.argument) &&
|
330
|
-
node.test.operator === '!') {
|
331
|
-
testNode = node.test.argument;
|
332
|
-
operator = '!';
|
333
|
-
}
|
334
|
-
if (testNode &&
|
335
|
-
areNodesSimilarMemberAccess(testNode, getBranchNodes(node, operator).nonNullishBranch)) {
|
336
|
-
nullishCoalescingLeftNode = testNode;
|
337
|
-
}
|
338
|
-
}
|
339
|
-
else {
|
340
|
-
// we check that the test only contains null, undefined and the identifier
|
341
|
-
for (const testNode of nodesInsideTestExpression) {
|
342
|
-
if ((0, util_1.isNullLiteral)(testNode)) {
|
343
|
-
hasNullCheckWithoutTruthinessCheck = true;
|
344
|
-
}
|
345
|
-
else if ((0, util_1.isUndefinedIdentifier)(testNode)) {
|
346
|
-
hasUndefinedCheckWithoutTruthinessCheck = true;
|
347
|
-
}
|
348
|
-
else if (areNodesSimilarMemberAccess(testNode, getBranchNodes(node, operator).nonNullishBranch)) {
|
349
|
-
// Only consider the first expression in a multi-part nullish check,
|
350
|
-
// as subsequent expressions might not require all the optional chaining operators.
|
351
|
-
// For example: a?.b?.c !== undefined && a.b.c !== null ? a.b.c : 'foo';
|
352
|
-
// This works because `node.test` is always evaluated first in the loop
|
353
|
-
// and has the same or more necessary optional chaining operators
|
354
|
-
// than `node.alternate` or `node.consequent`.
|
355
|
-
nullishCoalescingLeftNode ??= testNode;
|
356
|
-
}
|
357
|
-
else {
|
358
|
-
return;
|
359
|
-
}
|
360
|
-
}
|
361
|
-
}
|
362
|
-
if (!nullishCoalescingLeftNode) {
|
353
|
+
const { nodesInsideTestExpression, operator } = getOperatorAndNodesInsideTestExpression(node);
|
354
|
+
if (operator == null) {
|
363
355
|
return;
|
364
356
|
}
|
365
|
-
const
|
366
|
-
|
367
|
-
if (hasTruthinessCheck) {
|
368
|
-
return isTruthinessCheckEligibleForPreferNullish({
|
369
|
-
node,
|
370
|
-
testNode: nullishCoalescingLeftNode,
|
371
|
-
});
|
372
|
-
}
|
373
|
-
// it is fixable if we check for both null and undefined, or not if neither
|
374
|
-
if (hasUndefinedCheckWithoutTruthinessCheck ===
|
375
|
-
hasNullCheckWithoutTruthinessCheck) {
|
376
|
-
return hasUndefinedCheckWithoutTruthinessCheck;
|
377
|
-
}
|
378
|
-
// it is fixable if we loosely check for either null or undefined
|
379
|
-
if (operator === '==' || operator === '!=') {
|
380
|
-
return true;
|
381
|
-
}
|
382
|
-
const type = parserServices.getTypeAtLocation(nullishCoalescingLeftNode);
|
383
|
-
const flags = (0, util_1.getTypeFlags)(type);
|
384
|
-
if (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
|
385
|
-
return false;
|
386
|
-
}
|
387
|
-
const hasNullType = (flags & ts.TypeFlags.Null) !== 0;
|
388
|
-
// it is fixable if we check for undefined and the type is not nullable
|
389
|
-
if (hasUndefinedCheckWithoutTruthinessCheck && !hasNullType) {
|
390
|
-
return true;
|
391
|
-
}
|
392
|
-
const hasUndefinedType = (flags & ts.TypeFlags.Undefined) !== 0;
|
393
|
-
// it is fixable if we check for null and the type can't be undefined
|
394
|
-
return hasNullCheckWithoutTruthinessCheck && !hasUndefinedType;
|
395
|
-
})();
|
396
|
-
if (isFixableWithPreferNullishOverTernary) {
|
357
|
+
const nullishCoalescingParams = getNullishCoalescingParams(node, getBranchNodes(node, operator).nonNullishBranch, nodesInsideTestExpression, operator);
|
358
|
+
if (nullishCoalescingParams.isFixable) {
|
397
359
|
context.report({
|
398
360
|
node,
|
399
361
|
messageId: 'preferNullishOverTernary',
|
@@ -404,7 +366,63 @@ exports.default = (0, util_1.createRule)({
|
|
404
366
|
messageId: 'suggestNullish',
|
405
367
|
data: { equals: '' },
|
406
368
|
fix(fixer) {
|
407
|
-
return fixer.replaceText(node, `${(0, util_1.getTextWithParentheses)(context.sourceCode, nullishCoalescingLeftNode)} ?? ${(0, util_1.getTextWithParentheses)(context.sourceCode, getBranchNodes(node, operator).nullishBranch)}`);
|
369
|
+
return fixer.replaceText(node, `${(0, util_1.getTextWithParentheses)(context.sourceCode, nullishCoalescingParams.nullishCoalescingLeftNode)} ?? ${(0, util_1.getTextWithParentheses)(context.sourceCode, getBranchNodes(node, operator).nullishBranch)}`);
|
370
|
+
},
|
371
|
+
},
|
372
|
+
],
|
373
|
+
});
|
374
|
+
}
|
375
|
+
},
|
376
|
+
IfStatement(node) {
|
377
|
+
if (ignoreIfStatements || node.alternate != null) {
|
378
|
+
return;
|
379
|
+
}
|
380
|
+
let assignmentExpression;
|
381
|
+
if (node.consequent.type === utils_1.AST_NODE_TYPES.BlockStatement &&
|
382
|
+
node.consequent.body.length === 1 &&
|
383
|
+
node.consequent.body[0].type === utils_1.AST_NODE_TYPES.ExpressionStatement) {
|
384
|
+
assignmentExpression = node.consequent.body[0].expression;
|
385
|
+
}
|
386
|
+
else if (node.consequent.type === utils_1.AST_NODE_TYPES.ExpressionStatement) {
|
387
|
+
assignmentExpression = node.consequent.expression;
|
388
|
+
}
|
389
|
+
if (!assignmentExpression ||
|
390
|
+
assignmentExpression.type !== utils_1.AST_NODE_TYPES.AssignmentExpression ||
|
391
|
+
!isMemberAccessLike(assignmentExpression.left)) {
|
392
|
+
return;
|
393
|
+
}
|
394
|
+
const nullishCoalescingLeftNode = assignmentExpression.left;
|
395
|
+
const nullishCoalescingRightNode = assignmentExpression.right;
|
396
|
+
const { nodesInsideTestExpression, operator } = getOperatorAndNodesInsideTestExpression(node);
|
397
|
+
if (operator == null || !['!', '==', '==='].includes(operator)) {
|
398
|
+
return;
|
399
|
+
}
|
400
|
+
const nullishCoalescingParams = getNullishCoalescingParams(node, nullishCoalescingLeftNode, nodesInsideTestExpression, operator);
|
401
|
+
if (nullishCoalescingParams.isFixable) {
|
402
|
+
// Handle comments
|
403
|
+
const isConsequentNodeBlockStatement = node.consequent.type === utils_1.AST_NODE_TYPES.BlockStatement;
|
404
|
+
const commentsBefore = formatComments(context.sourceCode.getCommentsBefore(assignmentExpression), isConsequentNodeBlockStatement ? '\n' : ' ');
|
405
|
+
const commentsAfter = isConsequentNodeBlockStatement
|
406
|
+
? formatComments(context.sourceCode.getCommentsAfter(assignmentExpression.parent), '\n')
|
407
|
+
: '';
|
408
|
+
context.report({
|
409
|
+
node,
|
410
|
+
messageId: 'preferNullishOverAssignment',
|
411
|
+
data: { equals: '=' },
|
412
|
+
suggest: [
|
413
|
+
{
|
414
|
+
messageId: 'suggestNullish',
|
415
|
+
data: { equals: '=' },
|
416
|
+
fix(fixer) {
|
417
|
+
const fixes = [];
|
418
|
+
if (commentsBefore) {
|
419
|
+
fixes.push(fixer.insertTextBefore(node, commentsBefore));
|
420
|
+
}
|
421
|
+
fixes.push(fixer.replaceText(node, `${(0, util_1.getTextWithParentheses)(context.sourceCode, nullishCoalescingLeftNode)} ??= ${(0, util_1.getTextWithParentheses)(context.sourceCode, nullishCoalescingRightNode)};`));
|
422
|
+
if (commentsAfter) {
|
423
|
+
fixes.push(fixer.insertTextAfter(node, ` ${commentsAfter.slice(0, -1)}`));
|
424
|
+
}
|
425
|
+
return fixes;
|
408
426
|
},
|
409
427
|
},
|
410
428
|
],
|
@@ -512,8 +530,21 @@ function isMixedLogicalExpression(node) {
|
|
512
530
|
function areNodesSimilarMemberAccess(a, b) {
|
513
531
|
if (a.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
514
532
|
b.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
515
|
-
|
516
|
-
|
533
|
+
if (!areNodesSimilarMemberAccess(a.object, b.object)) {
|
534
|
+
return false;
|
535
|
+
}
|
536
|
+
if (a.computed === b.computed) {
|
537
|
+
return (0, util_1.isNodeEqual)(a.property, b.property);
|
538
|
+
}
|
539
|
+
if (a.property.type === utils_1.AST_NODE_TYPES.Literal &&
|
540
|
+
b.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
541
|
+
return a.property.value === b.property.name;
|
542
|
+
}
|
543
|
+
if (a.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
544
|
+
b.property.type === utils_1.AST_NODE_TYPES.Literal) {
|
545
|
+
return a.property.name === b.property.value;
|
546
|
+
}
|
547
|
+
return false;
|
517
548
|
}
|
518
549
|
if (a.type === utils_1.AST_NODE_TYPES.ChainExpression ||
|
519
550
|
b.type === utils_1.AST_NODE_TYPES.ChainExpression) {
|
@@ -527,8 +558,82 @@ function areNodesSimilarMemberAccess(a, b) {
|
|
527
558
|
* - the "nullish branch" is the branch when test node is nullish
|
528
559
|
*/
|
529
560
|
function getBranchNodes(node, operator) {
|
530
|
-
if (
|
561
|
+
if (['', '!=', '!=='].includes(operator)) {
|
531
562
|
return { nonNullishBranch: node.consequent, nullishBranch: node.alternate };
|
532
563
|
}
|
533
564
|
return { nonNullishBranch: node.alternate, nullishBranch: node.consequent };
|
534
565
|
}
|
566
|
+
function getOperatorAndNodesInsideTestExpression(node) {
|
567
|
+
let operator = null;
|
568
|
+
let nodesInsideTestExpression = [];
|
569
|
+
if (isMemberAccessLike(node.test) ||
|
570
|
+
node.test.type === utils_1.AST_NODE_TYPES.UnaryExpression) {
|
571
|
+
operator = getNonBinaryNodeOperator(node.test);
|
572
|
+
}
|
573
|
+
else if (node.test.type === utils_1.AST_NODE_TYPES.BinaryExpression) {
|
574
|
+
nodesInsideTestExpression = [node.test.left, node.test.right];
|
575
|
+
if (node.test.operator === '==' ||
|
576
|
+
node.test.operator === '!=' ||
|
577
|
+
node.test.operator === '===' ||
|
578
|
+
node.test.operator === '!==') {
|
579
|
+
operator = node.test.operator;
|
580
|
+
}
|
581
|
+
}
|
582
|
+
else if (node.test.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
583
|
+
node.test.left.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
|
584
|
+
node.test.right.type === utils_1.AST_NODE_TYPES.BinaryExpression) {
|
585
|
+
if (isNodeNullishComparison(node.test.left) ||
|
586
|
+
isNodeNullishComparison(node.test.right)) {
|
587
|
+
return { nodesInsideTestExpression, operator };
|
588
|
+
}
|
589
|
+
nodesInsideTestExpression = [
|
590
|
+
node.test.left.left,
|
591
|
+
node.test.left.right,
|
592
|
+
node.test.right.left,
|
593
|
+
node.test.right.right,
|
594
|
+
];
|
595
|
+
if (['||', '||='].includes(node.test.operator)) {
|
596
|
+
if (node.test.left.operator === '===' &&
|
597
|
+
node.test.right.operator === '===') {
|
598
|
+
operator = '===';
|
599
|
+
}
|
600
|
+
else if (((node.test.left.operator === '===' ||
|
601
|
+
node.test.right.operator === '===') &&
|
602
|
+
(node.test.left.operator === '==' ||
|
603
|
+
node.test.right.operator === '==')) ||
|
604
|
+
(node.test.left.operator === '==' && node.test.right.operator === '==')) {
|
605
|
+
operator = '==';
|
606
|
+
}
|
607
|
+
}
|
608
|
+
else if (node.test.operator === '&&') {
|
609
|
+
if (node.test.left.operator === '!==' &&
|
610
|
+
node.test.right.operator === '!==') {
|
611
|
+
operator = '!==';
|
612
|
+
}
|
613
|
+
else if (((node.test.left.operator === '!==' ||
|
614
|
+
node.test.right.operator === '!==') &&
|
615
|
+
(node.test.left.operator === '!=' ||
|
616
|
+
node.test.right.operator === '!=')) ||
|
617
|
+
(node.test.left.operator === '!=' && node.test.right.operator === '!=')) {
|
618
|
+
operator = '!=';
|
619
|
+
}
|
620
|
+
}
|
621
|
+
}
|
622
|
+
return { nodesInsideTestExpression, operator };
|
623
|
+
}
|
624
|
+
function getNonBinaryNodeOperator(node) {
|
625
|
+
if (node.type !== utils_1.AST_NODE_TYPES.UnaryExpression) {
|
626
|
+
return '';
|
627
|
+
}
|
628
|
+
if (isMemberAccessLike(node.argument) && node.operator === '!') {
|
629
|
+
return '!';
|
630
|
+
}
|
631
|
+
return null;
|
632
|
+
}
|
633
|
+
function formatComments(comments, separator) {
|
634
|
+
return comments
|
635
|
+
.map(({ type, value }) => type === utils_1.AST_TOKEN_TYPES.Line
|
636
|
+
? `//${value}${separator}`
|
637
|
+
: `/*${value}*/${separator}`)
|
638
|
+
.join('');
|
639
|
+
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"use-unknown-in-catch-callback-variable.d.ts","sourceRoot":"","sources":["../../src/rules/use-unknown-in-catch-callback-variable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAgBnE,MAAM,MAAM,UAAU,GAClB,wCAAwC,GACxC,oCAAoC,GACpC,YAAY,GACZ,qCAAqC,GACrC,sCAAsC,GACtC,mCAAmC,GACnC,+BAA+B,CAAC;;AAKpC,
|
1
|
+
{"version":3,"file":"use-unknown-in-catch-callback-variable.d.ts","sourceRoot":"","sources":["../../src/rules/use-unknown-in-catch-callback-variable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAgBnE,MAAM,MAAM,UAAU,GAClB,wCAAwC,GACxC,oCAAoC,GACpC,YAAY,GACZ,qCAAqC,GACrC,sCAAsC,GACtC,mCAAmC,GACnC,+BAA+B,CAAC;;AAKpC,wBAkSG"}
|
@@ -46,7 +46,6 @@ exports.default = (0, util_1.createRule)({
|
|
46
46
|
recommended: 'strict',
|
47
47
|
requiresTypeChecking: true,
|
48
48
|
},
|
49
|
-
fixable: 'code',
|
50
49
|
hasSuggestions: true,
|
51
50
|
messages: {
|
52
51
|
addUnknownRestTypeAnnotationSuggestion: 'Add an explicit `: [unknown]` type annotation to the rejection callback rest variable.',
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"isAssignee.d.ts","sourceRoot":"","sources":["../../src/util/isAssignee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,OAAO,
|
1
|
+
{"version":3,"file":"isAssignee.d.ts","sourceRoot":"","sources":["../../src/util/isAssignee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,OAAO,CA+DvD"}
|
package/dist/util/isAssignee.js
CHANGED
@@ -38,5 +38,13 @@ function isAssignee(node) {
|
|
38
38
|
isAssignee(parent.parent)) {
|
39
39
|
return true;
|
40
40
|
}
|
41
|
+
// (a[i] as number)++, [...a[i]!] = [0], etc.
|
42
|
+
if ((parent.type === utils_1.AST_NODE_TYPES.TSNonNullExpression ||
|
43
|
+
parent.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
|
44
|
+
parent.type === utils_1.AST_NODE_TYPES.TSTypeAssertion ||
|
45
|
+
parent.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression) &&
|
46
|
+
isAssignee(parent)) {
|
47
|
+
return true;
|
48
|
+
}
|
41
49
|
return false;
|
42
50
|
}
|
@@ -17,6 +17,54 @@ This rule reports when you may consider replacing:
|
|
17
17
|
- An `||` operator with `??`
|
18
18
|
- An `||=` operator with `??=`
|
19
19
|
- Ternary expressions (`?:`) that are equivalent to `||` or `??` with `??`
|
20
|
+
- Assignment expressions (`=`) that can be safely replaced by `??=`
|
21
|
+
|
22
|
+
## Examples
|
23
|
+
|
24
|
+
<Tabs>
|
25
|
+
<TabItem value="❌ Incorrect">
|
26
|
+
|
27
|
+
```ts
|
28
|
+
declare const a: string | null;
|
29
|
+
declare const b: string | null;
|
30
|
+
|
31
|
+
const c = a || b;
|
32
|
+
|
33
|
+
declare let foo: { a: string } | null;
|
34
|
+
declare function makeFoo(): { a: string };
|
35
|
+
|
36
|
+
function lazyInitializeFooByTruthiness() {
|
37
|
+
if (!foo) {
|
38
|
+
foo = makeFoo();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
function lazyInitializeFooByNullCheck() {
|
43
|
+
if (foo == null) {
|
44
|
+
foo = makeFoo();
|
45
|
+
}
|
46
|
+
}
|
47
|
+
```
|
48
|
+
|
49
|
+
</TabItem>
|
50
|
+
<TabItem value="✅ Correct">
|
51
|
+
|
52
|
+
```ts
|
53
|
+
declare const a: string | null;
|
54
|
+
declare const b: string | null;
|
55
|
+
|
56
|
+
const c = a ?? b;
|
57
|
+
|
58
|
+
declare let foo: { a: string } | null;
|
59
|
+
declare function makeFoo(): { a: string };
|
60
|
+
|
61
|
+
function lazyInitializeFoo() {
|
62
|
+
foo ??= makeFoo();
|
63
|
+
}
|
64
|
+
```
|
65
|
+
|
66
|
+
</TabItem>
|
67
|
+
</Tabs>
|
20
68
|
|
21
69
|
:::caution
|
22
70
|
This rule will not work as expected if [`strictNullChecks`](https://www.typescriptlang.org/tsconfig#strictNullChecks) is not enabled.
|
@@ -70,6 +118,49 @@ c ?? 'a string';
|
|
70
118
|
</TabItem>
|
71
119
|
</Tabs>
|
72
120
|
|
121
|
+
### `ignoreIfStatements`
|
122
|
+
|
123
|
+
{/* insert option description */}
|
124
|
+
|
125
|
+
Examples of code for this rule with `{ ignoreIfStatements: false }`:
|
126
|
+
|
127
|
+
<Tabs>
|
128
|
+
<TabItem value="❌ Incorrect">
|
129
|
+
|
130
|
+
```ts option='{ "ignoreIfStatements": false }'
|
131
|
+
declare let foo: { a: string } | null;
|
132
|
+
declare function makeFoo(): { a: string };
|
133
|
+
|
134
|
+
function lazyInitializeFoo1() {
|
135
|
+
if (!foo) {
|
136
|
+
foo = makeFoo();
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
function lazyInitializeFoo2() {
|
141
|
+
if (!foo) foo = makeFoo();
|
142
|
+
}
|
143
|
+
```
|
144
|
+
|
145
|
+
</TabItem>
|
146
|
+
<TabItem value="✅ Correct">
|
147
|
+
|
148
|
+
```ts option='{ "ignoreIfStatements": false }'
|
149
|
+
declare let foo: { a: string } | null;
|
150
|
+
declare function makeFoo(): { a: string };
|
151
|
+
|
152
|
+
function lazyInitializeFoo1() {
|
153
|
+
foo ??= makeFoo();
|
154
|
+
}
|
155
|
+
|
156
|
+
function lazyInitializeFoo2() {
|
157
|
+
foo ??= makeFoo();
|
158
|
+
}
|
159
|
+
```
|
160
|
+
|
161
|
+
</TabItem>
|
162
|
+
</Tabs>
|
163
|
+
|
73
164
|
### `ignoreConditionalTests`
|
74
165
|
|
75
166
|
{/* insert option description */}
|
@@ -255,3 +346,4 @@ If you are not using TypeScript 3.7 (or greater), then you will not be able to u
|
|
255
346
|
|
256
347
|
- [TypeScript 3.7 Release Notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html)
|
257
348
|
- [Nullish Coalescing Operator Proposal](https://github.com/tc39/proposal-nullish-coalescing/)
|
349
|
+
- [`logical-assignment-operators`](https://eslint.org/docs/latest/rules/logical-assignment-operators)
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@typescript-eslint/eslint-plugin",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.28.1-alpha.0",
|
4
4
|
"description": "TypeScript plugin for ESLint",
|
5
5
|
"files": [
|
6
6
|
"dist",
|
@@ -62,10 +62,10 @@
|
|
62
62
|
},
|
63
63
|
"dependencies": {
|
64
64
|
"@eslint-community/regexpp": "^4.10.0",
|
65
|
-
"@typescript-eslint/scope-manager": "8.
|
66
|
-
"@typescript-eslint/type-utils": "8.
|
67
|
-
"@typescript-eslint/utils": "8.
|
68
|
-
"@typescript-eslint/visitor-keys": "8.
|
65
|
+
"@typescript-eslint/scope-manager": "8.28.1-alpha.0",
|
66
|
+
"@typescript-eslint/type-utils": "8.28.1-alpha.0",
|
67
|
+
"@typescript-eslint/utils": "8.28.1-alpha.0",
|
68
|
+
"@typescript-eslint/visitor-keys": "8.28.1-alpha.0",
|
69
69
|
"graphemer": "^1.4.0",
|
70
70
|
"ignore": "^5.3.1",
|
71
71
|
"natural-compare": "^1.4.0",
|
@@ -76,8 +76,8 @@
|
|
76
76
|
"@types/marked": "^5.0.2",
|
77
77
|
"@types/mdast": "^4.0.3",
|
78
78
|
"@types/natural-compare": "*",
|
79
|
-
"@typescript-eslint/rule-schema-to-typescript-types": "8.
|
80
|
-
"@typescript-eslint/rule-tester": "8.
|
79
|
+
"@typescript-eslint/rule-schema-to-typescript-types": "8.28.1-alpha.0",
|
80
|
+
"@typescript-eslint/rule-tester": "8.28.1-alpha.0",
|
81
81
|
"ajv": "^6.12.6",
|
82
82
|
"cross-env": "^7.0.3",
|
83
83
|
"cross-fetch": "*",
|