eslint-plugin-ts-std-forge 0.1.8 → 0.1.10

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 (33) hide show
  1. package/dist/rule-types.d.mts +3 -2
  2. package/dist/rule-types.d.mts.map +1 -1
  3. package/dist/rule-types.mjs.map +1 -1
  4. package/dist/rules/ast-utils.d.mts +8 -5
  5. package/dist/rules/ast-utils.d.mts.map +1 -1
  6. package/dist/rules/ast-utils.mjs +14 -13
  7. package/dist/rules/ast-utils.mjs.map +1 -1
  8. package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
  9. package/dist/rules/prefer-is-non-null-object.mjs +113 -38
  10. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  11. package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
  12. package/dist/rules/prefer-is-record-and-has-key.mjs +95 -34
  13. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  14. package/dist/rules/prefer-safe-array-length-guard.d.mts.map +1 -1
  15. package/dist/rules/prefer-safe-array-length-guard.mjs +4 -10
  16. package/dist/rules/prefer-safe-array-length-guard.mjs.map +1 -1
  17. package/dist/rules/prefer-safe-number-parse-integer.mjs +4 -3
  18. package/dist/rules/prefer-safe-number-parse-integer.mjs.map +1 -1
  19. package/dist/rules/prefer-safe-number-parse.mjs +4 -3
  20. package/dist/rules/prefer-safe-number-parse.mjs.map +1 -1
  21. package/package.json +10 -10
  22. package/src/rule-types.mts +3 -2
  23. package/src/rules/ast-utils.mts +20 -21
  24. package/src/rules/prefer-is-non-null-object.mts +152 -49
  25. package/src/rules/prefer-is-non-null-object.test.mts +107 -0
  26. package/src/rules/prefer-is-record-and-has-key.mts +141 -53
  27. package/src/rules/prefer-is-record-and-has-key.test.mts +116 -29
  28. package/src/rules/prefer-safe-array-length-guard.mts +11 -16
  29. package/src/rules/prefer-safe-array-length-guard.test.mts +19 -5
  30. package/src/rules/prefer-safe-number-parse-integer.mts +8 -8
  31. package/src/rules/prefer-safe-number-parse-integer.test.mts +19 -5
  32. package/src/rules/prefer-safe-number-parse.mts +8 -8
  33. package/src/rules/prefer-safe-number-parse.test.mts +19 -5
