Skip to content

Commit a2a5b1b

Browse files
committed
refactor: enforce nullish checks
1 parent eac06be commit a2a5b1b

File tree

57 files changed

+397
-124
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+397
-124
lines changed

eslint.config.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,21 @@ const p11tGroups = {
7171
};
7272

7373
const enableTypeCheckedRules = {
74-
...tseslint.configs.strictTypeCheckedOnly.map(x => x.rules).reduce((a, b) => ({ ...a, ...b }), {}),
74+
...tseslint.configs.strictTypeCheckedOnly
75+
.map(x => x.rules)
76+
.reduce((a, b) => ({ ...a, ...b }), {}),
7577
...eslintPluginSafeTypeScript.configs.recommended.rules,
7678
"@susisu/safe-typescript/no-unsafe-object-property-check": "off",
7779
"@susisu/safe-typescript/no-unsafe-object-property-overwrite": "off",
7880
"@typescript-eslint/consistent-type-exports": "error",
79-
"@typescript-eslint/strict-boolean-expressions": ["warn", {
81+
"@typescript-eslint/strict-boolean-expressions": ["error", {
8082
allowAny: false,
8183
allowNullableBoolean: true,
8284
allowNullableEnum: false,
83-
allowNullableNumber: false,
84-
allowNullableObject: true,
85+
allowNullableNumber: true,
86+
allowNullableObject: false,
8587
allowNullableString: false,
86-
allowNumber: false,
88+
allowNumber: true,
8789
allowString: false,
8890
}],
8991
} as const;
@@ -150,11 +152,11 @@ export default tseslint.config(
150152
files: [...GLOB_JS, ...GLOB_TS],
151153
rules: {
152154
curly: "warn",
153-
eqeqeq: ["error", "always"],
155+
eqeqeq: ["error", "smart"],
154156
"no-console": "error",
155157
"no-else-return": "error",
156158
"no-fallthrough": ["error", { commentPattern: ".*intentional fallthrough.*" }],
157-
"no-implicit-coercion": ["warn", { allow: ["!!"] }],
159+
"no-implicit-coercion": "error",
158160
"no-mixed-operators": "warn",
159161
"no-process-exit": "error",
160162
"no-undef": "off",
@@ -256,6 +258,7 @@ export default tseslint.config(
256258
"eslint-plugin/require-meta-docs-url": "off",
257259
// Part: local rules
258260
"local/avoid-multiline-template-expression": "warn",
261+
"local/prefer-eqeq-nullish-comparison": "warn",
259262
},
260263
settings: {
261264
"import-x/parsers": {

packages/core/src/component/component-collector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export function useComponentCollector(
8787
.reverse()
8888
.some(r => {
8989
return context.sourceCode.getScope(r).block === entry.node
90-
&& r.argument !== null
90+
&& r.argument != null
9191
&& !JSX.isJSXValue(r.argument, jsxCtx, hint);
9292
});
9393
if (shouldDrop) {
@@ -153,7 +153,7 @@ export function useComponentCollector(
153153
const component = Array
154154
.from(components.values())
155155
.findLast(({ name }) => O.exists(name, n => n === componentName));
156-
if (!component) {
156+
if (component == null) {
157157
return;
158158
}
159159
components.set(component._, {

packages/core/src/component/component-name.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ export function getComponentNameFromIdentifier(node: TSESTree.Identifier | TSEST
99
}
1010

1111
export function isComponentName(name: string) {
12-
return !!name && RE_COMPONENT_NAME.test(name);
12+
return RE_COMPONENT_NAME.test(name);
1313
}

packages/core/src/component/is.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
88
* @returns `true` if the node is a class component, `false` otherwise
99
*/
1010
export function isClassComponent(node: TSESTree.Node): node is AST.TSESTreeClass {
11-
if ("superClass" in node && node.superClass) {
11+
if ("superClass" in node && node.superClass != null) {
1212
const re = /^(?:Pure)?Component$/u;
1313
switch (true) {
1414
case node.superClass.type === T.Identifier:
@@ -27,7 +27,7 @@ export function isClassComponent(node: TSESTree.Node): node is AST.TSESTreeClass
2727
* @returns `true` if the node is a pure component, `false` otherwise
2828
*/
2929
export function isPureComponent(node: TSESTree.Node) {
30-
if ("superClass" in node && node.superClass) {
30+
if ("superClass" in node && node.superClass != null) {
3131
const re = /^PureComponent$/u;
3232
switch (true) {
3333
case node.superClass.type === T.Identifier:

packages/core/src/component/misc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ export function hasNoneOrValidComponentName(node: AST.TSESTreeFunction, context:
1414
const name = Array.isArray(id)
1515
? id.at(-1)?.name
1616
: id.name;
17-
return !!name && isComponentName(name);
17+
return name != null && isComponentName(name);
1818
}

packages/core/src/effect/is.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as AST from "@eslint-react/ast";
2-
import { O } from "@eslint-react/eff";
2+
import { F, O } from "@eslint-react/eff";
33
import type { TSESTree } from "@typescript-eslint/types";
44
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
55

@@ -14,14 +14,14 @@ export function isSetupFunction(node: TSESTree.Node) {
1414
}
1515

1616
export function isCleanupFunction(node: TSESTree.Node) {
17-
const nearestRet = O.getOrNull(AST.findParentNodeGuard(node, AST.is(T.ReturnStatement)));
18-
if (!nearestRet) {
19-
return false;
20-
}
21-
const nearestFunction = O.getOrNull(AST.findParentNodeGuard(node, AST.isFunction));
22-
const nearestFunctionOfRet = O.getOrNull(AST.findParentNodeGuard(nearestRet, AST.isFunction));
23-
if (!nearestFunction || !nearestFunctionOfRet) {
24-
return false;
25-
}
26-
return nearestFunction === nearestFunctionOfRet && isSetupFunction(nearestFunction);
17+
return F.pipe(
18+
O.Do,
19+
O.bind("nearReturn", () => AST.findParentNodeGuard(node, AST.is(T.ReturnStatement))),
20+
O.bind("nearFunction", () => AST.findParentNodeGuard(node, AST.isFunction)),
21+
O.bind("nearFunctionOfReturn", ({ nearReturn }) => AST.findParentNodeGuard(nearReturn, AST.isFunction)),
22+
O.exists(({ nearFunction, nearFunctionOfReturn }) =>
23+
nearFunction === nearFunctionOfReturn
24+
&& isSetupFunction(nearFunction)
25+
),
26+
);
2727
}

packages/core/src/hook/hook-collector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function useHookCollector() {
4949
return;
5050
}
5151
const [fNode, hookId] = fStack.at(-1) ?? [];
52-
if (!fNode || !hookId) {
52+
if (fNode == null || hookId == null) {
5353
return;
5454
}
5555
F.pipe(

packages/core/src/utils/is-react-api.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ import { isCallFromReact, isCallFromReactMember, isFromReact, isFromReactMember
33
export function isReactAPIWithName(name: string): ReturnType<typeof isFromReact>;
44
export function isReactAPIWithName(name: string, member: string): ReturnType<typeof isFromReactMember>;
55
export function isReactAPIWithName(name: string, member?: string) {
6-
return member
7-
? isFromReactMember(name, member)
8-
: isFromReact(name);
6+
return member == null
7+
? isFromReact(name)
8+
: isFromReactMember(name, member);
99
}
1010

1111
export function isReactAPICallWithName(name: string): ReturnType<typeof isCallFromReact>;
1212
export function isReactAPICallWithName(name: string, member: string): ReturnType<typeof isCallFromReactMember>;
1313
export function isReactAPICallWithName(name: string, member?: string) {
14-
return member
15-
? isCallFromReactMember(name, member)
16-
: isCallFromReact(name);
14+
return member == null
15+
? isCallFromReact(name)
16+
: isCallFromReactMember(name, member);
1717
}
1818

1919
export const isChildrenCount = isReactAPIWithName("Children", "count");

packages/plugins/eslint-plugin-react-debug/src/rules/function-component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ export default createRule<[], MessageID>({
4040
node,
4141
data: {
4242
name: O.getOrElse(name, F.constant("anonymous")),
43-
forwardRef: Boolean(flag & ERFunctionComponentFlag.ForwardRef),
43+
forwardRef: (flag & ERFunctionComponentFlag.ForwardRef) > 0n,
4444
hookCalls: hookCalls.length,
45-
memo: Boolean(flag & ERFunctionComponentFlag.Memo),
45+
memo: (flag & ERFunctionComponentFlag.Memo) > 0n,
4646
},
4747
});
4848
}

packages/plugins/eslint-plugin-react-dom/src/rules/no-script-url.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default createRule<[], MessageID>({
3535
create(context) {
3636
return {
3737
JSXAttribute(node) {
38-
if (node.name.type !== T.JSXIdentifier || !node.value) {
38+
if (node.name.type !== T.JSXIdentifier || node.value == null) {
3939
return;
4040
}
4141
const isJavaScript = F.pipe(

0 commit comments

Comments
 (0)