eslint-plugin-ts-std-forge 0.1.3 → 0.1.5
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/plugin.d.mts +1 -1
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +1 -0
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.d.mts +1 -1
- package/dist/rule-types.d.mts.map +1 -1
- package/dist/rules/ast-utils.d.mts +41 -0
- package/dist/rules/ast-utils.d.mts.map +1 -0
- package/dist/rules/ast-utils.mjs +101 -0
- package/dist/rules/ast-utils.mjs.map +1 -0
- package/dist/rules/import-utils.d.mts +1 -1
- package/dist/rules/import-utils.d.mts.map +1 -1
- package/dist/rules/import-utils.mjs +2 -1
- package/dist/rules/import-utils.mjs.map +1 -1
- package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
- package/dist/rules/prefer-is-non-null-object.mjs +55 -43
- package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
- package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
- package/dist/rules/prefer-is-record-and-has-key.mjs +22 -17
- package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
- package/dist/rules/prefer-safe-array-is-array.d.mts.map +1 -1
- package/dist/rules/prefer-safe-array-is-array.mjs +23 -14
- package/dist/rules/prefer-safe-array-is-array.mjs.map +1 -1
- package/dist/rules/prefer-safe-array-length-guard.d.mts.map +1 -1
- package/dist/rules/prefer-safe-array-length-guard.mjs +19 -15
- package/dist/rules/prefer-safe-array-length-guard.mjs.map +1 -1
- package/dist/rules/prefer-safe-number-parse-integer.d.mts.map +1 -1
- package/dist/rules/prefer-safe-number-parse-integer.mjs +16 -17
- package/dist/rules/prefer-safe-number-parse-integer.mjs.map +1 -1
- package/dist/rules/prefer-safe-number-parse.d.mts.map +1 -1
- package/dist/rules/prefer-safe-number-parse.mjs +14 -16
- package/dist/rules/prefer-safe-number-parse.mjs.map +1 -1
- package/dist/types.d.mts +2 -2
- package/dist/types.d.mts.map +1 -1
- package/package.json +24 -22
- package/src/plugin.mts +5 -4
- package/src/plugin.test.mts +0 -13
- package/src/rule-types.mts +2 -2
- package/src/rules/ast-utils.mts +147 -0
- package/src/rules/import-utils.mts +4 -2
- package/src/rules/prefer-is-non-null-object.mts +63 -38
- package/src/rules/prefer-is-non-null-object.test.mts +54 -0
- package/src/rules/prefer-is-record-and-has-key.mts +34 -21
- package/src/rules/prefer-is-record-and-has-key.test.mts +128 -0
- package/src/rules/prefer-safe-array-is-array.mts +34 -16
- package/src/rules/prefer-safe-array-is-array.test.mts +93 -0
- package/src/rules/prefer-safe-array-length-guard.mts +32 -19
- package/src/rules/prefer-safe-array-length-guard.test.mts +98 -0
- package/src/rules/prefer-safe-number-parse-integer.mts +29 -23
- package/src/rules/prefer-safe-number-parse-integer.test.mts +104 -0
- package/src/rules/prefer-safe-number-parse.mts +25 -21
- package/src/rules/prefer-safe-number-parse.test.mts +97 -0
- package/src/rules/rules.mts +1 -1
- package/src/types.mts +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
|
+
import { getArgumentText, getValueType, skipTypeWrappers, } from './ast-utils.mjs';
|
|
2
3
|
import { buildImportFixes, getNamedImports, getTsStdForgeImport, } from './import-utils.mjs';
|
|
3
4
|
|
|
4
5
|
|
|
@@ -46,8 +47,8 @@ export const preferSafeArrayLengthGuard = {
|
|
|
46
47
|
const sourceCode = context.sourceCode;
|
|
47
48
|
const program = sourceCode.ast;
|
|
48
49
|
const tsStdForgeImport = getTsStdForgeImport(program);
|
|
49
|
-
const
|
|
50
|
-
|
|
50
|
+
const checker = sourceCode.parserServices?.program?.getTypeChecker();
|
|
51
|
+
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
|
|
@@ -56,22 +57,23 @@ export const preferSafeArrayLengthGuard = {
|
|
|
56
57
|
const isArrayLike = (
|
|
57
58
|
|
|
58
59
|
expression) => {
|
|
59
|
-
if (checker === undefined)
|
|
60
|
-
return false;
|
|
61
|
-
const tsNode = services?.esTreeNodeToTSNodeMap?.get(expression);
|
|
62
|
-
if (tsNode === undefined)
|
|
60
|
+
if (checker === undefined) {
|
|
63
61
|
return false;
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
}
|
|
63
|
+
const type = getValueType(sourceCode, expression);
|
|
64
|
+
return (type !== undefined &&
|
|
65
|
+
(checker.isArrayType(type) || checker.isTupleType(type)));
|
|
66
66
|
};
|
|
67
67
|
const mut_nodesToFix = [];
|
|
68
68
|
return {
|
|
69
69
|
BinaryExpression: (node) => {
|
|
70
70
|
const matched = matchLengthComparison(node);
|
|
71
|
-
if (matched === undefined)
|
|
71
|
+
if (matched === undefined) {
|
|
72
72
|
return;
|
|
73
|
-
|
|
73
|
+
}
|
|
74
|
+
if (!isArrayLike(matched.arrayExpression)) {
|
|
74
75
|
return;
|
|
76
|
+
}
|
|
75
77
|
mut_nodesToFix.push({ node, ...matched });
|
|
76
78
|
},
|
|
77
79
|
'Program:exit': () => {
|
|
@@ -82,7 +84,7 @@ export const preferSafeArrayLengthGuard = {
|
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
for (const [index, { node, arrayExpression, guard },] of mut_nodesToFix.entries()) {
|
|
85
|
-
const arrayText = sourceCode
|
|
87
|
+
const arrayText = getArgumentText(sourceCode, arrayExpression);
|
|
86
88
|
context.report({
|
|
87
89
|
node,
|
|
88
90
|
messageId: MESSAGE_IDS[guard],
|
|
@@ -114,14 +116,16 @@ const matchLengthComparison = (
|
|
|
114
116
|
|
|
115
117
|
|
|
116
118
|
node) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
const left = skipTypeWrappers(node.left);
|
|
122
|
+
const right = skipTypeWrappers(node.right);
|
|
120
123
|
const lengthOnLeft = isLengthAccess(left);
|
|
121
124
|
const lengthSide = lengthOnLeft ? left : right;
|
|
122
125
|
const boundSide = lengthOnLeft ? right : left;
|
|
123
|
-
if (!isLengthAccess(lengthSide))
|
|
126
|
+
if (!isLengthAccess(lengthSide)) {
|
|
124
127
|
return undefined;
|
|
128
|
+
}
|
|
125
129
|
|
|
126
130
|
|
|
127
131
|
if (boundSide.type !== AST_NODE_TYPES.Literal ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-safe-array-length-guard.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-array-length-guard.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAQ5B;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG;IAClB,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE;IAC/C,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE;IAClD,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE;IAChD,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE;CAK/C,CAAC;AAEL,wEAAwE;AACxE,MAAM,OAAO,GAAmC;IAC9C,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;CACF,CAAC;AAEX,MAAM,WAAW,GAAsC;IACrD,OAAO,EAAE,YAAY;IACrB,UAAU,EAAE,eAAe;CACnB,CAAC;AAEX,MAAM,CAAC,MAAM,0BAA0B,GAGnC;IACF,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,+LAA+L;SAClM;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,UAAU,EACR,uJAAuJ;YACzJ,aAAa,EACX,iKAAiK;SACpK;KACF;IAED,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC;QAE/B,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEtD,MAAM,
|
|
1
|
+
{"version":3,"file":"prefer-safe-array-length-guard.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-array-length-guard.mts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-safe-number-parse-integer.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse-integer.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"prefer-safe-number-parse-integer.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse-integer.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAclC,KAAK,OAAO,GAAG,SAAS,EAAE,CAAC;AAE3B,KAAK,UAAU,GAAG,2BAA2B,CAAC;AAkB9C;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,UAAU,CAC5D,UAAU,EACV,OAAO,CAwHC,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
2
|
import * as ts from 'typescript';
|
|
3
|
+
import { getArgumentText, getValueType, isIdentifierNamed, skipTypeWrappers, } from './ast-utils.mjs';
|
|
3
4
|
import { buildImportFixes, getNamedImports, getTsStdForgeImport, } from './import-utils.mjs';
|
|
4
5
|
|
|
5
6
|
|
|
@@ -36,32 +37,34 @@ export const preferSafeNumberParseInteger = {
|
|
|
36
37
|
const sourceCode = context.sourceCode;
|
|
37
38
|
const program = sourceCode.ast;
|
|
38
39
|
const tsStdForgeImport = getTsStdForgeImport(program);
|
|
39
|
-
const services = sourceCode.parserServices;
|
|
40
40
|
const mut_nodesToFix = [];
|
|
41
41
|
return {
|
|
42
42
|
CallExpression: (node) => {
|
|
43
|
-
const
|
|
43
|
+
const callee = skipTypeWrappers(node.callee);
|
|
44
44
|
|
|
45
45
|
const isGlobalParseInt = callee.type === AST_NODE_TYPES.Identifier &&
|
|
46
46
|
callee.name === 'parseInt';
|
|
47
47
|
const isNumberParseInt = callee.type === AST_NODE_TYPES.MemberExpression &&
|
|
48
48
|
!callee.computed &&
|
|
49
|
-
callee.object
|
|
50
|
-
callee.object.name === 'Number' &&
|
|
49
|
+
isIdentifierNamed(callee.object, 'Number') &&
|
|
51
50
|
callee.property.type === AST_NODE_TYPES.Identifier &&
|
|
52
51
|
callee.property.name === 'parseInt';
|
|
53
|
-
if (!isGlobalParseInt && !isNumberParseInt)
|
|
52
|
+
if (!isGlobalParseInt && !isNumberParseInt) {
|
|
54
53
|
return;
|
|
54
|
+
}
|
|
55
55
|
const args = node.arguments;
|
|
56
56
|
const firstArg = args[0];
|
|
57
|
-
if (firstArg === undefined)
|
|
57
|
+
if (firstArg === undefined) {
|
|
58
58
|
return;
|
|
59
|
+
}
|
|
59
60
|
|
|
60
|
-
if (firstArg.type === AST_NODE_TYPES.SpreadElement)
|
|
61
|
+
if (firstArg.type === AST_NODE_TYPES.SpreadElement) {
|
|
61
62
|
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
62
65
|
|
|
63
66
|
if (args.length >= 2) {
|
|
64
|
-
const radix = args[1];
|
|
67
|
+
const radix = args[1] === undefined ? undefined : skipTypeWrappers(args[1]);
|
|
65
68
|
if (radix?.type !== AST_NODE_TYPES.Literal || radix.value !== 10) {
|
|
66
69
|
return;
|
|
67
70
|
}
|
|
@@ -69,22 +72,18 @@ export const preferSafeNumberParseInteger = {
|
|
|
69
72
|
|
|
70
73
|
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const tsNode = services.esTreeNodeToTSNodeMap?.get(firstArg);
|
|
76
|
-
if (tsNode === undefined)
|
|
77
|
-
return;
|
|
78
|
-
const argType = checker.getTypeAtLocation(tsNode);
|
|
79
|
-
if (!isStringType(argType))
|
|
75
|
+
|
|
76
|
+
const argType = getValueType(sourceCode, firstArg);
|
|
77
|
+
if (argType === undefined || !isStringType(argType)) {
|
|
80
78
|
return;
|
|
79
|
+
}
|
|
81
80
|
mut_nodesToFix.push({ node, argExpression: firstArg });
|
|
82
81
|
},
|
|
83
82
|
'Program:exit': () => {
|
|
84
83
|
const namedImports = getNamedImports(tsStdForgeImport);
|
|
85
84
|
const missingImports = ['Result', 'SafeNumber'].filter((name) => !namedImports.includes(name));
|
|
86
85
|
for (const [index, { node, argExpression },] of mut_nodesToFix.entries()) {
|
|
87
|
-
const argText = sourceCode
|
|
86
|
+
const argText = getArgumentText(sourceCode, argExpression);
|
|
88
87
|
context.report({
|
|
89
88
|
node,
|
|
90
89
|
messageId: 'useSafeNumberParseInteger',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-safe-number-parse-integer.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse-integer.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAM5B;;;;;GAKG;AACH,8EAA8E;AAC9E,MAAM,YAAY,GAAG,CAAC,IAAa,EAAW,EAAE;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAW,CAAC;IAE9D,OAAO,CACL,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAC9D,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAGrC;IACF,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,uIAAuI;SAC1I;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,yBAAyB,EACvB,sHAAsH;SACzH;KACF;IAED,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC;QAE/B,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEtD,MAAM,
|
|
1
|
+
{"version":3,"file":"prefer-safe-number-parse-integer.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse-integer.mts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-safe-number-parse.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"prefer-safe-number-parse.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAclC,KAAK,OAAO,GAAG,SAAS,EAAE,CAAC;AAE3B,KAAK,UAAU,GAAG,oBAAoB,CAAC;AAkBvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CAiHjE,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
2
|
import * as ts from 'typescript';
|
|
3
|
+
import { getArgumentText, getValueType, isIdentifierNamed, skipTypeWrappers, } from './ast-utils.mjs';
|
|
3
4
|
import { buildImportFixes, getNamedImports, getTsStdForgeImport, } from './import-utils.mjs';
|
|
4
5
|
|
|
5
6
|
|
|
@@ -42,51 +43,48 @@ export const preferSafeNumberParse = {
|
|
|
42
43
|
const sourceCode = context.sourceCode;
|
|
43
44
|
const program = sourceCode.ast;
|
|
44
45
|
const tsStdForgeImport = getTsStdForgeImport(program);
|
|
45
|
-
const services = sourceCode.parserServices;
|
|
46
46
|
const mut_nodesToFix = [];
|
|
47
47
|
return {
|
|
48
48
|
CallExpression: (node) => {
|
|
49
|
-
const
|
|
49
|
+
const callee = skipTypeWrappers(node.callee);
|
|
50
50
|
|
|
51
51
|
const isGlobalParseFloat = callee.type === AST_NODE_TYPES.Identifier &&
|
|
52
52
|
callee.name === 'parseFloat';
|
|
53
53
|
|
|
54
54
|
const isNumberParseFloat = callee.type === AST_NODE_TYPES.MemberExpression &&
|
|
55
55
|
!callee.computed &&
|
|
56
|
-
callee.object
|
|
57
|
-
callee.object.name === 'Number' &&
|
|
56
|
+
isIdentifierNamed(callee.object, 'Number') &&
|
|
58
57
|
callee.property.type === AST_NODE_TYPES.Identifier &&
|
|
59
58
|
callee.property.name === 'parseFloat';
|
|
60
59
|
|
|
61
60
|
const isNumberCall = callee.type === AST_NODE_TYPES.Identifier && callee.name === 'Number';
|
|
62
|
-
if (!isGlobalParseFloat && !isNumberParseFloat && !isNumberCall)
|
|
61
|
+
if (!isGlobalParseFloat && !isNumberParseFloat && !isNumberCall) {
|
|
63
62
|
return;
|
|
63
|
+
}
|
|
64
64
|
const args = node.arguments;
|
|
65
65
|
const firstArg = args[0];
|
|
66
|
-
if (firstArg === undefined)
|
|
66
|
+
if (firstArg === undefined) {
|
|
67
67
|
return;
|
|
68
|
+
}
|
|
68
69
|
|
|
69
|
-
if (firstArg.type === AST_NODE_TYPES.SpreadElement)
|
|
70
|
+
if (firstArg.type === AST_NODE_TYPES.SpreadElement) {
|
|
70
71
|
return;
|
|
72
|
+
}
|
|
71
73
|
|
|
72
74
|
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const tsNode = services.esTreeNodeToTSNodeMap?.get(firstArg);
|
|
78
|
-
if (tsNode === undefined)
|
|
79
|
-
return;
|
|
80
|
-
const argType = checker.getTypeAtLocation(tsNode);
|
|
81
|
-
if (!isStringType(argType))
|
|
76
|
+
|
|
77
|
+
const argType = getValueType(sourceCode, firstArg);
|
|
78
|
+
if (argType === undefined || !isStringType(argType)) {
|
|
82
79
|
return;
|
|
80
|
+
}
|
|
83
81
|
mut_nodesToFix.push({ node, argExpression: firstArg });
|
|
84
82
|
},
|
|
85
83
|
'Program:exit': () => {
|
|
86
84
|
const namedImports = getNamedImports(tsStdForgeImport);
|
|
87
85
|
const missingImports = ['Result', 'SafeNumber'].filter((name) => !namedImports.includes(name));
|
|
88
86
|
for (const [index, { node, argExpression },] of mut_nodesToFix.entries()) {
|
|
89
|
-
const argText = sourceCode
|
|
87
|
+
const argText = getArgumentText(sourceCode, argExpression);
|
|
90
88
|
context.report({
|
|
91
89
|
node,
|
|
92
90
|
messageId: 'useSafeNumberParse',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-safe-number-parse.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAM5B;;;;;GAKG;AACH,8EAA8E;AAC9E,MAAM,YAAY,GAAG,CAAC,IAAa,EAAW,EAAE;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAW,CAAC;IAE9D,OAAO,CACL,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAC9D,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA6C;IAC7E,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,mKAAmK;SACtK;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,kBAAkB,EAChB,+GAA+G;SAClH;KACF;IAED,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAEtC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC;QAE/B,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEtD,MAAM,
|
|
1
|
+
{"version":3,"file":"prefer-safe-number-parse.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse.mts"],"names":[],"mappings":"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"}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
import type { DeepReadonly } from 'ts-type-forge';
|
|
3
3
|
export type ESLintPlugin = DeepReadonly<TSESLint.FlatConfig.Plugin>;
|
|
4
4
|
export type ESLintFlatConfig = DeepReadonly<TSESLint.FlatConfig.Config>;
|
|
5
5
|
//# sourceMappingURL=types.d.mts.map
|
package/dist/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-ts-std-forge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "ESLint rules that steer code toward ts-std-forge idioms.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,21 +34,21 @@
|
|
|
34
34
|
"LICENSE"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@typescript-eslint/utils": "^8.70.
|
|
37
|
+
"@typescript-eslint/utils": "^8.70.1",
|
|
38
38
|
"ts-std-forge": "0.5.1",
|
|
39
39
|
"ts-type-forge": "~9.2.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@typescript-eslint/parser": "8.70.
|
|
43
|
-
"@typescript-eslint/rule-tester": "8.70.
|
|
42
|
+
"@typescript-eslint/parser": "8.70.1",
|
|
43
|
+
"@typescript-eslint/rule-tester": "8.70.1",
|
|
44
44
|
"dedent": "1.7.2",
|
|
45
|
-
"eslint-config-typed": "5.
|
|
46
|
-
"eslint-plugin-ts-fortress": "1.
|
|
47
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
48
|
-
"prettier": "3.9.
|
|
45
|
+
"eslint-config-typed": "5.17.0",
|
|
46
|
+
"eslint-plugin-ts-fortress": "1.3.0",
|
|
47
|
+
"eslint-plugin-ts-type-forge": "0.8.5",
|
|
48
|
+
"prettier": "3.9.9",
|
|
49
49
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
50
50
|
"prettier-plugin-packagejson": "3.0.2",
|
|
51
|
-
"ts-repo-utils": "10.
|
|
51
|
+
"ts-repo-utils": "10.7.1"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"eslint": ">=9.0.0",
|
|
@@ -65,20 +65,22 @@
|
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/build.mts",
|
|
67
67
|
"check:ext": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-ext.mts",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
68
|
+
"check:lint": "eslint .",
|
|
69
|
+
"check:test": "pnpm run z:vitest run",
|
|
70
|
+
"check:test:cov": "pnpm run z:vitest run --coverage",
|
|
71
|
+
"check:types": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
|
|
72
|
+
"doc": "pnpm run gen:readme",
|
|
73
|
+
"fix:fmt": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-uncommitted.mts --cwd .",
|
|
74
|
+
"fix:fmt:diff": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-diff-from.mts origin/main --cwd .",
|
|
75
|
+
"fix:fmt:full": "pnpm run z:prettier .",
|
|
76
|
+
"fix:lint": "eslint . --fix",
|
|
77
|
+
"fmt": "pnpm run fix:fmt",
|
|
78
|
+
"gen": "run-s gen:rule-types gen:readme",
|
|
79
|
+
"gen:readme": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples.mts",
|
|
73
80
|
"gen:rule-types": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/gen-rule-types.mts",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"test": "pnpm run z:vitest run",
|
|
78
|
-
"test:cov": "pnpm run z:vitest run --coverage",
|
|
79
|
-
"testw": "pnpm run z:vitest",
|
|
80
|
-
"tscw": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch -p ./tsconfig.json",
|
|
81
|
-
"type-check": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
|
|
81
|
+
"test": "pnpm run check:test",
|
|
82
|
+
"watch:test": "pnpm run z:vitest",
|
|
83
|
+
"watch:types": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch -p ./tsconfig.json",
|
|
82
84
|
"z:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --ignore-path ../../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
|
|
83
85
|
"z:vitest": "vitest --config ./configs/vitest.config.mts"
|
|
84
86
|
}
|
package/src/plugin.mts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ReadonlyRecord } from 'ts-type-forge';
|
|
2
2
|
import { tsStdForgeRules } from './rules/index.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import type { ESLintFlatConfig, ESLintPlugin } from './types.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Every rule this plugin ships, at `error`.
|
|
7
7
|
*
|
|
8
|
-
* The `satisfies` clause below is keyed off {@link tsStdForgeRules}, so
|
|
9
|
-
*
|
|
8
|
+
* The `satisfies` clause below is keyed off {@link tsStdForgeRules}, so leaving a
|
|
9
|
+
* rule out, naming one that does not exist, or setting one to anything
|
|
10
|
+
* but `error` fails to type-check. That is the whole check; no test repeats it.
|
|
10
11
|
*/
|
|
11
12
|
const recommendedRules = {
|
|
12
13
|
'ts-std-forge/prefer-is-non-null-object': 'error',
|
package/src/plugin.test.mts
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
import { eslintPluginTsStdForge } from './plugin.mjs';
|
|
2
|
-
import { tsStdForgeRules } from './rules/index.mjs';
|
|
3
2
|
|
|
4
3
|
describe('eslintPluginTsStdForge.configs.recommended', () => {
|
|
5
4
|
const recommended = eslintPluginTsStdForge.configs.recommended;
|
|
6
5
|
|
|
7
|
-
test('enables every rule of the plugin, and nothing else, at "error"', () => {
|
|
8
|
-
assert.deepStrictEqual(
|
|
9
|
-
recommended.rules,
|
|
10
|
-
Object.fromEntries(
|
|
11
|
-
Object.keys(tsStdForgeRules).map((name) => [
|
|
12
|
-
`ts-std-forge/${name}`,
|
|
13
|
-
'error',
|
|
14
|
-
]),
|
|
15
|
-
),
|
|
16
|
-
);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
6
|
test('registers the exported plugin object itself', () => {
|
|
20
7
|
// Registering a *copy* would make `Cannot redefine plugin` errors possible
|
|
21
8
|
// for users who also list the plugin in their own `plugins` record.
|
package/src/rule-types.mts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// This file is auto-generated by `pnpm run gen:rule-types`
|
|
4
4
|
// (`scripts/cmd/gen-rule-types.mts`). Do not edit it manually.
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import type { Linter } from 'eslint';
|
|
7
7
|
import { expectType } from 'ts-std-forge';
|
|
8
|
-
import {
|
|
8
|
+
import type { tsStdForgeRules } from './rules/index.mjs';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @description Replace `typeof u === "object" && u !== null` with `isNonNullObject(u)` from ts-std-forge.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AST_NODE_TYPES,
|
|
3
|
+
ASTUtils,
|
|
4
|
+
type TSESLint,
|
|
5
|
+
type TSESTree,
|
|
6
|
+
} from '@typescript-eslint/utils';
|
|
7
|
+
import type * as ts from 'typescript';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `node` with every `as`, `satisfies`, `!` and `<T>` around it taken off: the
|
|
11
|
+
* expression whose value it is. Judge syntax and ask types on what this
|
|
12
|
+
* returns, so that a wrapper neither hides a pattern (`xs.length > (0 as
|
|
13
|
+
* const)`) nor vouches for a type (`Number(b as unknown as string)`, whose
|
|
14
|
+
* value is still a boolean), and keep the original node for fix text. See
|
|
15
|
+
* `docs/writing-lint-rules.md` at the repository root.
|
|
16
|
+
*
|
|
17
|
+
* A copy of the helper in `eslint-config-typed`, which this package, published
|
|
18
|
+
* on its own, cannot import.
|
|
19
|
+
*/
|
|
20
|
+
export const skipTypeWrappers = (
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
22
|
+
node: TSESTree.Node,
|
|
23
|
+
): TSESTree.Node =>
|
|
24
|
+
isTypeWrapper(node) ? skipTypeWrappers(node.expression) : node;
|
|
25
|
+
|
|
26
|
+
export const isTypeWrapper = (
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
28
|
+
node: TSESTree.Node,
|
|
29
|
+
): node is TypeWrapper => TYPE_WRAPPERS.has(node.type);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether `node`, read through its type wrappers, is the identifier `name`:
|
|
33
|
+
* `Number`, `(Number as NumberConstructor)` and `Number!` are the same object.
|
|
34
|
+
*/
|
|
35
|
+
export const isIdentifierNamed = (
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
37
|
+
node: TSESTree.Node,
|
|
38
|
+
name: string,
|
|
39
|
+
): boolean => {
|
|
40
|
+
const unwrapped = skipTypeWrappers(node);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
unwrapped.type === AST_NODE_TYPES.Identifier && unwrapped.name === name
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type TypeWrapper =
|
|
48
|
+
| TSESTree.TSAsExpression
|
|
49
|
+
| TSESTree.TSNonNullExpression
|
|
50
|
+
| TSESTree.TSSatisfiesExpression
|
|
51
|
+
| TSESTree.TSTypeAssertion;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The type of the value `node` evaluates to, asked of the expression inside
|
|
55
|
+
* its type wrappers rather than of the cast, or `undefined` without type
|
|
56
|
+
* information. A `!` among the wrappers still takes `null` and `undefined`
|
|
57
|
+
* out, since that much the source asserts about the value itself.
|
|
58
|
+
*/
|
|
59
|
+
export const getValueType = (
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
61
|
+
sourceCode: TSESLint.SourceCode,
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
63
|
+
node: TSESTree.Node,
|
|
64
|
+
): ts.Type | undefined => {
|
|
65
|
+
const services = sourceCode.parserServices;
|
|
66
|
+
|
|
67
|
+
const checker = services?.program?.getTypeChecker();
|
|
68
|
+
|
|
69
|
+
const tsNode = services?.esTreeNodeToTSNodeMap?.get(skipTypeWrappers(node));
|
|
70
|
+
|
|
71
|
+
if (checker === undefined || tsNode === undefined) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const type = checker.getTypeAtLocation(tsNode);
|
|
76
|
+
|
|
77
|
+
return hasNonNullAssertion(node) ? checker.getNonNullableType(type) : type;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The source text of `node` to put in a call's argument list. `getText`
|
|
82
|
+
* leaves out the parentheses the source puts around a node, and a sequence
|
|
83
|
+
* `(a, b)` without them would be read as two arguments.
|
|
84
|
+
*/
|
|
85
|
+
export const getArgumentText = (
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
87
|
+
sourceCode: TSESLint.SourceCode,
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
89
|
+
node: TSESTree.Node,
|
|
90
|
+
): string => {
|
|
91
|
+
const text = sourceCode.getText(node);
|
|
92
|
+
|
|
93
|
+
return node.type === AST_NODE_TYPES.SequenceExpression ? `(${text})` : text;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The range of `node` together with the parentheses the source puts around it,
|
|
98
|
+
* which `node.range` leaves out: all of `((Array.isArray))` for the member
|
|
99
|
+
* expression inside.
|
|
100
|
+
*/
|
|
101
|
+
export const getRangeWithParens = (
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
103
|
+
sourceCode: TSESLint.SourceCode,
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
105
|
+
node: TSESTree.Node,
|
|
106
|
+
): TSESTree.Range => {
|
|
107
|
+
const depth = parenthesesDepth(sourceCode, node);
|
|
108
|
+
|
|
109
|
+
if (depth === 0) {
|
|
110
|
+
return node.range;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const opening = sourceCode.getTokenBefore(node, { skip: depth - 1 });
|
|
114
|
+
|
|
115
|
+
const closing = sourceCode.getTokenAfter(node, { skip: depth - 1 });
|
|
116
|
+
|
|
117
|
+
return opening === null || closing === null
|
|
118
|
+
? node.range
|
|
119
|
+
: [opening.range[0], closing.range[1]];
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** How many pairs of parentheses the source puts around `node`. */
|
|
123
|
+
const parenthesesDepth = (
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
125
|
+
sourceCode: TSESLint.SourceCode,
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
127
|
+
node: TSESTree.Node,
|
|
128
|
+
depth: number = 0,
|
|
129
|
+
): number =>
|
|
130
|
+
ASTUtils.isParenthesized(depth + 1, node, sourceCode)
|
|
131
|
+
? parenthesesDepth(sourceCode, node, depth + 1)
|
|
132
|
+
: depth;
|
|
133
|
+
|
|
134
|
+
const hasNonNullAssertion = (
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
136
|
+
node: TSESTree.Node,
|
|
137
|
+
): boolean =>
|
|
138
|
+
isTypeWrapper(node) &&
|
|
139
|
+
(node.type === AST_NODE_TYPES.TSNonNullExpression ||
|
|
140
|
+
hasNonNullAssertion(node.expression));
|
|
141
|
+
|
|
142
|
+
const TYPE_WRAPPERS: ReadonlySet<AST_NODE_TYPES> = new Set([
|
|
143
|
+
AST_NODE_TYPES.TSAsExpression,
|
|
144
|
+
AST_NODE_TYPES.TSNonNullExpression,
|
|
145
|
+
AST_NODE_TYPES.TSSatisfiesExpression,
|
|
146
|
+
AST_NODE_TYPES.TSTypeAssertion,
|
|
147
|
+
]);
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
type TSESLint,
|
|
4
4
|
type TSESTree,
|
|
5
5
|
} from '@typescript-eslint/utils';
|
|
6
|
-
import {
|
|
6
|
+
import type { DeepReadonly } from 'ts-type-forge';
|
|
7
7
|
import { TS_STD_FORGE_MODULE } from './constants.mjs';
|
|
8
8
|
|
|
9
9
|
/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
|
|
@@ -20,7 +20,9 @@ export const getTsStdForgeImport = (
|
|
|
20
20
|
export const getNamedImports = (
|
|
21
21
|
node: DeepReadonly<TSESTree.ImportDeclaration> | undefined,
|
|
22
22
|
): readonly string[] => {
|
|
23
|
-
if (node === undefined)
|
|
23
|
+
if (node === undefined) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
24
26
|
|
|
25
27
|
return node.specifiers.flatMap((specifier) =>
|
|
26
28
|
specifier.type === AST_NODE_TYPES.ImportSpecifier
|