eslint-plugin-ts-data-forge 0.8.6 → 0.9.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.
Files changed (64) hide show
  1. package/README.md +20 -19
  2. package/dist/plugin.d.mts +2 -0
  3. package/dist/plugin.d.mts.map +1 -1
  4. package/dist/plugin.mjs +1 -0
  5. package/dist/plugin.mjs.map +1 -1
  6. package/dist/rule-types.d.mts +16 -1
  7. package/dist/rule-types.d.mts.map +1 -1
  8. package/dist/rule-types.mjs.map +1 -1
  9. package/dist/rules/ast-utils.d.mts +21 -2
  10. package/dist/rules/ast-utils.d.mts.map +1 -1
  11. package/dist/rules/ast-utils.mjs +51 -4
  12. package/dist/rules/ast-utils.mjs.map +1 -1
  13. package/dist/rules/constants.d.mts +2 -0
  14. package/dist/rules/constants.d.mts.map +1 -1
  15. package/dist/rules/constants.mjs +9 -0
  16. package/dist/rules/constants.mjs.map +1 -1
  17. package/dist/rules/mutable-result.d.mts +10 -0
  18. package/dist/rules/mutable-result.d.mts.map +1 -0
  19. package/dist/rules/mutable-result.mjs +145 -0
  20. package/dist/rules/mutable-result.mjs.map +1 -0
  21. package/dist/rules/prefer-arr-generate.d.mts +57 -0
  22. package/dist/rules/prefer-arr-generate.d.mts.map +1 -0
  23. package/dist/rules/prefer-arr-generate.mjs +588 -0
  24. package/dist/rules/prefer-arr-generate.mjs.map +1 -0
  25. package/dist/rules/prefer-arr-uniq.d.mts.map +1 -1
  26. package/dist/rules/prefer-arr-uniq.mjs +2 -149
  27. package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
  28. package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
  29. package/dist/rules/prefer-canonical-array-slicing.mjs +47 -28
  30. package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
  31. package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
  32. package/dist/rules/prefer-is-non-null-object.mjs +110 -40
  33. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  34. package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
  35. package/dist/rules/prefer-is-record-and-has-key.mjs +102 -45
  36. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  37. package/dist/rules/prefer-range-for-loop.d.mts.map +1 -1
  38. package/dist/rules/prefer-range-for-loop.mjs +97 -16
  39. package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
  40. package/dist/rules/rules.d.mts +1 -0
  41. package/dist/rules/rules.d.mts.map +1 -1
  42. package/dist/rules/rules.mjs +2 -0
  43. package/dist/rules/rules.mjs.map +1 -1
  44. package/package.json +11 -11
  45. package/src/plugin.mts +1 -0
  46. package/src/rule-types.mts +17 -1
  47. package/src/rules/ast-utils.mts +72 -5
  48. package/src/rules/constants.mts +12 -0
  49. package/src/rules/mutable-result.mts +204 -0
  50. package/src/rules/prefer-arr-generate.mts +918 -0
  51. package/src/rules/prefer-arr-generate.test.mts +967 -0
  52. package/src/rules/prefer-arr-is-bounded-length-array.test.mts +19 -0
  53. package/src/rules/prefer-arr-is-max-length-array.test.mts +8 -0
  54. package/src/rules/prefer-arr-is-min-length-array.test.mts +8 -0
  55. package/src/rules/prefer-arr-uniq.mts +2 -207
  56. package/src/rules/prefer-canonical-array-slicing.mts +57 -40
  57. package/src/rules/prefer-canonical-array-slicing.test.mts +55 -0
  58. package/src/rules/prefer-is-non-null-object.mts +160 -57
  59. package/src/rules/prefer-is-non-null-object.test.mts +138 -0
  60. package/src/rules/prefer-is-record-and-has-key.mts +148 -67
  61. package/src/rules/prefer-is-record-and-has-key.test.mts +118 -23
  62. package/src/rules/prefer-range-for-loop.mts +142 -21
  63. package/src/rules/prefer-range-for-loop.test.mts +127 -5
  64. package/src/rules/rules.mts +2 -0