@@ -1 +1 @@
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
+ {"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,7 +1,7 @@
1
1
  import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
2
2
  import { buildNamedImportFix, getArgumentText, getImportDeclarations, getNamedImports, skipTypeWrappers, } from 'eslint-rule-forge';
3
3
  import * as ts from 'typescript';
4
- import { getValueType, isIdentifierNamed } from './ast-utils.mjs';
4
+ import { isIdentifierNamed, typeHoldsAtEveryLayer } from './ast-utils.mjs';
5
5
  import { TS_STD_FORGE_MODULE } from './constants.mjs';
6
6
 
7
7
 
@@ -74,8 +74,9 @@ export const preferSafeNumberParseInteger = {
74
74
 
75
75
 
76
76
 
77
- const argType = getValueType(sourceCode, firstArg);
78
- if (argType === undefined || !isStringType(argType)) {
77
+
78
+
79
+ if (!typeHoldsAtEveryLayer(sourceCode, firstArg, isStringType)) {
79
80
  return;
80
81
  }
81
82
  mut_nodesToFix.push({ node, argExpression: firstArg });
@@ -1 +1 @@
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
+ {"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,7 +1,7 @@
1
1
  import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
2
2
  import { buildNamedImportFix, getArgumentText, getImportDeclarations, getNamedImports, skipTypeWrappers, } from 'eslint-rule-forge';
3
3
  import * as ts from 'typescript';
4
- import { getValueType, isIdentifierNamed } from './ast-utils.mjs';
4
+ import { isIdentifierNamed, typeHoldsAtEveryLayer } from './ast-utils.mjs';
5
5
  import { TS_STD_FORGE_MODULE } from './constants.mjs';
6
6
 
7
7
 
@@ -75,8 +75,9 @@ export const preferSafeNumberParse = {
75
75
 
76
76
 
77
77
 
78
- const argType = getValueType(sourceCode, firstArg);
79
- if (argType === undefined || !isStringType(argType)) {
78
+
79
+
80
+ if (!typeHoldsAtEveryLayer(sourceCode, firstArg, isStringType)) {
80
81
  return;
81
82
  }
82
83
  mut_nodesToFix.push({ node, argExpression: firstArg });
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-safe-number-parse.mjs","sourceRoot":"","sources":["../../src/rules/prefer-safe-number-parse.mts"],"names":[],"mappings":"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"}
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ts-std-forge",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "private": false,
5
5
  "description": "ESLint rules that steer code toward ts-std-forge idioms.",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@typescript-eslint/utils": "^8.71.1",
38
- "eslint-rule-forge": "^0.1.0",
38
+ "eslint-rule-forge": "^0.2.0",
39
39
  "ts-std-forge": "0.5.1",
40
40
  "ts-type-forge": "~9.2.2"
41
41
  },
@@ -43,9 +43,9 @@
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",
@@ -66,15 +66,15 @@
66
66
  "scripts": {
67
67
  "build": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/build.mts",
68
68
  "check:ext": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/check-ext.mts",
69
- "check:lint": "oxlint . && eslint .",
70
- "check:test": "pnpm run z:vitest run",
71
- "check:test:cov": "pnpm run z:vitest run --coverage",
72
- "check:types": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
69
+ "check:lint": "node ../../tools/scripts/cmd/assert-deps-built.mts && oxlint . && eslint .",
70
+ "check:test": "node ../../tools/scripts/cmd/assert-deps-built.mts && pnpm run z:vitest run",
71
+ "check:test:cov": "node ../../tools/scripts/cmd/assert-deps-built.mts && pnpm run z:vitest run --coverage",
72
+ "check:types": "node ../../tools/scripts/cmd/assert-deps-built.mts && node ../../node_modules/typescript-native/bin/tsc --noEmit",
73
73
  "doc": "pnpm run gen:readme",
74
74
  "fix:fmt": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-uncommitted.mts --cwd .",
75
75
  "fix:fmt:diff": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/format-diff-from.mts origin/main --cwd .",
76
76
  "fix:fmt:full": "pnpm run z:prettier .",
77
- "fix:lint": "oxlint . --fix && eslint . --fix",
77
+ "fix:lint": "node ../../tools/scripts/cmd/assert-deps-built.mts && oxlint . --fix && eslint . --fix",
78
78
  "fmt": "pnpm run fix:fmt",
79
79
  "gen": "run-s gen:rule-types gen:readme",
80
80
  "gen:readme": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples.mts",
@@ -5,10 +5,11 @@
5
5
 
6
6
  import type { Linter } from 'eslint';
7
7
  import { expectType } from 'ts-std-forge';
8
+ import type { ReadonlyRecord } from 'ts-type-forge';
8
9
  import type { tsStdForgeRules } from './rules/index.mjs';
9
10
 
10
11
  /**
11
- * @description Replace `typeof u === "object" && u !== null` with `isNonNullObject(u)` from ts-std-forge.
12
+ * @description Replace `typeof u === "object" && u !== null`, in either order and anywhere in an `&&` chain, with `isNonNullObject(u)` from ts-std-forge.
12
13
  *
13
14
  * ```md
14
15
  * | key | value |
@@ -106,7 +107,7 @@ export type EslintTsStdForgeRules = Readonly<{
106
107
  'ts-std-forge/prefer-safe-number-parse-integer': PreferSafeNumberParseInteger.RuleEntry;
107
108
  }>;
108
109
 
109
- export type EslintTsStdForgeRulesOption = Readonly<{}>;
110
+ export type EslintTsStdForgeRulesOption = ReadonlyRecord<never, never>;
110
111
 
111
112
  // If this assertion fails to type-check, this generated file has drifted from
112
113
  // the actual plugin rules — re-run `pnpm run gen:rule-types`.
@@ -3,7 +3,7 @@ import {
3
3
  type TSESLint,
4
4
  type TSESTree,
5
5
  } from '@typescript-eslint/utils';
6
- import { isTypeWrapper, skipTypeWrappers } from 'eslint-rule-forge';
6
+ import { skipTypeWrappers, typeWrapperLayers } from 'eslint-rule-forge';
7
7
  import type * as ts from 'typescript';
8
8
 
9
9
  /**
@@ -23,36 +23,35 @@ export const isIdentifierNamed = (
23
23
  };
24
24
 
25
25
  /**
26
- * The type of the value `node` evaluates to, asked of the expression inside
27
- * its type wrappers rather than of the cast, or `undefined` without type
28
- * information. A `!` among the wrappers still takes `null` and `undefined`
29
- * out, since that much the source asserts about the value itself.
26
+ * Whether `holds` is true of the type of every layer of type wrappers around
27
+ * `node` (see {@link typeWrapperLayers}), outermost to innermost; `false`
28
+ * without type information. A widening cast (`s as string | number`) is the
29
+ * author saying the value may be more than it is, and is respected; a
30
+ * narrowing one (`s!`, `v as unknown as string`) cannot vouch for what the
31
+ * value's own type does not, and the fix, which keeps the wrapper, has to
32
+ * type-check at every layer too.
30
33
  */
31
- export const getValueType = (
34
+ export const typeHoldsAtEveryLayer = (
32
35
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
33
36
  sourceCode: TSESLint.SourceCode,
34
37
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
35
38
  node: TSESTree.Node,
36
- ): ts.Type | undefined => {
39
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
40
+ holds: (type: ts.Type, typeChecker: ts.TypeChecker) => boolean,
41
+ ): boolean => {
37
42
  const services = sourceCode.parserServices;
38
43
 
39
44
  const checker = services?.program?.getTypeChecker();
40
45
 
41
- const tsNode = services?.esTreeNodeToTSNodeMap?.get(skipTypeWrappers(node));
42
-
43
- if (checker === undefined || tsNode === undefined) {
44
- return undefined;
46
+ if (checker === undefined) {
47
+ return false;
45
48
  }
46
49
 
47
- const type = checker.getTypeAtLocation(tsNode);
50
+ return typeWrapperLayers(node).every((layer) => {
51
+ const tsNode = services?.esTreeNodeToTSNodeMap?.get(layer);
48
52
 
49
- return hasNonNullAssertion(node) ? checker.getNonNullableType(type) : type;
53
+ return (
54
+ tsNode !== undefined && holds(checker.getTypeAtLocation(tsNode), checker)
55
+ );
56
+ });
50
57
  };
51
-
52
- const hasNonNullAssertion = (
53
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
54
- node: TSESTree.Node,
55
- ): boolean =>
56
- isTypeWrapper(node) &&
57
- (node.type === AST_NODE_TYPES.TSNonNullExpression ||
58
- hasNonNullAssertion(node.expression));
@@ -7,6 +7,8 @@ import {
7
7
  buildNamedImportFix,
8
8
  getImportDeclarations,
9
9
  getNamedImports,
10
+ getRangeWithParens,
11
+ parenthesesDepth,
10
12
  skipTypeWrappers,
11
13
  } from 'eslint-rule-forge';
12
14
  import { TS_STD_FORGE_MODULE } from './constants.mjs';
@@ -20,7 +22,7 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
20
22
  type: 'suggestion',
21
23
  docs: {
22
24
  description:
23
- 'Replace `typeof u === "object" && u !== null` with `isNonNullObject(u)` from ts-std-forge.',
25
+ 'Replace `typeof u === "object" && u !== null`, in either order and anywhere in an `&&` chain, with `isNonNullObject(u)` from ts-std-forge.',
24
26
  },
25
27
  fixable: 'code',
26
28
  schema: [],
@@ -40,20 +42,16 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
40
42
  TS_STD_FORGE_MODULE,
41
43
  );
42
44
 
43
- const mut_nodesToFix: {
44
- node: TSESTree.LogicalExpression;
45
- identifierName: string;
46
- }[] = [];
45
+ const mut_pairsToFix: NonNullObjectPair[] = [];
47
46
 
48
47
  return {
49
48
  LogicalExpression: (node) => {
50
- const identifierName = getNonNullObjectIdentifierName(node);
51
-
52
- if (identifierName === undefined) {
49
+ // A chain is read once, from its outermost `&&`.
50
+ if (node.operator !== '&&' || isChainOperand(sourceCode, node)) {
53
51
  return;
54
52
  }
55
53
 
56
- mut_nodesToFix.push({ node, identifierName });
54
+ mut_pairsToFix.push(...findNonNullObjectPairs(sourceCode, node));
57
55
  },
58
56
  'Program:exit': () => {
59
57
  const hasIsNonNullObjectImport =
@@ -66,10 +64,13 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
66
64
  // with it.
67
65
  for (const [
68
66
  index,
69
- { node, identifierName },
70
- ] of mut_nodesToFix.entries()) {
67
+ { range, identifierName },
68
+ ] of mut_pairsToFix.entries()) {
71
69
  context.report({
72
- node,
70
+ loc: {
71
+ start: sourceCode.getLocFromIndex(range[0]),
72
+ end: sourceCode.getLocFromIndex(range[1]),
73
+ },
73
74
  messageId: 'useIsNonNullObject',
74
75
  fix: (fixer) => {
75
76
  const replacement = `isNonNullObject(${identifierName})`;
@@ -81,7 +82,10 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
81
82
  ])
82
83
  : [];
83
84
 
84
- return [...importFixes, fixer.replaceText(node, replacement)];
85
+ return [
86
+ ...importFixes,
87
+ fixer.replaceTextRange(range, replacement),
88
+ ];
85
89
  },
86
90
  });
87
91
  }
@@ -91,41 +95,124 @@ export const preferIsNonNullObject: TSESLint.RuleModule<MessageIds, Options> = {
91
95
  defaultOptions: [],
92
96
  } as const;
93
97
 
94
- // Every operand below is read through its type wrappers: `typeof (u satisfies
95
- // unknown) === 'object' && u! !== null` is the same check.
98
+ /**
99
+ * A `typeof u === 'object'` and a `u !== null` next to each other in an `&&`
100
+ * chain, as the source range from the first to the second (parentheses
101
+ * included) and the name of `u`.
102
+ */
103
+ type NonNullObjectPair = Readonly<{
104
+ range: TSESTree.Range;
105
+ identifierName: string;
106
+ }>;
96
107
 
97
- const getNonNullObjectIdentifierName = (
108
+ /**
109
+ * Whether `node` is an operand of an enclosing `&&` chain: a `&&` written
110
+ * directly under another one, without parentheses.
111
+ */
112
+ const isChainOperand = (
113
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
114
+ sourceCode: TSESLint.SourceCode,
98
115
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
99
116
  node: TSESTree.LogicalExpression,
100
- ): string | undefined => {
101
- if (node.operator !== '&&') {
102
- return undefined;
103
- }
117
+ ): boolean =>
118
+ node.parent.type === AST_NODE_TYPES.LogicalExpression &&
119
+ node.parent.operator === '&&' &&
120
+ parenthesesDepth(sourceCode, node) === 0;
121
+
122
+ /**
123
+ * Every non-overlapping pair in the `&&` chain `node` heads, left to right. The
124
+ * two halves may come in either order, and the pair may have operands before
125
+ * and after it: `a && u !== null && typeof u === 'object' && b`. They have to
126
+ * be next to each other, so that the pair is one range of the source.
127
+ */
128
+ const findNonNullObjectPairs = (
129
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
130
+ sourceCode: TSESLint.SourceCode,
131
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
132
+ node: TSESTree.LogicalExpression,
133
+ ): readonly NonNullObjectPair[] => {
134
+ const operands = chainOperands(sourceCode, node);
135
+
136
+ const pairsFrom = (index: number): readonly NonNullObjectPair[] => {
137
+ const first = operands[index];
138
+
139
+ const second = operands[index + 1];
140
+
141
+ if (first === undefined || second === undefined) {
142
+ return [];
143
+ }
144
+
145
+ const identifierName =
146
+ pairIdentifierName(first, second) ?? pairIdentifierName(second, first);
147
+
148
+ return identifierName === undefined
149
+ ? pairsFrom(index + 1)
150
+ : [
151
+ {
152
+ range: [
153
+ getRangeWithParens(sourceCode, first)[0],
154
+ getRangeWithParens(sourceCode, second)[1],
155
+ ],
156
+ identifierName,
157
+ },
158
+ ...pairsFrom(index + 2),
159
+ ];
160
+ };
104
161
 
105
- const leftIdentifierName = getTypeofObjectIdentifierName(
106
- skipTypeWrappers(node.left),
162
+ return pairsFrom(0);
163
+ };
164
+
165
+ /**
166
+ * The operands of the `&&` chain `node`, left to right. A parenthesized `&&`
167
+ * is one operand: its halves cannot be replaced without its parentheses.
168
+ */
169
+ const chainOperands = (
170
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
171
+ sourceCode: TSESLint.SourceCode,
172
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
173
+ node: TSESTree.LogicalExpression,
174
+ ): readonly TSESTree.Expression[] =>
175
+ [node.left, node.right].flatMap((operand) =>
176
+ operand.type === AST_NODE_TYPES.LogicalExpression &&
177
+ operand.operator === '&&' &&
178
+ parenthesesDepth(sourceCode, operand) === 0
179
+ ? chainOperands(sourceCode, operand)
180
+ : [operand],
107
181
  );
108
182
 
109
- const rightIdentifierName = getNonNullCheckIdentifierName(
110
- skipTypeWrappers(node.right),
183
+ // Every operand below is read through its type wrappers: `typeof (u satisfies
184
+ // unknown) === 'object' && u! !== null` is the same check.
185
+
186
+ /**
187
+ * The name of `u` when `typeofCheck` is `typeof u === 'object'` and
188
+ * `nullCheck` is `u !== null` for the same `u`.
189
+ */
190
+ const pairIdentifierName = (
191
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
192
+ typeofCheck: TSESTree.Expression,
193
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
194
+ nullCheck: TSESTree.Expression,
195
+ ): string | undefined => {
196
+ const identifierName = getTypeofObjectIdentifierName(
197
+ skipTypeWrappers(typeofCheck),
111
198
  );
112
199
 
113
- return leftIdentifierName === undefined ||
114
- rightIdentifierName === undefined ||
115
- leftIdentifierName !== rightIdentifierName
116
- ? undefined
117
- : leftIdentifierName;
200
+ return identifierName !== undefined &&
201
+ identifierName ===
202
+ getNonNullCheckIdentifierName(skipTypeWrappers(nullCheck))
203
+ ? identifierName
204
+ : undefined;
118
205
  };
119
206
 
207
+ /** `u` of `typeof u === 'object'`, in either operand order. */
120
208
  const getTypeofObjectIdentifierName = (
121
209
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
122
210
  node: TSESTree.Node,
123
211
  ): string | undefined => {
124
- if (node.type !== AST_NODE_TYPES.BinaryExpression) {
125
- return undefined;
126
- }
127
-
128
- if (node.operator !== '===') {
212
+ if (
213
+ node.type !== AST_NODE_TYPES.BinaryExpression ||
214
+ node.operator !== '==='
215
+ ) {
129
216
  return undefined;
130
217
  }
131
218
 
@@ -133,31 +220,39 @@ const getTypeofObjectIdentifierName = (
133
220
 
134
221
  const right = skipTypeWrappers(node.right);
135
222
 
223
+ const typeofSide = isLiteralOf(right, 'object')
224
+ ? left
225
+ : isLiteralOf(left, 'object')
226
+ ? right
227
+ : undefined;
228
+
136
229
  if (
137
- left.type !== AST_NODE_TYPES.UnaryExpression ||
138
- left.operator !== 'typeof' ||
139
- right.type !== AST_NODE_TYPES.Literal ||
140
- right.value !== 'object'
230
+ typeofSide?.type !== AST_NODE_TYPES.UnaryExpression ||
231
+ typeofSide.operator !== 'typeof'
141
232
  ) {
142
233
  return undefined;
143
234
  }
144
235
 
145
- const argument = skipTypeWrappers(left.argument);
236
+ const argument = skipTypeWrappers(typeofSide.argument);
146
237
 
147
238
  return argument.type === AST_NODE_TYPES.Identifier
148
239
  ? argument.name
149
240
  : undefined;
150
241
  };
151
242
 
243
+ /**
244
+ * `u` of `u !== null`, in either operand order. `u != null` also excludes
245
+ * `undefined`, which `typeof u === 'object'` has already excluded, so it is
246
+ * the same check here.
247
+ */
152
248
  const getNonNullCheckIdentifierName = (
153
249
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
154
250
  node: TSESTree.Node,
155
251
  ): string | undefined => {
156
- if (node.type !== AST_NODE_TYPES.BinaryExpression) {
157
- return undefined;
158
- }
159
-
160
- if (node.operator !== '!==') {
252
+ if (
253
+ node.type !== AST_NODE_TYPES.BinaryExpression ||
254
+ (node.operator !== '!==' && node.operator !== '!=')
255
+ ) {
161
256
  return undefined;
162
257
  }
163
258
 
@@ -165,9 +260,17 @@ const getNonNullCheckIdentifierName = (
165
260
 
166
261
  const right = skipTypeWrappers(node.right);
167
262
 
168
- return left.type !== AST_NODE_TYPES.Identifier ||
169
- right.type !== AST_NODE_TYPES.Literal ||
170
- right.value !== null
171
- ? undefined
172
- : left.name;
263
+ const checked = isLiteralOf(right, null)
264
+ ? left
265
+ : isLiteralOf(left, null)
266
+ ? right
267
+ : undefined;
268
+
269
+ return checked?.type === AST_NODE_TYPES.Identifier ? checked.name : undefined;
173
270
  };
271
+
272
+ const isLiteralOf = (
273
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
274
+ node: TSESTree.Node,
275
+ value: string | null,
276
+ ): boolean => node.type === AST_NODE_TYPES.Literal && node.value === value;
@@ -106,3 +106,110 @@ describe('prefer-is-non-null-object through type wrappers', () => {
106
106
  ],
107
107
  });
108
108
  });
109
+
110
+ describe('prefer-is-non-null-object in other forms', () => {
111
+ ruleTester.run('prefer-is-non-null-object', preferIsNonNullObject, {
112
+ valid: [
113
+ {
114
+ name: 'the two halves joined by `||`',
115
+ code: dedent`
116
+ const ok = typeof u === 'object' || u !== null;
117
+ `,
118
+ },
119
+ {
120
+ name: 'the two halves not next to each other in the chain',
121
+ code: dedent`
122
+ declare const a: boolean;
123
+ const ok = typeof u === 'object' && a && u !== null;
124
+ `,
125
+ },
126
+ {
127
+ name: 'an undefined check is not a null check',
128
+ code: dedent`
129
+ const ok = u !== undefined && typeof u === 'object';
130
+ `,
131
+ },
132
+ {
133
+ name: 'the halves split by parentheses',
134
+ code: dedent`
135
+ declare const b: boolean;
136
+ const ok = typeof u === 'object' && (u !== null && b);
137
+ `,
138
+ },
139
+ ],
140
+ invalid: [
141
+ {
142
+ name: 'the halves in reverse order',
143
+ code: dedent`
144
+ const ok = u !== null && typeof u === 'object';
145
+ `,
146
+ output: dedent`
147
+ import { isNonNullObject } from 'ts-std-forge';
148
+ const ok = isNonNullObject(u);
149
+ `,
150
+ errors: [{ messageId: 'useIsNonNullObject' }],
151
+ },
152
+ {
153
+ name: 'each comparison with its operands swapped',
154
+ code: dedent`
155
+ const ok = 'object' === typeof u && null !== u;
156
+ `,
157
+ output: dedent`
158
+ import { isNonNullObject } from 'ts-std-forge';
159
+ const ok = isNonNullObject(u);
160
+ `,
161
+ errors: [{ messageId: 'useIsNonNullObject' }],
162
+ },
163
+ {
164
+ name: '`!= null`, which typeof has already made the same check',
165
+ code: dedent`
166
+ const ok = typeof u === 'object' && u != null;
167
+ `,
168
+ output: dedent`
169
+ import { isNonNullObject } from 'ts-std-forge';
170
+ const ok = isNonNullObject(u);
171
+ `,
172
+ errors: [{ messageId: 'useIsNonNullObject' }],
173
+ },
174
+ {
175
+ name: 'the pair at the start, the end and the middle of a longer chain',
176
+ code: dedent`
177
+ declare const a: boolean;
178
+ declare const b: boolean;
179
+ const x = typeof u === 'object' && u !== null && 'k' in u;
180
+ const y = a && typeof u === 'object' && u !== null;
181
+ const z = a && u !== null && (typeof u === 'object') && b;
182
+ `,
183
+ output: dedent`
184
+ import { isNonNullObject } from 'ts-std-forge';
185
+ declare const a: boolean;
186
+ declare const b: boolean;
187
+ const x = isNonNullObject(u) && 'k' in u;
188
+ const y = a && isNonNullObject(u);
189
+ const z = a && isNonNullObject(u) && b;
190
+ `,
191
+ errors: [
192
+ { messageId: 'useIsNonNullObject' },
193
+ { messageId: 'useIsNonNullObject' },
194
+ { messageId: 'useIsNonNullObject' },
195
+ ],
196
+ },
197
+ {
198
+ name: 'two pairs in one chain',
199
+ code: dedent`
200
+ declare const v: unknown;
201
+ const ok = typeof u === 'object' && u !== null && v !== null && typeof v === 'object';
202
+ `,
203
+ output: dedent`
204
+ import { isNonNullObject } from 'ts-std-forge';
205
+ declare const v: unknown;
206
+ const ok = isNonNullObject(u) && isNonNullObject(v);
207
+ `,
208
+ errors: [
209
+ { messageId: 'useIsNonNullObject' },
210
+ { messageId: 'useIsNonNullObject' },
211
+ ],
212
+ },
213
+ ],
214
+ });
215
+ });