eslint-plugin-ts-data-forge 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +1 -0
  2. package/dist/index.mjs +2 -2
  3. package/dist/index.mjs.map +1 -1
  4. package/dist/plugin.d.mts +2 -0
  5. package/dist/plugin.d.mts.map +1 -1
  6. package/dist/plugin.mjs +45 -41
  7. package/dist/plugin.mjs.map +1 -1
  8. package/dist/rule-types.d.mts +15 -0
  9. package/dist/rule-types.d.mts.map +1 -1
  10. package/dist/rule-types.mjs +6 -2
  11. package/dist/rule-types.mjs.map +1 -1
  12. package/dist/rules/ast-utils.mjs +107 -50
  13. package/dist/rules/ast-utils.mjs.map +1 -1
  14. package/dist/rules/branded-number-types.mjs +41 -37
  15. package/dist/rules/branded-number-types.mjs.map +1 -1
  16. package/dist/rules/constants.mjs +2 -4
  17. package/dist/rules/constants.mjs.map +1 -1
  18. package/dist/rules/import-utils.mjs +80 -56
  19. package/dist/rules/import-utils.mjs.map +1 -1
  20. package/dist/rules/index.mjs +2 -2
  21. package/dist/rules/index.mjs.map +1 -1
  22. package/dist/rules/no-side-effect-import.mjs +46 -34
  23. package/dist/rules/no-side-effect-import.mjs.map +1 -1
  24. package/dist/rules/no-unnecessary-type-guard.mjs +376 -265
  25. package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
  26. package/dist/rules/prefer-arr-is-array.mjs +64 -52
  27. package/dist/rules/prefer-arr-is-array.mjs.map +1 -1
  28. package/dist/rules/prefer-arr-is-bounded-length-array.mjs +91 -85
  29. package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
  30. package/dist/rules/prefer-arr-is-fixed-length-array.mjs +92 -83
  31. package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
  32. package/dist/rules/prefer-arr-is-max-length-array.mjs +92 -80
  33. package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
  34. package/dist/rules/prefer-arr-is-min-length-array.mjs +92 -80
  35. package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
  36. package/dist/rules/prefer-arr-is-non-empty.mjs +85 -77
  37. package/dist/rules/prefer-arr-is-non-empty.mjs.map +1 -1
  38. package/dist/rules/prefer-arr-scan.d.mts +96 -0
  39. package/dist/rules/prefer-arr-scan.d.mts.map +1 -0
  40. package/dist/rules/prefer-arr-scan.mjs +482 -0
  41. package/dist/rules/prefer-arr-scan.mjs.map +1 -0
  42. package/dist/rules/prefer-arr-sum.mjs +176 -132
  43. package/dist/rules/prefer-arr-sum.mjs.map +1 -1
  44. package/dist/rules/prefer-as-int.mjs +77 -71
  45. package/dist/rules/prefer-as-int.mjs.map +1 -1
  46. package/dist/rules/prefer-canonical-array-slicing.mjs +503 -343
  47. package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
  48. package/dist/rules/prefer-canonical-length-cast.mjs +217 -144
  49. package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
  50. package/dist/rules/prefer-canonical-length-guard.mjs +160 -109
  51. package/dist/rules/prefer-canonical-length-guard.mjs.map +1 -1
  52. package/dist/rules/prefer-comparison-over-nullish-guard.mjs +89 -71
  53. package/dist/rules/prefer-comparison-over-nullish-guard.mjs.map +1 -1
  54. package/dist/rules/prefer-is-non-null-object.mjs +91 -72
  55. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  56. package/dist/rules/prefer-is-record-and-has-key.mjs +148 -105
  57. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  58. package/dist/rules/prefer-num-safe-parse-float.mjs +101 -77
  59. package/dist/rules/prefer-num-safe-parse-float.mjs.map +1 -1
  60. package/dist/rules/prefer-num-safe-parse-int.mjs +103 -81
  61. package/dist/rules/prefer-num-safe-parse-int.mjs.map +1 -1
  62. package/dist/rules/prefer-obj-over-entries-round-trip.mjs +299 -194
  63. package/dist/rules/prefer-obj-over-entries-round-trip.mjs.map +1 -1
  64. package/dist/rules/prefer-range-for-loop.mjs +121 -99
  65. package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
  66. package/dist/rules/rules.d.mts +1 -0
  67. package/dist/rules/rules.d.mts.map +1 -1
  68. package/dist/rules/rules.mjs +19 -20
  69. package/dist/rules/rules.mjs.map +1 -1
  70. package/dist/types.mjs +2 -2
  71. package/dist/types.mjs.map +1 -1
  72. package/package.json +6 -7
  73. package/src/plugin.mts +1 -0
  74. package/src/rule-types.mts +16 -0
  75. package/src/rules/prefer-arr-scan.mts +693 -0
  76. package/src/rules/prefer-arr-scan.test.mts +295 -0
  77. package/src/rules/rules.mts +2 -0