@@ -1,4 +1,4 @@
1
- import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
1
+ import { AST_NODE_TYPES, ASTUtils, } from '@typescript-eslint/utils';
2
2
  import { buildNamedImportFix, getArgumentText, getImportDeclarations, getNamedImports, skipTypeWrappers, } from 'eslint-rule-forge';
3
3
  import { Arr } from 'ts-data-forge';
4
4
  import { TS_DATA_FORGE_MODULE } from './constants.mjs';
@@ -18,6 +18,27 @@ export const preferRangeForLoop = {
18
18
  const sourceCode = context.sourceCode;
19
19
  const program = sourceCode.ast;
20
20
  const tsDataForgeImports = getImportDeclarations(program, TS_DATA_FORGE_MODULE);
21
+
22
+
23
+
24
+
25
+
26
+
27
+ const isStableBound = (
28
+
29
+ wrapped) => {
30
+ const node = skipTypeWrappers(wrapped);
31
+ if (node.type === AST_NODE_TYPES.Literal) {
32
+ return true;
33
+ }
34
+ if (node.type !== AST_NODE_TYPES.Identifier) {
35
+ return false;
36
+ }
37
+ const variable = ASTUtils.findVariable(sourceCode.getScope(node), node.name);
38
+ return (variable !== null &&
39
+ variable.defs.length > 0 &&
40
+ variable.references.every((reference) => !reference.isWrite() || reference.init === true));
41
+ };
21
42
  const mut_nodesToFix = [];
22
43
  return {
23
44
  ForStatement: (node) => {
@@ -35,6 +56,10 @@ export const preferRangeForLoop = {
35
56
  const varName = declaration.id.name;
36
57
  const beginExpr = declaration.init;
37
58
 
59
+ if (isNonIntegerNumberLiteral(beginExpr)) {
60
+ return;
61
+ }
62
+
38
63
 
39
64
 
40
65
  if (node.test?.type !== AST_NODE_TYPES.BinaryExpression ||
@@ -72,21 +97,35 @@ export const preferRangeForLoop = {
72
97
  if (stepValue.type === AST_NODE_TYPES.Literal) {
73
98
  const stepNum = stepValue.value;
74
99
 
75
- if (typeof stepNum === 'number' && stepNum > 0) {
100
+ if (typeof stepNum === 'number' &&
101
+ Number.isSafeInteger(stepNum) &&
102
+ stepNum > 0) {
76
103
  mut_step = stepNum === 1 ? undefined : stepNum.toString();
77
104
  }
78
105
  else {
79
106
  return;
80
107
  }
81
108
  }
109
+ else if (isNegatedLiteral(stepValue)) {
110
+
111
+
112
+
113
+ return;
114
+ }
82
115
  else {
83
116
 
117
+
118
+
84
119
  mut_step = getArgumentText(sourceCode, node.update.right);
85
120
  }
86
121
  }
87
122
  else {
88
123
  return;
89
124
  }
125
+
126
+ if (isAssignedOutsideUpdate(sourceCode, declaration, node.update)) {
127
+ return;
128
+ }
90
129
  const beginText = getArgumentText(sourceCode, beginExpr);
91
130
  const endText = getArgumentText(sourceCode, endExpr);
92
131
  mut_nodesToFix.push({
@@ -95,12 +134,17 @@ export const preferRangeForLoop = {
95
134
  begin: beginText,
96
135
  end: endText,
97
136
  step: mut_step,
137
+ fixable: isStableBound(endExpr) &&
138
+ (node.update.type !== AST_NODE_TYPES.AssignmentExpression ||
139
+ isStableBound(node.update.right)),
98
140
  });
99
141
  },
100
142
  'Program:exit': () => {
101
143
  const namedImports = getNamedImports(tsDataForgeImports);
102
144
  const hasRangeImport = namedImports.includes('range');
103
- for (const [index, { node, varName, begin, end, step },] of mut_nodesToFix.entries()) {
145
+ const importCarrier = mut_nodesToFix.find(({ fixable }) => fixable);
146
+ for (const entry of mut_nodesToFix) {
147
+ const { node, varName, begin, end, step } = entry;
104
148
  context.report({
105
149
  node: node.init ?? node,
106
150
  messageId: 'useRangeForLoop',
@@ -109,19 +153,22 @@ export const preferRangeForLoop = {
109
153
  begin,
110
154
  end,
111
155
  },
112
- fix: (fixer) => {
113
- const bodyText = sourceCode.getText(node.body);
114
- const rangeArgs = step === undefined
115
- ? `${begin}, ${end}`
116
- : `${begin}, ${end}, ${step}`;
117
- const replacement = `for (const ${varName} of range(${rangeArgs})) ${bodyText}`;
118
- const importFixes = index === 0 && !hasRangeImport
119
- ? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
120
- 'range',
121
- ])
122
- : [];
123
- return [...importFixes, fixer.replaceText(node, replacement)];
124
- },
156
+ fix: entry.fixable
157
+ ? (fixer) => {
158
+ const bodyText = sourceCode.getText(node.body);
159
+ const rangeArgs = step === undefined
160
+ ? `${begin}, ${end}`
161
+ : `${begin}, ${end}, ${step}`;
162
+ const replacement = `for (const ${varName} of range(${rangeArgs})) ${bodyText}`;
163
+
164
+
165
+
166
+ const importFixes = entry === importCarrier && !hasRangeImport
167
+ ? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, ['range'])
168
+ : [];
169
+ return [...importFixes, fixer.replaceText(node, replacement)];
170
+ }
171
+ : undefined,
125
172
  });
126
173
  }
127
174
  },
@@ -129,4 +176,38 @@ export const preferRangeForLoop = {
129
176
  },
130
177
  defaultOptions: [],
131
178
  };
179
+ const isNegatedLiteral = (
180
+
181
+ node) => node.type === AST_NODE_TYPES.UnaryExpression &&
182
+ node.operator === '-' &&
183
+ skipTypeWrappers(node.argument).type === AST_NODE_TYPES.Literal;
184
+ const isNonIntegerNumberLiteral = (
185
+
186
+ wrapped) => {
187
+ const node = skipTypeWrappers(wrapped);
188
+ return (node.type === AST_NODE_TYPES.Literal &&
189
+ typeof node.value === 'number' &&
190
+ !Number.isSafeInteger(node.value));
191
+ };
192
+
193
+
194
+
195
+
196
+ const isAssignedOutsideUpdate = (
197
+
198
+ sourceCode,
199
+
200
+ declaration,
201
+
202
+ update) => sourceCode
203
+ .getDeclaredVariables(declaration)
204
+ .flatMap((variable) => variable.references)
205
+ .some((reference) => reference.isWrite() &&
206
+ reference.init !== true &&
207
+ !isWithin(reference.identifier, update));
208
+ const isWithin = (
209
+
210
+ node,
211
+
212
+ container) => container.range[0] <= node.range[0] && node.range[1] <= container.range[1];
132
213
  //# sourceMappingURL=prefer-range-for-loop.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-range-for-loop.mjs","sourceRoot":"","sources":["../../src/rules/prefer-range-for-loop.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prefer-range-for-loop.mjs","sourceRoot":"","sources":["../../src/rules/prefer-range-for-loop.mts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ export declare const tsDataForgeRules: {
2
2
  readonly 'prefer-canonical-array-slicing': import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferCanonicalArraySlicing", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
3
  readonly 'prefer-canonical-length-guard': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useCanonicalGuard" | "useIsBoundedLengthArray" | "useIsFixedLengthArray" | "useIsMaxLengthArray" | "useIsMinLengthArray" | "useIsNonEmpty", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
4
4
  readonly 'prefer-canonical-length-cast': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useCanonicalCast", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
+ readonly 'prefer-arr-generate': import("@typescript-eslint/utils/ts-eslint").RuleModule<"suggestArrGenerate" | "useArrGenerate", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
6
  readonly 'prefer-arr-is-array': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useArrIsArray", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
7
  readonly 'prefer-arr-scan': import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferArrScanAccumulate" | "preferArrScanPrefix", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
8
  readonly 'prefer-arr-sum': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useArrSum" | "useArrSumBy", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;CAkBa,CAAC"}
1
+ {"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;CAmBa,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { noSideEffectImport } from './no-side-effect-import.mjs';
2
2
  import { noUnnecessaryTypeGuard } from './no-unnecessary-type-guard.mjs';
3
+ import { preferArrGenerate } from './prefer-arr-generate.mjs';
3
4
  import { preferArrIsArray } from './prefer-arr-is-array.mjs';
4
5
  import { preferArrScan } from './prefer-arr-scan.mjs';
5
6
  import { preferArrSum } from './prefer-arr-sum.mjs';
@@ -19,6 +20,7 @@ export const tsDataForgeRules = {
19
20
  'prefer-canonical-array-slicing': preferCanonicalArraySlicing,
20
21
  'prefer-canonical-length-guard': preferCanonicalLengthGuard,
21
22
  'prefer-canonical-length-cast': preferCanonicalLengthCast,
23
+ 'prefer-arr-generate': preferArrGenerate,
22
24
  'prefer-arr-is-array': preferArrIsArray,
23
25
  'prefer-arr-scan': preferArrScan,
24
26
  'prefer-arr-sum': preferArrSum,
@@ -1 +1 @@
1
- {"version":3,"file":"rules.mjs","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,gCAAgC,EAAE,2BAA2B;IAC7D,+BAA+B,EAAE,0BAA0B;IAC3D,8BAA8B,EAAE,yBAAyB;IACzD,qBAAqB,EAAE,gBAAgB;IACvC,iBAAiB,EAAE,aAAa;IAChC,gBAAgB,EAAE,YAAY;IAC9B,iBAAiB,EAAE,aAAa;IAChC,eAAe,EAAE,WAAW;IAC5B,2BAA2B,EAAE,qBAAqB;IAClD,uBAAuB,EAAE,kBAAkB;IAC3C,8BAA8B,EAAE,uBAAuB;IACvD,2BAA2B,EAAE,qBAAqB;IAClD,6BAA6B,EAAE,uBAAuB;IACtD,uBAAuB,EAAE,kBAAkB;IAC3C,2BAA2B,EAAE,sBAAsB;IACnD,sCAAsC,EAAE,gCAAgC;IACxE,oCAAoC,EAAE,6BAA6B;CAC3B,CAAC"}
1
+ {"version":3,"file":"rules.mjs","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,gCAAgC,EAAE,2BAA2B;IAC7D,+BAA+B,EAAE,0BAA0B;IAC3D,8BAA8B,EAAE,yBAAyB;IACzD,qBAAqB,EAAE,iBAAiB;IACxC,qBAAqB,EAAE,gBAAgB;IACvC,iBAAiB,EAAE,aAAa;IAChC,gBAAgB,EAAE,YAAY;IAC9B,iBAAiB,EAAE,aAAa;IAChC,eAAe,EAAE,WAAW;IAC5B,2BAA2B,EAAE,qBAAqB;IAClD,uBAAuB,EAAE,kBAAkB;IAC3C,8BAA8B,EAAE,uBAAuB;IACvD,2BAA2B,EAAE,qBAAqB;IAClD,6BAA6B,EAAE,uBAAuB;IACtD,uBAAuB,EAAE,kBAAkB;IAC3C,2BAA2B,EAAE,sBAAsB;IACnD,sCAAsC,EAAE,gCAAgC;IACxE,oCAAoC,EAAE,6BAA6B;CAC3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ts-data-forge",
3
- "version": "0.8.6",
3
+ "version": "0.9.0",
4
4
  "private": false,
5
5
  "description": "ESLint rules that steer code toward ts-data-forge idioms.",
6
6
  "keywords": [
@@ -35,17 +35,17 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@typescript-eslint/utils": "^8.71.1",
38
- "eslint-rule-forge": "^0.1.0",
39
- "ts-data-forge": "14.7.1",
38
+ "eslint-rule-forge": "^0.2.0",
39
+ "ts-data-forge": "14.8.0",
40
40
  "ts-type-forge": "~9.2.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@typescript-eslint/parser": "8.71.1",
44
44
  "@typescript-eslint/rule-tester": "8.71.1",
45
45
  "dedent": "1.7.2",
46
- "eslint-config-typed": "5.17.4",
47
- "eslint-plugin-ts-fortress": "1.3.3",
48
- "eslint-plugin-ts-type-forge": "0.8.8",
46
+ "eslint-config-typed": "5.19.0",
47
+ "eslint-plugin-ts-fortress": "1.3.4",
48
+ "eslint-plugin-ts-type-forge": "0.8.9",
49
49
  "prettier": "3.9.9",
50
50
  "prettier-plugin-organize-imports": "4.3.0",
51
51
  "prettier-plugin-packagejson": "3.0.2",
@@ -67,15 +67,15 @@
67
67
  "build": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/build.mts",
68
68
  "check:dist:branded-number-types": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-branded-number-types.mts",
69
69
  "check:ext": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-ext.mts",
70
- "check:lint": "oxlint . && eslint .",
71
- "check:test": "pnpm run z:vitest run",
72
- "check:test:cov": "pnpm run z:vitest run --coverage",
73
- "check:types": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
70
+ "check:lint": "node ../../tools/scripts/cmd/assert-deps-built.mts && oxlint . && eslint .",
71
+ "check:test": "node ../../tools/scripts/cmd/assert-deps-built.mts && pnpm run z:vitest run",
72
+ "check:test:cov": "node ../../tools/scripts/cmd/assert-deps-built.mts && pnpm run z:vitest run --coverage",
73
+ "check:types": "node ../../tools/scripts/cmd/assert-deps-built.mts && node ../../node_modules/typescript-native/bin/tsc --noEmit",
74
74
  "doc": "pnpm run gen:readme",
75
75
  "fix:fmt": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-uncommitted.mts --cwd .",
76
76
  "fix:fmt:diff": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-diff-from.mts origin/main --cwd .",
77
77
  "fix:fmt:full": "pnpm run z:prettier .",
78
- "fix:lint": "oxlint . --fix && eslint . --fix",
78
+ "fix:lint": "node ../../tools/scripts/cmd/assert-deps-built.mts && oxlint . --fix && eslint . --fix",
79
79
  "fmt": "pnpm run fix:fmt",
80
80
  "gen": "run-s gen:rule-types gen:readme",
81
81
  "gen:readme": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples.mts",
package/src/plugin.mts CHANGED
@@ -13,6 +13,7 @@ const recommendedRules = {
13
13
  'ts-data-forge/prefer-canonical-array-slicing': 'error',
14
14
  'ts-data-forge/prefer-canonical-length-cast': 'error',
15
15
  'ts-data-forge/prefer-canonical-length-guard': 'error',
16
+ 'ts-data-forge/prefer-arr-generate': 'error',
16
17
  'ts-data-forge/prefer-arr-is-array': 'error',
17
18
  'ts-data-forge/prefer-arr-scan': 'error',
18
19
  'ts-data-forge/prefer-arr-sum': 'error',
@@ -72,6 +72,21 @@ namespace PreferCanonicalLengthCast {
72
72
  export type RuleEntry = Linter.StringSeverity;
73
73
  }
74
74
 
75
+ /**
76
+ * @description Replace the filter-and-map idiom `xs.flatMap((x) => (cond ? [f(x)] : []))` with a loop in `Arr.generate` from ts-data-forge.
77
+ *
78
+ * ```md
79
+ * | key | value |
80
+ * | :--------- | :--------- |
81
+ * | type | suggestion |
82
+ * | deprecated | false |
83
+ * | fixable | code |
84
+ * ```
85
+ */
86
+ namespace PreferArrGenerate {
87
+ export type RuleEntry = Linter.StringSeverity;
88
+ }
89
+
75
90
  /**
76
91
  * @description Replace `Array.isArray` with `Arr.isArray` from ts-data-forge.
77
92
  *
@@ -148,7 +163,7 @@ namespace PreferAsInt {
148
163
  }
149
164
 
150
165
  /**
151
- * @description Replace `typeof u === "object" && u !== null` with `isNonNullObject(u)` from ts-data-forge.
166
+ * @description Replace `typeof u === "object" && u !== null`, in either order and anywhere in an `&&` chain, with `isNonNullObject(u)` from ts-data-forge.
152
167
  *
153
168
  * ```md
154
169
  * | key | value |
@@ -314,6 +329,7 @@ export type EslintTsDataForgeRules = Readonly<{
314
329
  'ts-data-forge/prefer-canonical-array-slicing': PreferCanonicalArraySlicing.RuleEntry;
315
330
  'ts-data-forge/prefer-canonical-length-guard': PreferCanonicalLengthGuard.RuleEntry;
316
331
  'ts-data-forge/prefer-canonical-length-cast': PreferCanonicalLengthCast.RuleEntry;
332
+ 'ts-data-forge/prefer-arr-generate': PreferArrGenerate.RuleEntry;
317
333
  'ts-data-forge/prefer-arr-is-array': PreferArrIsArray.RuleEntry;
318
334
  'ts-data-forge/prefer-arr-scan': PreferArrScan.RuleEntry;
319
335
  'ts-data-forge/prefer-arr-sum': PreferArrSum.RuleEntry;
@@ -10,6 +10,7 @@ import {
10
10
  typeWrapperLayers,
11
11
  } from 'eslint-rule-forge';
12
12
  import type { DeepReadonly } from 'ts-type-forge';
13
+ import type * as ts from 'typescript';
13
14
 
14
15
  const isIntegerLiteral = (node: DeepReadonly<TSESTree.Expression>): boolean =>
15
16
  node.type === AST_NODE_TYPES.Literal &&
@@ -144,7 +145,8 @@ type LengthComparison = Readonly<{
144
145
  * Parses a `<array>.length <op> <bound>` comparison (in either operand order)
145
146
  * into its array expression, integer-literal/`const` `bound`, and whether it is
146
147
  * a lower (`min`) or upper (`max`) length bound. Returns `undefined` for
147
- * anything else. The length and the bound are read through type wrappers; the
148
+ * anything else. The comparison, the length and the bound are read through
149
+ * type wrappers; the
148
150
  * `bound` returned is the literal or constant underneath, since a wrapper such
149
151
  * as `as number` would only widen the length a guard narrows to.
150
152
  *
@@ -153,10 +155,12 @@ type LengthComparison = Readonly<{
153
155
  */
154
156
  export const parseLengthComparison = (
155
157
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
156
- node: TSESTree.Expression,
158
+ wrapped: TSESTree.Expression,
157
159
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
158
160
  sourceCode: TSESLint.SourceCode,
159
161
  ): LengthComparison | undefined => {
162
+ const node = skipTypeWrappers(wrapped);
163
+
160
164
  if (
161
165
  node.type !== AST_NODE_TYPES.BinaryExpression ||
162
166
  (node.operator !== '>=' && node.operator !== '<=')
@@ -201,6 +205,8 @@ export const parseLengthComparison = (
201
205
  * together form the `Arr.isBoundedLengthArray` pattern handled by
202
206
  * `prefer-arr-is-bounded-length-array`. The single-bound rules skip such
203
207
  * operands so the bounded rule rewrites the whole `&&` instead of the parts.
208
+ * A comparison wrapped as a whole (`(xs.length >= 1 satisfies boolean) && …`)
209
+ * is still the operand.
204
210
  */
205
211
  export const isPartOfBoundedLengthCheck = (
206
212
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -208,10 +214,12 @@ export const isPartOfBoundedLengthCheck = (
208
214
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
209
215
  sourceCode: TSESLint.SourceCode,
210
216
  ): boolean => {
211
- const { parent } = node;
217
+ const operand = outermostTypeWrapper(node);
218
+
219
+ const { parent } = operand;
212
220
 
213
221
  if (
214
- parent.type !== AST_NODE_TYPES.LogicalExpression ||
222
+ parent?.type !== AST_NODE_TYPES.LogicalExpression ||
215
223
  parent.operator !== '&&'
216
224
  ) {
217
225
  return false;
@@ -223,7 +231,7 @@ export const isPartOfBoundedLengthCheck = (
223
231
  return false;
224
232
  }
225
233
 
226
- const sibling = parent.left === node ? parent.right : parent.left;
234
+ const sibling = parent.left === operand ? parent.right : parent.left;
227
235
 
228
236
  const other = parseLengthComparison(sibling, sourceCode);
229
237
 
@@ -237,6 +245,15 @@ export const isPartOfBoundedLengthCheck = (
237
245
  );
238
246
  };
239
247
 
248
+ /** The outermost of the type wrappers around `node`, or `node` itself. */
249
+ const outermostTypeWrapper = (
250
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
251
+ node: TSESTree.Node,
252
+ ): TSESTree.Node =>
253
+ node.parent !== undefined && isTypeWrapper(node.parent)
254
+ ? outermostTypeWrapper(node.parent)
255
+ : node;
256
+
240
257
  type VariableDefinition = Readonly<{
241
258
  type: string;
242
259
  parent: TSESTree.VariableDeclaration;
@@ -248,3 +265,53 @@ const isVariableDefinition = (
248
265
  def: TSESLint.Scope.Definition,
249
266
  ): def is TSESLint.Scope.Definition & VariableDefinition =>
250
267
  (def.type as string) === 'Variable';
268
+
269
+ /**
270
+ * Whether `node`, read through its type wrappers, is the identifier `name`:
271
+ * `Number`, `(Number as NumberConstructor)` and `Number!` are the same object.
272
+ */
273
+ export const isIdentifierNamed = (
274
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
275
+ node: TSESTree.Node,
276
+ name: string,
277
+ ): boolean => {
278
+ const unwrapped = skipTypeWrappers(node);
279
+
280
+ return (
281
+ unwrapped.type === AST_NODE_TYPES.Identifier && unwrapped.name === name
282
+ );
283
+ };
284
+
285
+ /**
286
+ * Whether `holds` is true of the type of every layer of type wrappers around
287
+ * `node` (see {@link typeWrapperLayers}), outermost to innermost; `false`
288
+ * without type information. A widening cast (`s as string | number`) is the
289
+ * author saying the value may be more than it is, and is respected; a
290
+ * narrowing one (`s!`, `v as unknown as string`) cannot vouch for what the
291
+ * value's own type does not, and the fix, which keeps the wrapper, has to
292
+ * type-check at every layer too.
293
+ */
294
+ export const typeHoldsAtEveryLayer = (
295
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
296
+ sourceCode: TSESLint.SourceCode,
297
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
298
+ node: TSESTree.Node,
299
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
300
+ holds: (type: ts.Type, typeChecker: ts.TypeChecker) => boolean,
301
+ ): boolean => {
302
+ const services = sourceCode.parserServices;
303
+
304
+ const checker = services?.program?.getTypeChecker();
305
+
306
+ if (checker === undefined) {
307
+ return false;
308
+ }
309
+
310
+ return typeWrapperLayers(node).every((layer) => {
311
+ const tsNode = services?.esTreeNodeToTSNodeMap?.get(layer);
312
+
313
+ return (
314
+ tsNode !== undefined && holds(checker.getTypeAtLocation(tsNode), checker)
315
+ );
316
+ });
317
+ };
@@ -1 +1,13 @@
1
+ import * as ts from 'typescript';
2
+
1
3
  export const TS_DATA_FORGE_MODULE = 'ts-data-forge';
4
+
5
+ /** The type flags of every primitive type but `void`. */
6
+ export const primitiveTypeFlags =
7
+ ts.TypeFlags.StringLike |
8
+ ts.TypeFlags.NumberLike |
9
+ ts.TypeFlags.BigIntLike |
10
+ ts.TypeFlags.BooleanLike |
11
+ ts.TypeFlags.ESSymbolLike |
12
+ ts.TypeFlags.Null |
13
+ ts.TypeFlags.Undefined;