Skip to content

Commit 6da2cd6

Browse files
authored
refactor: remove 'MutRef' and 'Ref' utils functions (#890)
1 parent ec7d45f commit 6da2cd6

Some content is hidden

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

51 files changed

+60
-6054
lines changed

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-effect.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable better-mutation/no-mutating-methods */
22
import * as AST from "@eslint-react/ast";
33
import { isReactHookCallWithNameAlias } from "@eslint-react/core";
4-
import { F, MutRef, O } from "@eslint-react/eff";
4+
import { F, O } from "@eslint-react/eff";
55
import { decodeSettings } from "@eslint-react/shared";
66
import type { RuleFeature } from "@eslint-react/types";
77
import * as VAR from "@eslint-react/var";
@@ -53,7 +53,7 @@ export default createRule<[], MessageID>({
5353
const isSetStateCall = isSetFunctionCall(context, settings);
5454
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
5555
const functionStack: [node: AST.TSESTreeFunction, kind: FunctionKind][] = [];
56-
const setupFunctionRef = MutRef.make<AST.TSESTreeFunction | null>(null);
56+
const setupFunctionRef = { current: O.none<AST.TSESTreeFunction>() };
5757
const setupFunctionIdentifiers: TSESTree.Identifier[] = [];
5858
const indirectFunctionCalls: TSESTree.CallExpression[] = [];
5959
const indirectSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
@@ -64,10 +64,12 @@ export default createRule<[], MessageID>({
6464
TSESTree.CallExpression[]
6565
>();
6666
const onSetupFunctionEnter = (node: AST.TSESTreeFunction) => {
67-
MutRef.set(setupFunctionRef, node);
67+
// eslint-disable-next-line better-mutation/no-mutation
68+
setupFunctionRef.current = O.some(node);
6869
};
6970
const onSetupFunctionExit = (node: AST.TSESTreeFunction) => {
70-
MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
71+
// eslint-disable-next-line better-mutation/no-mutation
72+
setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
7173
};
7274
function isSetupFunction(node: TSESTree.Node) {
7375
return node.parent?.type === AST_NODE_TYPES.CallExpression
@@ -100,7 +102,7 @@ export default createRule<[], MessageID>({
100102
if (functionKind === "setup") onSetupFunctionExit(node);
101103
},
102104
CallExpression(node) {
103-
const effectFn = MutRef.get(setupFunctionRef);
105+
const effectFn = O.getOrNull(setupFunctionRef.current);
104106
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
105107
if (parentFn?.async) return;
106108
match(getCallKind(node))

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-layout-effect.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
/* eslint-disable better-mutation/no-mutating-methods */
23
import * as AST from "@eslint-react/ast";
34
import { isReactHookCallWithNameAlias } from "@eslint-react/core";
4-
import { F, MutRef, O } from "@eslint-react/eff";
5+
import { F, O } from "@eslint-react/eff";
56
import { decodeSettings } from "@eslint-react/shared";
67
import type { RuleFeature } from "@eslint-react/types";
78
import * as VAR from "@eslint-react/var";
@@ -58,7 +59,7 @@ export default createRule<[], MessageID>({
5859
const isSetStateCall = isSetFunctionCall(context, settings);
5960
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
6061
const functionStack: [node: AST.TSESTreeFunction, kind: FunctionKind][] = [];
61-
const setupFunctionRef = MutRef.make<AST.TSESTreeFunction | null>(null);
62+
const setupFunctionRef = { current: O.none<AST.TSESTreeFunction>() };
6263
const setupFunctionIdentifiers: TSESTree.Identifier[] = [];
6364
const indirectFunctionCalls: TSESTree.CallExpression[] = [];
6465
const indirectSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
@@ -69,10 +70,10 @@ export default createRule<[], MessageID>({
6970
TSESTree.CallExpression[]
7071
>();
7172
const onSetupFunctionEnter = (node: AST.TSESTreeFunction) => {
72-
MutRef.set(setupFunctionRef, node);
73+
setupFunctionRef.current = O.some(node);
7374
};
7475
const onSetupFunctionExit = (node: AST.TSESTreeFunction) => {
75-
MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
76+
setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
7677
};
7778
function isSetupFunction(node: TSESTree.Node) {
7879
return node.parent?.type === AST_NODE_TYPES.CallExpression
@@ -105,7 +106,7 @@ export default createRule<[], MessageID>({
105106
if (functionKind === "setup") onSetupFunctionExit(node);
106107
},
107108
CallExpression(node) {
108-
const effectFn = MutRef.get(setupFunctionRef);
109+
const effectFn = O.getOrNull(setupFunctionRef.current);
109110
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
110111
if (parentFn?.async) return;
111112
match(getCallKind(node))

packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { isObject, MutRef } from "@eslint-react/eff";
1+
/* eslint-disable better-mutation/no-mutation */
2+
import { isObject } from "@eslint-react/eff";
23
import type { RuleFeature } from "@eslint-react/types";
34
import type { JSONSchema4 } from "@typescript-eslint/utils/json-schema";
45

@@ -86,23 +87,21 @@ export default createRule<Options, MessageID>({
8687
const extensions = isObject(options) && "extensions" in options
8788
? options.extensions
8889
: defaultOptions[0].extensions;
89-
9090
const filename = context.filename;
91-
const hasJSXNodeRef = MutRef.make<boolean>(false);
91+
92+
let hasJSXNode = false;
9293

9394
return {
9495
JSXElement() {
95-
MutRef.set(hasJSXNodeRef, true);
96+
hasJSXNode = true;
9697
},
9798
JSXFragment() {
98-
MutRef.set(hasJSXNodeRef, true);
99+
hasJSXNode = true;
99100
},
100101
"Program:exit"(node) {
101102
const fileNameExt = filename.slice(filename.lastIndexOf("."));
102103
const isJSXExt = extensions.includes(fileNameExt);
103-
const hasJSXCode = MutRef.get(hasJSXNodeRef);
104-
105-
if (hasJSXCode && !isJSXExt) {
104+
if (hasJSXNode && !isJSXExt) {
106105
context.report({
107106
messageId: "filenameExtensionInvalid",
108107
node,
@@ -114,7 +113,7 @@ export default createRule<Options, MessageID>({
114113
const ignoreFilesWithoutCode = isObject(options) && options.ignoreFilesWithoutCode;
115114
if (!hasCode && ignoreFilesWithoutCode) return;
116115
if (
117-
!hasJSXCode
116+
!hasJSXNode
118117
&& isJSXExt
119118
&& allow === "as-needed"
120119
) {

packages/plugins/eslint-plugin-react-x/src/rules/no-duplicate-key.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
import * as AST from "@eslint-react/ast";
23
import { isChildrenToArrayCall } from "@eslint-react/core";
3-
import { F, MutRef, O } from "@eslint-react/eff";
4+
import { F, O } from "@eslint-react/eff";
45
import * as JSX from "@eslint-react/jsx";
56
import type { RuleFeature } from "@eslint-react/types";
67
import * as VAR from "@eslint-react/var";
@@ -35,7 +36,7 @@ export default createRule<[], MessageID>({
3536
},
3637
name: RULE_NAME,
3738
create(context) {
38-
const isWithinChildrenToArrayRef = MutRef.make(false);
39+
const state = { isWithinChildrenToArray: false };
3940
function isKeyEqual(a: TSESTree.Node, b: TSESTree.Node) {
4041
return VAR.isNodeValueEqual(a, b, [context.sourceCode.getScope(a), context.sourceCode.getScope(b)]);
4142
}
@@ -97,7 +98,7 @@ export default createRule<[], MessageID>({
9798

9899
return {
99100
"ArrayExpression, JSXElement > JSXElement"(node: TSESTree.ArrayExpression | TSESTree.JSXElement) {
100-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
101+
if (state.isWithinChildrenToArray) return;
101102
const elements = match(node)
102103
.with({ type: AST_NODE_TYPES.ArrayExpression }, ({ elements }) => elements)
103104
.with({ type: AST_NODE_TYPES.JSXElement }, ({ parent }) => "children" in parent ? parent.children : [])
@@ -138,7 +139,8 @@ export default createRule<[], MessageID>({
138139
}
139140
},
140141
CallExpression(node) {
141-
if (isChildrenToArrayCall(node, context)) MutRef.set(isWithinChildrenToArrayRef, true);
142+
state.isWithinChildrenToArray ||= isChildrenToArrayCall(node, context);
143+
if (state.isWithinChildrenToArray) return;
142144
const isMapCall = AST.isMapCallLoose(node);
143145
const isArrayFromCall = isMatching({
144146
type: AST_NODE_TYPES.CallExpression,
@@ -150,7 +152,6 @@ export default createRule<[], MessageID>({
150152
},
151153
}, node);
152154
if (!isMapCall && !isArrayFromCall) return;
153-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
154155
const fn = node.arguments[isMapCall ? 0 : 1];
155156
if (!AST.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(fn)) return;
156157
if (fn.body.type === AST_NODE_TYPES.BlockStatement) {
@@ -162,7 +163,8 @@ export default createRule<[], MessageID>({
162163
O.map(checkExpression(fn.body), context.report);
163164
},
164165
"CallExpression:exit"(node) {
165-
if (isChildrenToArrayCall(node, context)) MutRef.set(isWithinChildrenToArrayRef, false);
166+
if (!isChildrenToArrayCall(node, context)) return;
167+
state.isWithinChildrenToArray = false;
166168
},
167169
};
168170
},

packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
import * as AST from "@eslint-react/ast";
23
import { isChildrenToArrayCall } from "@eslint-react/core";
3-
import { MutRef, O } from "@eslint-react/eff";
4+
import { O } from "@eslint-react/eff";
45
import * as JSX from "@eslint-react/jsx";
56
import type { RuleFeature } from "@eslint-react/types";
67
import type { TSESTree } from "@typescript-eslint/types";
@@ -35,7 +36,7 @@ export default createRule<[], MessageID>({
3536
},
3637
name: RULE_NAME,
3738
create(context) {
38-
const isWithinChildrenToArrayRef = MutRef.make(false);
39+
const state = { isWithinChildrenToArray: false };
3940
function checkIteratorElement(node: TSESTree.Node): O.Option<ReportDescriptor<MessageID>> {
4041
switch (node.type) {
4142
case AST_NODE_TYPES.JSXElement: {
@@ -89,7 +90,7 @@ export default createRule<[], MessageID>({
8990

9091
return {
9192
ArrayExpression(node) {
92-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
93+
if (state.isWithinChildrenToArray) return;
9394
const elements = node.elements.filter(AST.is(AST_NODE_TYPES.JSXElement));
9495
if (elements.length === 0) return;
9596
const initialScope = context.sourceCode.getScope(node);
@@ -103,7 +104,8 @@ export default createRule<[], MessageID>({
103104
}
104105
},
105106
CallExpression(node) {
106-
if (isChildrenToArrayCall(node, context)) MutRef.set(isWithinChildrenToArrayRef, true);
107+
state.isWithinChildrenToArray ||= isChildrenToArrayCall(node, context);
108+
if (state.isWithinChildrenToArray) return;
107109
const isMapCall = AST.isMapCallLoose(node);
108110
const isArrayFromCall = isMatching({
109111
type: AST_NODE_TYPES.CallExpression,
@@ -115,7 +117,6 @@ export default createRule<[], MessageID>({
115117
},
116118
}, node);
117119
if (!isMapCall && !isArrayFromCall) return;
118-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
119120
const fn = node.arguments[isMapCall ? 0 : 1];
120121
if (!AST.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(fn)) return;
121122
if (fn.body.type === AST_NODE_TYPES.BlockStatement) {
@@ -127,10 +128,11 @@ export default createRule<[], MessageID>({
127128
O.map(checkExpression(fn.body), context.report);
128129
},
129130
"CallExpression:exit"(node) {
130-
if (isChildrenToArrayCall(node, context)) MutRef.set(isWithinChildrenToArrayRef, false);
131+
if (!isChildrenToArrayCall(node, context)) return;
132+
state.isWithinChildrenToArray = false;
131133
},
132134
JSXFragment(node) {
133-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
135+
if (state.isWithinChildrenToArray) return;
134136
if (node.parent.type === AST_NODE_TYPES.ArrayExpression) {
135137
context.report({
136138
messageId: "noMissingKeyWithFragment",

packages/utilities/ast/src/get-class-identifier.spec.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
import path from "node:path";
23

3-
import { MutRef, O } from "@eslint-react/eff";
4+
import { O } from "@eslint-react/eff";
45
import { parseForESLint } from "@typescript-eslint/parser";
56
import { AST_NODE_TYPES } from "@typescript-eslint/types";
67
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
@@ -24,16 +25,16 @@ describe("get class identifier from class declaration", () => {
2425
["class Foo<T> {}", "Foo"],
2526
["class Foo<T extends Bar> {}", "Foo"],
2627
])("should return the class name from %s", (code, expected) => {
27-
const n = MutRef.make<null | TSESTreeClass>(null);
28+
let n = O.none<TSESTreeClass>();
2829
simpleTraverse(parse(code).ast, {
2930
enter(node) {
3031
if (node.type !== AST_NODE_TYPES.ClassDeclaration) return;
3132
const id = O.getOrThrow(getClassIdentifier(node));
3233
expect(id).include({ type: AST_NODE_TYPES.Identifier, name: expected });
33-
MutRef.set(n, node);
34+
n = O.fromNullable(node);
3435
},
3536
}, true);
36-
expect(MutRef.get(n)).not.toBeNull();
37+
expect(O.isSome(n)).toBe(true);
3738
});
3839
});
3940

@@ -44,15 +45,15 @@ describe("get class identifier from class expression", () => {
4445
["const Foo = class<T> {};", "Foo"],
4546
["const Foo = class<T extends Bar> {};", "Foo"],
4647
])("should return the class name from %s", (code, expected) => {
47-
const n = MutRef.make<null | TSESTreeClass>(null);
48+
let n = O.none<TSESTreeClass>();
4849
simpleTraverse(parse(code).ast, {
4950
enter(node) {
5051
if (node.type !== AST_NODE_TYPES.ClassExpression) return;
5152
const id = O.getOrThrow(getClassIdentifier(node));
5253
expect(id).include({ type: AST_NODE_TYPES.Identifier, name: expected });
53-
MutRef.set(n, node);
54+
n = O.fromNullable(node);
5455
},
5556
}, true);
56-
expect(MutRef.get(n)).not.toBeNull();
57+
expect(O.isSome(n)).toBe(true);
5758
});
5859
});

packages/utilities/ast/src/get-function-identifier.spec.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
import path from "node:path";
23

3-
import { MutRef, O } from "@eslint-react/eff";
4+
import { O } from "@eslint-react/eff";
45
import { parseForESLint } from "@typescript-eslint/parser";
56
import { AST_NODE_TYPES } from "@typescript-eslint/types";
67
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
@@ -24,16 +25,16 @@ describe("get function identifier from function declaration", () => {
2425
["function bar() {}", "bar"],
2526
["function baz<T>() {}", "baz"],
2627
])("should return the function name from %s", (code, expected) => {
27-
const n = MutRef.make<null | TSESTreeFunction>(null);
28+
let n = O.none<TSESTreeFunction>();
2829
simpleTraverse(parse(code).ast, {
2930
enter(node) {
3031
if (!isFunction(node)) return;
3132
const id = O.getOrThrow(getFunctionIdentifier(node));
3233
expect(id).include({ type: AST_NODE_TYPES.Identifier, name: expected });
33-
MutRef.set(n, node);
34+
n = O.fromNullable(node);
3435
},
3536
}, true);
36-
expect(MutRef.get(n)).not.toBeNull();
37+
expect(O.isSome(n)).toBe(true);
3738
});
3839
});
3940

@@ -53,15 +54,15 @@ describe("get function identifier from function expression", () => {
5354
["class Clazz { Foo = function() {} }", "Foo"],
5455
["class Clazz { Foo = () => {} }", "Foo"],
5556
])("should return the function name from %s", (code, expected) => {
56-
const n = MutRef.make<null | TSESTreeFunction>(null);
57+
let n = O.none<TSESTreeFunction>();
5758
simpleTraverse(parse(code).ast, {
5859
enter(node) {
5960
if (!isFunction(node)) return;
6061
const id = O.getOrThrow(getFunctionIdentifier(node));
6162
expect(id).include({ type: AST_NODE_TYPES.Identifier, name: expected });
62-
MutRef.set(n, node);
63+
n = O.fromNullable(node);
6364
},
6465
}, true);
65-
expect(MutRef.get(n)).not.toBeNull();
66+
expect(O.isSome(n)).toBe(true);
6667
});
6768
});

packages/utilities/ast/src/get-nested-return-statements.spec.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
/* eslint-disable better-mutation/no-mutation */
12
import path from "node:path";
23

3-
import { MutRef } from "@eslint-react/eff";
4+
import { O } from "@eslint-react/eff";
45
import { parseForESLint } from "@typescript-eslint/parser";
56
import { AST_NODE_TYPES } from "@typescript-eslint/types";
67
import { simpleTraverse } from "@typescript-eslint/typescript-estree";
@@ -91,19 +92,19 @@ describe("get nested return statements from function", () => {
9192
],
9293
],
9394
])("should return the nested return statements from %s", (code, expected) => {
94-
const n = MutRef.make<null | TSESTreeFunction>(null);
95+
let n = O.none<TSESTreeFunction>();
9596
const { ast } = parse(code);
9697
simpleTraverse(ast, {
9798
enter(node) {
99+
if (O.isSome(n)) return;
98100
if (!isFunction(node)) return;
99-
if (MutRef.get(n)) return;
100101
const returnStatements = getNestedReturnStatements(node);
101102
for (const [index, statement] of returnStatements.entries()) {
102103
expect(statement).include(expected[index]);
103104
}
104-
MutRef.set(n, node);
105+
n = O.fromNullable(node);
105106
},
106107
}, true);
107-
expect(MutRef.get(n)).not.toBeNull();
108+
expect(O.isSome(n)).toBe(true);
108109
});
109110
});

packages/utilities/eff/docs/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
- [Data](namespaces/Data/README.md)
1212
- [Equal](namespaces/Equal/README.md)
1313
- [F](namespaces/F/README.md)
14-
- [MutRef](namespaces/MutRef/README.md)
15-
- [Ref](namespaces/Ref/README.md)
1614
- [compose](functions/compose.md)
1715
- [struct](functions/struct.md)
1816
- [tuple](functions/tuple.md)

0 commit comments

Comments
 (0)