@@ -1,290 +1,401 @@
1
- import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
1
+ import { AST_NODE_TYPES, ESLintUtils, } from '@typescript-eslint/utils';
2
2
  import * as ts from 'typescript';
3
- import { getTsDataForgeImport, buildCalleeResolver, getImportedLocalName, buildImportFixes } from './import-utils.mjs';
3
+ import { buildCalleeResolver, buildImportFixes, getImportedLocalName, getTsDataForgeImport, } from './import-utils.mjs';
4
4
 
5
- const BRAND_MARKER_PROPERTY = "TSTypeForgeInternals--edd2f9ce-7ca5-45b0-9d1a-bd61b9b5d9c3";
6
- const MIN_LENGTH_BRAND_KEY = "MinLength";
5
+
6
+
7
+
8
+
9
+ const BRAND_MARKER_PROPERTY = 'TSTypeForgeInternals--edd2f9ce-7ca5-45b0-9d1a-bd61b9b5d9c3';
10
+
11
+
12
+
13
+
14
+
15
+
16
+ const MIN_LENGTH_BRAND_KEY = 'MinLength';
7
17
  const NULLISH_REPLACEMENTS_EXCLUDE = {
8
- undefined: "isNotUndefined",
9
- null: "isNotNull"
18
+ undefined: 'isNotUndefined',
19
+ null: 'isNotNull',
10
20
  };
11
21
  const NULLISH_REPLACEMENTS_NARROW = {
12
- undefined: "isUndefined",
13
- null: "isNull"
22
+ undefined: 'isUndefined',
23
+ null: 'isNull',
14
24
  };
15
25
  const GUARD_SPECS = {
16
- isUndefined: { kind: "narrowTo", atoms: ["undefined"] },
17
- isNotUndefined: { kind: "excludeFrom", atoms: ["undefined"] },
18
- isNull: { kind: "narrowTo", atoms: ["null"] },
19
- isNotNull: { kind: "excludeFrom", atoms: ["null"] },
20
- isBoolean: { kind: "narrowTo", atoms: ["boolean"] },
21
- isNotBoolean: { kind: "excludeFrom", atoms: ["boolean"] },
22
- isNumber: { kind: "narrowTo", atoms: ["number"] },
23
- isNotNumber: { kind: "excludeFrom", atoms: ["number"] },
24
- isString: { kind: "narrowTo", atoms: ["string"] },
25
- isNotString: { kind: "excludeFrom", atoms: ["string"] },
26
- isBigint: { kind: "narrowTo", atoms: ["bigint"] },
27
- isNotBigint: { kind: "excludeFrom", atoms: ["bigint"] },
28
- isSymbol: { kind: "narrowTo", atoms: ["symbol"] },
29
- isNotSymbol: { kind: "excludeFrom", atoms: ["symbol"] },
30
- isNullish: {
31
- kind: "narrowTo",
32
- atoms: ["null", "undefined"],
33
- replacements: NULLISH_REPLACEMENTS_NARROW
34
- },
35
- isNonNullish: {
36
- kind: "excludeFrom",
37
- atoms: ["null", "undefined"],
38
- replacements: NULLISH_REPLACEMENTS_EXCLUDE
39
- },
40
- isNonEmptyString: { kind: "nonEmptyString" },
41
- isRecord: { kind: "record" }
42
- };
43
- const DEFERRED_OR_OPAQUE_FLAGS = ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never | ts.TypeFlags.TypeParameter | ts.TypeFlags.IndexedAccess | ts.TypeFlags.Conditional | ts.TypeFlags.Substitution;
44
- const noUnnecessaryTypeGuard = {
45
- meta: {
46
- type: "suggestion",
47
- docs: {
48
- description: "Detect ts-data-forge type guard calls that perform no narrowing (the argument type already satisfies, or can never satisfy, the guard)."
26
+ isUndefined: { kind: 'narrowTo', atoms: ['undefined'] },
27
+ isNotUndefined: { kind: 'excludeFrom', atoms: ['undefined'] },
28
+ isNull: { kind: 'narrowTo', atoms: ['null'] },
29
+ isNotNull: { kind: 'excludeFrom', atoms: ['null'] },
30
+ isBoolean: { kind: 'narrowTo', atoms: ['boolean'] },
31
+ isNotBoolean: { kind: 'excludeFrom', atoms: ['boolean'] },
32
+ isNumber: { kind: 'narrowTo', atoms: ['number'] },
33
+ isNotNumber: { kind: 'excludeFrom', atoms: ['number'] },
34
+ isString: { kind: 'narrowTo', atoms: ['string'] },
35
+ isNotString: { kind: 'excludeFrom', atoms: ['string'] },
36
+ isBigint: { kind: 'narrowTo', atoms: ['bigint'] },
37
+ isNotBigint: { kind: 'excludeFrom', atoms: ['bigint'] },
38
+ isSymbol: { kind: 'narrowTo', atoms: ['symbol'] },
39
+ isNotSymbol: { kind: 'excludeFrom', atoms: ['symbol'] },
40
+ isNullish: {
41
+ kind: 'narrowTo',
42
+ atoms: ['null', 'undefined'],
43
+ replacements: NULLISH_REPLACEMENTS_NARROW,
49
44
  },
50
- fixable: "code",
51
- schema: [
52
- {
53
- type: "object",
54
- properties: {
55
- ignore: {
56
- type: "array",
57
- items: { type: "string" },
58
- description: "Names of ts-data-forge guard functions to skip checking."
59
- }
45
+ isNonNullish: {
46
+ kind: 'excludeFrom',
47
+ atoms: ['null', 'undefined'],
48
+ replacements: NULLISH_REPLACEMENTS_EXCLUDE,
49
+ },
50
+ isNonEmptyString: { kind: 'nonEmptyString' },
51
+ isRecord: { kind: 'record' },
52
+ };
53
+ const DEFERRED_OR_OPAQUE_FLAGS = ts.TypeFlags.Any |
54
+ ts.TypeFlags.Unknown |
55
+ ts.TypeFlags.Never |
56
+ ts.TypeFlags.TypeParameter |
57
+ ts.TypeFlags.IndexedAccess |
58
+ ts.TypeFlags.Conditional |
59
+ ts.TypeFlags.Substitution;
60
+ export const noUnnecessaryTypeGuard = {
61
+ meta: {
62
+ type: 'suggestion',
63
+ docs: {
64
+ description: 'Detect ts-data-forge type guard calls that perform no narrowing (the argument type already satisfies, or can never satisfy, the guard).',
60
65
  },
61
- additionalProperties: false
62
- }
63
- ],
64
- messages: {
65
- alwaysTrue: "Unnecessary `{{name}}` call: the argument type guarantees it always returns `true`. Replace the call with `true`.",
66
- alwaysFalse: "Unnecessary `{{name}}` call: the argument type guarantees it always returns `false`. Replace the call with `false`.",
67
- replaceTypeGuard: "Unnecessary `{{from}}` call: the argument can only be narrowed by `{{to}}`. Use `{{to}}` instead."
68
- }
69
- },
70
- create: (context) => {
71
- const options = context.options[0];
72
- const parserServices = ESLintUtils.getParserServices(context);
73
- const compilerOptions = parserServices.program.getCompilerOptions();
74
- const strictNullChecks = compilerOptions.strictNullChecks ?? compilerOptions.strict ?? false;
75
- if (!strictNullChecks) return {};
76
- const checker = parserServices.program.getTypeChecker();
77
- const sourceCode = context.sourceCode;
78
- const program = sourceCode.ast;
79
- const ignored = new Set(options?.ignore);
80
- const tsDataForgeImport = getTsDataForgeImport(program);
81
- const resolveGuard = buildCalleeResolver(tsDataForgeImport);
82
- const buildReplaceFix = (isNamespace, propertyNode, replacement) => (fixer) => {
83
- if (isNamespace) {
84
- return [fixer.replaceText(propertyNode, replacement)];
85
- }
86
- const localName = getImportedLocalName(
87
- tsDataForgeImport,
88
- replacement
89
- );
90
- if (localName !== void 0) {
91
- return [fixer.replaceText(propertyNode, localName)];
92
- }
93
- return [
94
- ...buildImportFixes(fixer, program, tsDataForgeImport, [
95
- replacement
96
- ]),
97
- fixer.replaceText(propertyNode, replacement)
98
- ];
99
- };
100
- const reportConstant = (node, name, value, argument) => {
101
- const canFix = isSideEffectFreeArg(argument);
102
- context.report({
103
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
104
- node,
105
- messageId: value ? "alwaysTrue" : "alwaysFalse",
106
- data: { name },
107
- fix: canFix ? (fixer) => fixer.replaceText(
108
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
109
- node,
110
- value ? "true" : "false"
111
- ) : void 0
112
- });
113
- };
114
- const reportReplace = (node, from, to, isNamespace, propertyNode) => {
115
- context.report({
116
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
117
- node,
118
- messageId: "replaceTypeGuard",
119
- data: { from, to },
120
- fix: buildReplaceFix(isNamespace, propertyNode, to)
121
- });
122
- };
123
- return {
124
- CallExpression: (node) => {
125
- if (node.arguments.length !== 1) return;
126
- const argument = node.arguments[0];
127
- if (argument === void 0 || argument.type === AST_NODE_TYPES.SpreadElement) {
128
- return;
129
- }
130
- const resolved = resolveGuard(node.callee);
131
- if (resolved === void 0) return;
132
- const { canonicalName, propertyNode, isNamespace } = resolved;
133
- if (ignored.has(canonicalName)) return;
134
- const spec = GUARD_SPECS[canonicalName];
135
- if (spec === void 0) return;
136
- const argTsNode = parserServices.esTreeNodeToTSNodeMap.get(argument);
137
- const argType = checker.getTypeAtLocation(argTsNode);
138
- const parts = collectUnionParts(argType);
139
- if (parts === void 0) return;
140
- const inputAtoms = new Set(parts.map(classifyAtom));
141
- const hasMemberOutsideTarget = (atoms) => {
142
- const targetSet = new Set(atoms);
143
- return parts.some((p) => !targetSet.has(classifyAtom(p)));
144
- };
145
- switch (spec.kind) {
146
- case "excludeFrom": {
147
- const removable = spec.atoms.filter((a) => inputAtoms.has(a));
148
- if (removable.length === 0) {
149
- reportConstant(node, canonicalName, true, argument);
150
- } else if (!hasMemberOutsideTarget(spec.atoms)) {
151
- reportConstant(node, canonicalName, false, argument);
152
- } else if (removable.length < spec.atoms.length) {
153
- const replacement = spec.replacements?.[joinAtoms(removable)];
154
- if (replacement !== void 0) {
155
- reportReplace(
156
- node,
157
- canonicalName,
158
- replacement,
159
- isNamespace,
160
- propertyNode
161
- );
162
- }
163
- }
164
- break;
165
- }
166
- case "narrowTo": {
167
- const present = spec.atoms.filter((a) => inputAtoms.has(a));
168
- if (present.length === 0) {
169
- reportConstant(node, canonicalName, false, argument);
170
- } else if (!hasMemberOutsideTarget(spec.atoms)) {
171
- reportConstant(node, canonicalName, true, argument);
172
- } else if (present.length < spec.atoms.length) {
173
- const replacement = spec.replacements?.[joinAtoms(present)];
174
- if (replacement !== void 0) {
175
- reportReplace(
176
- node,
177
- canonicalName,
178
- replacement,
179
- isNamespace,
180
- propertyNode
181
- );
182
- }
66
+ fixable: 'code',
67
+ schema: [
68
+ {
69
+ type: 'object',
70
+ properties: {
71
+ ignore: {
72
+ type: 'array',
73
+ items: { type: 'string' },
74
+ description: 'Names of ts-data-forge guard functions to skip checking.',
75
+ },
76
+ },
77
+ additionalProperties: false,
78
+ },
79
+ ],
80
+ messages: {
81
+ alwaysTrue: 'Unnecessary `{{name}}` call: the argument type guarantees it always returns `true`. Replace the call with `true`.',
82
+ alwaysFalse: 'Unnecessary `{{name}}` call: the argument type guarantees it always returns `false`. Replace the call with `false`.',
83
+ replaceTypeGuard: 'Unnecessary `{{from}}` call: the argument can only be narrowed by `{{to}}`. Use `{{to}}` instead.',
84
+ },
85
+ },
86
+ create: (context) => {
87
+ const options = context.options[0];
88
+ const parserServices = ESLintUtils.getParserServices(context);
89
+ const compilerOptions = parserServices.program.getCompilerOptions();
90
+
91
+
92
+ const strictNullChecks = compilerOptions.strictNullChecks ?? compilerOptions.strict ?? false;
93
+ if (!strictNullChecks)
94
+ return {};
95
+ const checker = parserServices.program.getTypeChecker();
96
+ const sourceCode = context.sourceCode;
97
+ const program = sourceCode.ast;
98
+ const ignored = new Set(options?.ignore);
99
+ const tsDataForgeImport = getTsDataForgeImport(program);
100
+ const resolveGuard = buildCalleeResolver(tsDataForgeImport);
101
+ const buildReplaceFix = (isNamespace,
102
+
103
+ propertyNode, replacement) => (fixer) => {
104
+
105
+
106
+ if (isNamespace) {
107
+ return [fixer.replaceText(propertyNode, replacement)];
183
108
  }
184
- break;
185
- }
186
- case "record": {
187
- if (parts.every((p) => isGuaranteedRecord(p, checker))) {
188
- reportConstant(node, canonicalName, true, argument);
189
- } else if (parts.every((p) => isGuaranteedNotRecord(p, checker))) {
190
- reportConstant(node, canonicalName, false, argument);
109
+
110
+
111
+
112
+ const localName = getImportedLocalName(tsDataForgeImport, replacement);
113
+ if (localName !== undefined) {
114
+ return [fixer.replaceText(propertyNode, localName)];
191
115
  }
192
- break;
193
- }
194
- case "nonEmptyString": {
195
- const hasNullish = inputAtoms.has("undefined") || inputAtoms.has("null");
196
- const nonNullishParts = parts.filter((p) => {
197
- const atom = classifyAtom(p);
198
- return atom !== "undefined" && atom !== "null";
116
+ return [
117
+ ...buildImportFixes(fixer, program, tsDataForgeImport, [
118
+ replacement,
119
+ ]),
120
+ fixer.replaceText(propertyNode, replacement),
121
+ ];
122
+ };
123
+ const reportConstant = (node, name, value, argument) => {
124
+
125
+
126
+ const canFix = isSideEffectFreeArg(argument);
127
+ context.report({
128
+
129
+ node: node,
130
+ messageId: value ? 'alwaysTrue' : 'alwaysFalse',
131
+ data: { name },
132
+ fix: canFix
133
+ ? (fixer) => fixer.replaceText(
134
+
135
+ node, value ? 'true' : 'false')
136
+ : undefined,
199
137
  });
200
- if (!nonNullishParts.some(couldBeNonEmptyString)) {
201
- reportConstant(node, canonicalName, false, argument);
202
- break;
203
- }
204
- if (nonNullishParts.some(
205
- (p) => !isGuaranteedNonEmptyString(p, checker)
206
- )) {
207
- break;
208
- }
209
- if (hasNullish) {
210
- reportReplace(
211
- node,
212
- canonicalName,
213
- "isNonNullish",
214
- isNamespace,
215
- propertyNode
216
- );
217
- } else {
218
- reportConstant(node, canonicalName, true, argument);
219
- }
220
- break;
221
- }
222
- }
223
- }
224
- };
225
- },
226
- defaultOptions: [{}]
138
+ };
139
+ const reportReplace = (node, from, to, isNamespace,
140
+
141
+ propertyNode) => {
142
+ context.report({
143
+
144
+ node: node,
145
+ messageId: 'replaceTypeGuard',
146
+ data: { from, to },
147
+ fix: buildReplaceFix(isNamespace, propertyNode, to),
148
+ });
149
+ };
150
+ return {
151
+ CallExpression: (node) => {
152
+ if (node.arguments.length !== 1)
153
+ return;
154
+ const argument = node.arguments[0];
155
+ if (argument === undefined ||
156
+ argument.type === AST_NODE_TYPES.SpreadElement) {
157
+ return;
158
+ }
159
+ const resolved = resolveGuard(node.callee);
160
+ if (resolved === undefined)
161
+ return;
162
+ const { canonicalName, propertyNode, isNamespace } = resolved;
163
+ if (ignored.has(canonicalName))
164
+ return;
165
+ const spec = GUARD_SPECS[canonicalName];
166
+ if (spec === undefined)
167
+ return;
168
+ const argTsNode = parserServices.esTreeNodeToTSNodeMap.get(argument);
169
+ const argType = checker.getTypeAtLocation(argTsNode);
170
+ const parts = collectUnionParts(argType);
171
+ if (parts === undefined)
172
+ return;
173
+ const inputAtoms = new Set(parts.map(classifyAtom));
174
+ const hasMemberOutsideTarget = (atoms) => {
175
+ const targetSet = new Set(atoms);
176
+ return parts.some((p) => !targetSet.has(classifyAtom(p)));
177
+ };
178
+ switch (spec.kind) {
179
+ case 'excludeFrom': {
180
+ const removable = spec.atoms.filter((a) => inputAtoms.has(a));
181
+ if (removable.length === 0) {
182
+
183
+ reportConstant(node, canonicalName, true, argument);
184
+ }
185
+ else if (!hasMemberOutsideTarget(spec.atoms)) {
186
+
187
+ reportConstant(node, canonicalName, false, argument);
188
+ }
189
+ else if (removable.length < spec.atoms.length) {
190
+ const replacement = spec.replacements?.[joinAtoms(removable)];
191
+ if (replacement !== undefined) {
192
+ reportReplace(node, canonicalName, replacement, isNamespace, propertyNode);
193
+ }
194
+ }
195
+ break;
196
+ }
197
+ case 'narrowTo': {
198
+ const present = spec.atoms.filter((a) => inputAtoms.has(a));
199
+ if (present.length === 0) {
200
+
201
+ reportConstant(node, canonicalName, false, argument);
202
+ }
203
+ else if (!hasMemberOutsideTarget(spec.atoms)) {
204
+
205
+ reportConstant(node, canonicalName, true, argument);
206
+ }
207
+ else if (present.length < spec.atoms.length) {
208
+ const replacement = spec.replacements?.[joinAtoms(present)];
209
+ if (replacement !== undefined) {
210
+ reportReplace(node, canonicalName, replacement, isNamespace, propertyNode);
211
+ }
212
+ }
213
+ break;
214
+ }
215
+ case 'record': {
216
+ if (parts.every((p) => isGuaranteedRecord(p, checker))) {
217
+
218
+ reportConstant(node, canonicalName, true, argument);
219
+ }
220
+ else if (parts.every((p) => isGuaranteedNotRecord(p, checker))) {
221
+
222
+ reportConstant(node, canonicalName, false, argument);
223
+ }
224
+ break;
225
+ }
226
+ case 'nonEmptyString': {
227
+ const hasNullish = inputAtoms.has('undefined') || inputAtoms.has('null');
228
+ const nonNullishParts = parts.filter((p) => {
229
+ const atom = classifyAtom(p);
230
+ return atom !== 'undefined' && atom !== 'null';
231
+ });
232
+ if (!nonNullishParts.some(couldBeNonEmptyString)) {
233
+
234
+ reportConstant(node, canonicalName, false, argument);
235
+ break;
236
+ }
237
+ if (nonNullishParts.some((p) => !isGuaranteedNonEmptyString(p, checker))) {
238
+ break;
239
+ }
240
+ if (hasNullish) {
241
+ reportReplace(node, canonicalName, 'isNonNullish', isNamespace, propertyNode);
242
+ }
243
+ else {
244
+ reportConstant(node, canonicalName, true, argument);
245
+ }
246
+ break;
247
+ }
248
+ }
249
+ },
250
+ };
251
+ },
252
+ defaultOptions: [{}],
227
253
  };
254
+
255
+
256
+
257
+
258
+
259
+
228
260
  const collectUnionParts = (type) => {
229
- const parts = type.isUnion() ? type.types : [type];
230
- for (const part of parts) {
231
- if ((part.flags & DEFERRED_OR_OPAQUE_FLAGS) !== 0) return void 0;
232
- }
233
- return parts;
261
+ const parts = type.isUnion() ? type.types : [type];
262
+ for (const part of parts) {
263
+ if ((part.flags & DEFERRED_OR_OPAQUE_FLAGS) !== 0)
264
+ return undefined;
265
+ }
266
+ return parts;
234
267
  };
235
- const isGuaranteedRecord = (type, checker) => checker.getIndexInfoOfType(type, ts.IndexKind.String) !== void 0 && !isCallableType(type, checker) && !checker.isArrayType(type) && !checker.isTupleType(type);
236
- const isGuaranteedNotRecord = (type, checker) => classifyAtom(type) !== "other" || checker.isArrayType(type) || checker.isTupleType(type) || isCallableType(type, checker);
237
- const isCallableType = (type, checker) => checker.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0 || checker.getSignaturesOfType(type, ts.SignatureKind.Construct).length > 0;
268
+
269
+
270
+
271
+
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+ const isGuaranteedRecord = (
282
+
283
+ type,
284
+
285
+ checker) => checker.getIndexInfoOfType(type, ts.IndexKind.String) !== undefined &&
286
+ !isCallableType(type, checker) &&
287
+ !checker.isArrayType(type) &&
288
+ !checker.isTupleType(type);
289
+
290
+
291
+
292
+
293
+
294
+ const isGuaranteedNotRecord = (
295
+
296
+ type,
297
+
298
+ checker) => classifyAtom(type) !== 'other' ||
299
+ checker.isArrayType(type) ||
300
+ checker.isTupleType(type) ||
301
+ isCallableType(type, checker);
302
+ const isCallableType = (
303
+
304
+ type,
305
+
306
+ checker) => checker.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0 ||
307
+ checker.getSignaturesOfType(type, ts.SignatureKind.Construct).length > 0;
308
+
309
+
238
310
  const classifyAtom = (type) => {
239
- const { flags } = type;
240
- if ((flags & ts.TypeFlags.Undefined) !== 0) return "undefined";
241
- if ((flags & ts.TypeFlags.Null) !== 0) return "null";
242
- if ((flags & ts.TypeFlags.BooleanLike) !== 0) return "boolean";
243
- if ((flags & ts.TypeFlags.NumberLike) !== 0) return "number";
244
- if ((flags & ts.TypeFlags.StringLike) !== 0) return "string";
245
- if ((flags & ts.TypeFlags.BigIntLike) !== 0) return "bigint";
246
- if ((flags & ts.TypeFlags.ESSymbolLike) !== 0) return "symbol";
247
- if (type.isIntersection()) {
248
- for (const constituent of type.types) {
249
- const atom = classifyAtom(constituent);
250
- if (atom !== "other") return atom;
311
+ const { flags } = type;
312
+ if ((flags & ts.TypeFlags.Undefined) !== 0)
313
+ return 'undefined';
314
+ if ((flags & ts.TypeFlags.Null) !== 0)
315
+ return 'null';
316
+ if ((flags & ts.TypeFlags.BooleanLike) !== 0)
317
+ return 'boolean';
318
+ if ((flags & ts.TypeFlags.NumberLike) !== 0)
319
+ return 'number';
320
+ if ((flags & ts.TypeFlags.StringLike) !== 0)
321
+ return 'string';
322
+ if ((flags & ts.TypeFlags.BigIntLike) !== 0)
323
+ return 'bigint';
324
+ if ((flags & ts.TypeFlags.ESSymbolLike) !== 0)
325
+ return 'symbol';
326
+
327
+
328
+ if (type.isIntersection()) {
329
+ for (const constituent of type.types) {
330
+ const atom = classifyAtom(constituent);
331
+ if (atom !== 'other')
332
+ return atom;
333
+ }
251
334
  }
252
- }
253
- return "other";
335
+ return 'other';
254
336
  };
255
337
  const ATOM_ORDER = [
256
- "undefined",
257
- "null",
258
- "boolean",
259
- "number",
260
- "string",
261
- "bigint",
262
- "symbol"
338
+ 'undefined',
339
+ 'null',
340
+ 'boolean',
341
+ 'number',
342
+ 'string',
343
+ 'bigint',
344
+ 'symbol',
263
345
  ];
264
- const joinAtoms = (atoms) => ATOM_ORDER.filter((atom) => atoms.includes(atom)).join("|");
265
- const isGuaranteedNonEmptyString = (type, checker) => {
266
- if (type.isStringLiteral()) return type.value !== "";
267
- if (type.getProperty(BRAND_MARKER_PROPERTY) === void 0) return false;
268
- const minLengthSymbol = type.getProperty(MIN_LENGTH_BRAND_KEY);
269
- if (minLengthSymbol === void 0) return false;
270
- return checker.getTypeOfSymbol(minLengthSymbol).getProperty("0") !== void 0;
346
+
347
+ const joinAtoms = (atoms) => ATOM_ORDER.filter((atom) => atoms.includes(atom)).join('|');
348
+
349
+
350
+
351
+
352
+
353
+ const isGuaranteedNonEmptyString = (
354
+
355
+ type,
356
+
357
+ checker) => {
358
+ if (type.isStringLiteral())
359
+ return type.value !== '';
360
+ if (type.getProperty(BRAND_MARKER_PROPERTY) === undefined)
361
+ return false;
362
+ const minLengthSymbol = type.getProperty(MIN_LENGTH_BRAND_KEY);
363
+ if (minLengthSymbol === undefined)
364
+ return false;
365
+
366
+
367
+
368
+ return (checker.getTypeOfSymbol(minLengthSymbol).getProperty('0') !== undefined);
271
369
  };
370
+
371
+
372
+
373
+
374
+
375
+
272
376
  const couldBeNonEmptyString = (type) => {
273
- if (type.isStringLiteral()) return type.value !== "";
274
- return classifyAtom(type) === "string";
377
+ if (type.isStringLiteral())
378
+ return type.value !== '';
379
+ return classifyAtom(type) === 'string';
275
380
  };
381
+
382
+
383
+
384
+
385
+
276
386
  const isSideEffectFreeArg = (node) => {
277
- switch (node.type) {
278
- case AST_NODE_TYPES.Identifier:
279
- case AST_NODE_TYPES.ThisExpression:
280
- case AST_NODE_TYPES.Literal:
281
- return true;
282
- case AST_NODE_TYPES.MemberExpression:
283
- return isSideEffectFreeArg(node.object) && (!node.computed || isSideEffectFreeArg(node.property));
284
- default:
285
- return false;
286
- }
287
- };
288
387
 
289
- export { noUnnecessaryTypeGuard };
290
- //# sourceMappingURL=no-unnecessary-type-guard.mjs.map
388
+
389
+ switch (node.type) {
390
+ case AST_NODE_TYPES.Identifier:
391
+ case AST_NODE_TYPES.ThisExpression:
392
+ case AST_NODE_TYPES.Literal:
393
+ return true;
394
+ case AST_NODE_TYPES.MemberExpression:
395
+ return (isSideEffectFreeArg(node.object) &&
396
+ (!node.computed || isSideEffectFreeArg(node.property)));
397
+ default:
398
+ return false;
399
+ }
400
+ };
401
+ //# sourceMappingURL=no-unnecessary-type-guard.mjs.map