From e40ea576a6d0783cababa714366c00a1f94fb84c Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:06:55 +0000 Subject: [PATCH 01/13] Add failing test for spread --- tests/rules/no-redundant-flow.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/rules/no-redundant-flow.test.ts b/tests/rules/no-redundant-flow.test.ts index 930561d..916efc2 100644 --- a/tests/rules/no-redundant-flow.test.ts +++ b/tests/rules/no-redundant-flow.test.ts @@ -19,6 +19,9 @@ ruleTester.run("no-redundant-flow", rule, { bar ) `, + `import { flow } from "fp-ts/function" + flow(...fns) + `, ], invalid: [ { From c62a297ce32a0e353e5eaa02761899af2ebc149a Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:12:51 +0000 Subject: [PATCH 02/13] Ignore flow call if it contains a spread Fixes https://github.com/buildo/eslint-plugin-fp-ts/issues/223 --- src/rules/no-redundant-flow.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index b99a3af..add6bd0 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -1,5 +1,18 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from "@typescript-eslint/experimental-utils"; +import * as O from "fp-ts/Option"; import { contextUtils, createRule } from "../utils"; +const getArgumentExpression = ( + x: TSESTree.CallExpressionArgument +): O.Option => + // TODO: isExpression? + x.type !== AST_NODE_TYPES.SpreadElement ? O.some(x) : O.none; + +const checkIsArgumentExpression = O.getRefinement(getArgumentExpression); + export default createRule({ name: "no-redundant-flow", meta: { @@ -20,9 +33,20 @@ export default createRule({ create(context) { const { isFlowExpression } = contextUtils(context); + /** + * We ignore flow calls which contain a spread argument because these are never invalid. + */ + const isFlowCallWithExpressionArguments = ( + node: TSESTree.CallExpression + ): boolean => + isFlowExpression(node) && node.arguments.every(checkIsArgumentExpression); + return { CallExpression(node) { - if (node.arguments.length === 1 && isFlowExpression(node)) { + if ( + node.arguments.length === 1 && + isFlowCallWithExpressionArguments(node) + ) { context.report({ node, messageId: "redundantFlow", From c9ff7a0b1e2beb35b087f827127ae9b559a378d7 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:14:56 +0000 Subject: [PATCH 03/13] Preserve filtered call expression data --- src/rules/no-redundant-flow.ts | 65 +++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index add6bd0..44c6b20 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -2,6 +2,8 @@ import { AST_NODE_TYPES, TSESTree, } from "@typescript-eslint/experimental-utils"; +import { pipe } from "fp-ts/function"; +import * as NonEmptyArray from "fp-ts/NonEmptyArray"; import * as O from "fp-ts/Option"; import { contextUtils, createRule } from "../utils"; @@ -33,39 +35,52 @@ export default createRule({ create(context) { const { isFlowExpression } = contextUtils(context); + type FlowCallWithExpressionArgs = { + node: TSESTree.CallExpression; + args: NonEmptyArray.NonEmptyArray; + }; + /** * We ignore flow calls which contain a spread argument because these are never invalid. */ - const isFlowCallWithExpressionArguments = ( + const getFlowCallWithExpressionArguments = ( node: TSESTree.CallExpression - ): boolean => - isFlowExpression(node) && node.arguments.every(checkIsArgumentExpression); + ): O.Option => + isFlowExpression(node) && node.arguments.every(checkIsArgumentExpression) + ? pipe( + node.arguments, + NonEmptyArray.fromArray, + O.map((args): FlowCallWithExpressionArgs => ({ node, args })) + ) + : O.none; return { CallExpression(node) { - if ( - node.arguments.length === 1 && - isFlowCallWithExpressionArguments(node) - ) { - context.report({ - node, - messageId: "redundantFlow", - suggest: [ - { - messageId: "removeFlow", - fix(fixer) { - return [ - fixer.removeRange([ - node.callee.range[0], - node.callee.range[1] + 1, - ]), - fixer.removeRange([node.range[1] - 1, node.range[1]]), - ]; + pipe( + node, + O.fromPredicate((node) => node.arguments.length === 1), + O.chain(getFlowCallWithExpressionArguments), + O.map((redundantFlowCall) => { + context.report({ + node: redundantFlowCall.node, + messageId: "redundantFlow", + suggest: [ + { + messageId: "removeFlow", + fix(fixer) { + return [ + fixer.removeRange([ + node.callee.range[0], + node.callee.range[1] + 1, + ]), + fixer.removeRange([node.range[1] - 1, node.range[1]]), + ]; + }, }, - }, - ], - }); - } + ], + }); + }) + ); }, }; }, From b9af3c614cecd6d4fbbffd3c3cb23d07c773f509 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:15:51 +0000 Subject: [PATCH 04/13] Reverse condition order --- src/rules/no-redundant-flow.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index 44c6b20..e013bbb 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -58,8 +58,8 @@ export default createRule({ CallExpression(node) { pipe( node, - O.fromPredicate((node) => node.arguments.length === 1), - O.chain(getFlowCallWithExpressionArguments), + getFlowCallWithExpressionArguments, + O.filter((flowCall) => flowCall.node.arguments.length === 1), O.map((redundantFlowCall) => { context.report({ node: redundantFlowCall.node, From 06168f29ceaa84fa101183bd9686d5de07a93236 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 09:53:17 +0000 Subject: [PATCH 05/13] Add failing test trailing comma --- tests/rules/no-redundant-flow.test.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/rules/no-redundant-flow.test.ts b/tests/rules/no-redundant-flow.test.ts index 916efc2..b0a4777 100644 --- a/tests/rules/no-redundant-flow.test.ts +++ b/tests/rules/no-redundant-flow.test.ts @@ -68,5 +68,29 @@ const a = ${""} }, ], }, + { + code: ` +import { flow } from "fp-ts/function" +const a = flow( + foo, +); +`, + errors: [ + { + messageId: "redundantFlow", + suggestions: [ + { + messageId: "removeFlow", + output: ` +import { flow } from "fp-ts/function" +const a = + foo +; +`, + }, + ], + }, + ], + } ], }); From b76044afa46f006869624450daacc46bf2034ed5 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:13:33 +0000 Subject: [PATCH 06/13] Code for fix is generated by AST node rather than text manipulation Fixes https://github.com/buildo/eslint-plugin-fp-ts/issues/222 --- src/rules/no-redundant-flow.ts | 26 ++++++++++++++++++++------ tests/rules/no-redundant-flow.test.ts | 8 ++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index e013bbb..7054527 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -5,7 +5,7 @@ import { import { pipe } from "fp-ts/function"; import * as NonEmptyArray from "fp-ts/NonEmptyArray"; import * as O from "fp-ts/Option"; -import { contextUtils, createRule } from "../utils"; +import { contextUtils, createRule, prettyPrint } from "../utils"; const getArgumentExpression = ( x: TSESTree.CallExpressionArgument @@ -54,6 +54,19 @@ export default createRule({ ) : O.none; + const createSequenceExpressionFromFlowCall = ( + flowCall: FlowCallWithExpressionArgs + ): TSESTree.SequenceExpression => { + const firstArg = pipe(flowCall.args, NonEmptyArray.head); + const lastArg = pipe(flowCall.args, NonEmptyArray.last); + return { + loc: flowCall.node.loc, + range: [firstArg.range[0], lastArg.range[1]], + type: AST_NODE_TYPES.SequenceExpression, + expressions: flowCall.args, + }; + }; + return { CallExpression(node) { pipe( @@ -68,12 +81,13 @@ export default createRule({ { messageId: "removeFlow", fix(fixer) { + const sequenceExpression = + createSequenceExpressionFromFlowCall(redundantFlowCall); return [ - fixer.removeRange([ - node.callee.range[0], - node.callee.range[1] + 1, - ]), - fixer.removeRange([node.range[1] - 1, node.range[1]]), + fixer.replaceText( + redundantFlowCall.node, + prettyPrint(sequenceExpression) + ), ]; }, }, diff --git a/tests/rules/no-redundant-flow.test.ts b/tests/rules/no-redundant-flow.test.ts index b0a4777..2618be3 100644 --- a/tests/rules/no-redundant-flow.test.ts +++ b/tests/rules/no-redundant-flow.test.ts @@ -59,9 +59,7 @@ const a = flow( messageId: "removeFlow", output: ` import { flow } from "fp-ts/function" -const a = ${""} - foo - +const a = foo `, }, ], @@ -83,9 +81,7 @@ const a = flow( messageId: "removeFlow", output: ` import { flow } from "fp-ts/function" -const a = - foo -; +const a = foo; `, }, ], From 846369b91de9c133cd2be88a4ff64de94d492dbd Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:23:51 +0000 Subject: [PATCH 07/13] Make function more generic --- src/rules/no-redundant-flow.ts | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index 7054527..41b790a 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -35,35 +35,32 @@ export default createRule({ create(context) { const { isFlowExpression } = contextUtils(context); - type FlowCallWithExpressionArgs = { + type CallWithExpressionArgs = { node: TSESTree.CallExpression; args: NonEmptyArray.NonEmptyArray; }; - /** - * We ignore flow calls which contain a spread argument because these are never invalid. - */ - const getFlowCallWithExpressionArguments = ( + const getCallWithExpressionArguments = ( node: TSESTree.CallExpression - ): O.Option => - isFlowExpression(node) && node.arguments.every(checkIsArgumentExpression) + ): O.Option => + node.arguments.every(checkIsArgumentExpression) ? pipe( node.arguments, NonEmptyArray.fromArray, - O.map((args): FlowCallWithExpressionArgs => ({ node, args })) + O.map((args): CallWithExpressionArgs => ({ node, args })) ) : O.none; - const createSequenceExpressionFromFlowCall = ( - flowCall: FlowCallWithExpressionArgs + const createSequenceExpressionFromCall = ( + call: CallWithExpressionArgs ): TSESTree.SequenceExpression => { - const firstArg = pipe(flowCall.args, NonEmptyArray.head); - const lastArg = pipe(flowCall.args, NonEmptyArray.last); + const firstArg = pipe(call.args, NonEmptyArray.head); + const lastArg = pipe(call.args, NonEmptyArray.last); return { - loc: flowCall.node.loc, + loc: call.node.loc, range: [firstArg.range[0], lastArg.range[1]], type: AST_NODE_TYPES.SequenceExpression, - expressions: flowCall.args, + expressions: call.args, }; }; @@ -71,7 +68,11 @@ export default createRule({ CallExpression(node) { pipe( node, - getFlowCallWithExpressionArguments, + O.fromPredicate(isFlowExpression), + /** + * We ignore flow calls which contain a spread argument because these are never invalid. + */ + O.chain(getCallWithExpressionArguments), O.filter((flowCall) => flowCall.node.arguments.length === 1), O.map((redundantFlowCall) => { context.report({ @@ -82,7 +83,7 @@ export default createRule({ messageId: "removeFlow", fix(fixer) { const sequenceExpression = - createSequenceExpressionFromFlowCall(redundantFlowCall); + createSequenceExpressionFromCall(redundantFlowCall); return [ fixer.replaceText( redundantFlowCall.node, From ee405c769eafcf6b77399dd7a74c29941fa79d21 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:25:41 +0000 Subject: [PATCH 08/13] Rename --- src/rules/no-redundant-flow.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index 41b790a..71f1a4a 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -35,24 +35,24 @@ export default createRule({ create(context) { const { isFlowExpression } = contextUtils(context); - type CallWithExpressionArgs = { + type CallExpressionWithExpressionArgs = { node: TSESTree.CallExpression; args: NonEmptyArray.NonEmptyArray; }; - const getCallWithExpressionArguments = ( + const getCallExpressionWithExpressionArgs = ( node: TSESTree.CallExpression - ): O.Option => + ): O.Option => node.arguments.every(checkIsArgumentExpression) ? pipe( node.arguments, NonEmptyArray.fromArray, - O.map((args): CallWithExpressionArgs => ({ node, args })) + O.map((args): CallExpressionWithExpressionArgs => ({ node, args })) ) : O.none; const createSequenceExpressionFromCall = ( - call: CallWithExpressionArgs + call: CallExpressionWithExpressionArgs ): TSESTree.SequenceExpression => { const firstArg = pipe(call.args, NonEmptyArray.head); const lastArg = pipe(call.args, NonEmptyArray.last); @@ -72,7 +72,7 @@ export default createRule({ /** * We ignore flow calls which contain a spread argument because these are never invalid. */ - O.chain(getCallWithExpressionArguments), + O.chain(getCallExpressionWithExpressionArgs), O.filter((flowCall) => flowCall.node.arguments.length === 1), O.map((redundantFlowCall) => { context.report({ From 99db88e9b4ea025f3aa403abc7188f4536f60931 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:26:00 +0000 Subject: [PATCH 09/13] Rename --- src/rules/no-redundant-flow.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index 71f1a4a..a264067 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -51,7 +51,7 @@ export default createRule({ ) : O.none; - const createSequenceExpressionFromCall = ( + const createSequenceExpressionFromCallExpressionWithExpressionArgs = ( call: CallExpressionWithExpressionArgs ): TSESTree.SequenceExpression => { const firstArg = pipe(call.args, NonEmptyArray.head); @@ -83,7 +83,9 @@ export default createRule({ messageId: "removeFlow", fix(fixer) { const sequenceExpression = - createSequenceExpressionFromCall(redundantFlowCall); + createSequenceExpressionFromCallExpressionWithExpressionArgs( + redundantFlowCall + ); return [ fixer.replaceText( redundantFlowCall.node, From 057583eeeb4bd6a3f9f97708ab3260bc152889c5 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:26:59 +0000 Subject: [PATCH 10/13] Format --- src/rules/no-redundant-flow.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index a264067..8f9416f 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -47,7 +47,12 @@ export default createRule({ ? pipe( node.arguments, NonEmptyArray.fromArray, - O.map((args): CallExpressionWithExpressionArgs => ({ node, args })) + O.map( + (args): CallExpressionWithExpressionArgs => ({ + node, + args, + }) + ) ) : O.none; From 98b34e89da914fb0218fefa5f6d4bad1a4a5f101 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:27:19 +0000 Subject: [PATCH 11/13] Hoist --- src/rules/no-redundant-flow.ts | 68 +++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index 8f9416f..c2bc88b 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -15,6 +15,40 @@ const getArgumentExpression = ( const checkIsArgumentExpression = O.getRefinement(getArgumentExpression); +type CallExpressionWithExpressionArgs = { + node: TSESTree.CallExpression; + args: NonEmptyArray.NonEmptyArray; +}; + +const getCallExpressionWithExpressionArgs = ( + node: TSESTree.CallExpression +): O.Option => + node.arguments.every(checkIsArgumentExpression) + ? pipe( + node.arguments, + NonEmptyArray.fromArray, + O.map( + (args): CallExpressionWithExpressionArgs => ({ + node, + args, + }) + ) + ) + : O.none; + +const createSequenceExpressionFromCallExpressionWithExpressionArgs = ( + call: CallExpressionWithExpressionArgs +): TSESTree.SequenceExpression => { + const firstArg = pipe(call.args, NonEmptyArray.head); + const lastArg = pipe(call.args, NonEmptyArray.last); + return { + loc: call.node.loc, + range: [firstArg.range[0], lastArg.range[1]], + type: AST_NODE_TYPES.SequenceExpression, + expressions: call.args, + }; +}; + export default createRule({ name: "no-redundant-flow", meta: { @@ -35,40 +69,6 @@ export default createRule({ create(context) { const { isFlowExpression } = contextUtils(context); - type CallExpressionWithExpressionArgs = { - node: TSESTree.CallExpression; - args: NonEmptyArray.NonEmptyArray; - }; - - const getCallExpressionWithExpressionArgs = ( - node: TSESTree.CallExpression - ): O.Option => - node.arguments.every(checkIsArgumentExpression) - ? pipe( - node.arguments, - NonEmptyArray.fromArray, - O.map( - (args): CallExpressionWithExpressionArgs => ({ - node, - args, - }) - ) - ) - : O.none; - - const createSequenceExpressionFromCallExpressionWithExpressionArgs = ( - call: CallExpressionWithExpressionArgs - ): TSESTree.SequenceExpression => { - const firstArg = pipe(call.args, NonEmptyArray.head); - const lastArg = pipe(call.args, NonEmptyArray.last); - return { - loc: call.node.loc, - range: [firstArg.range[0], lastArg.range[1]], - type: AST_NODE_TYPES.SequenceExpression, - expressions: call.args, - }; - }; - return { CallExpression(node) { pipe( From 87733cd709e394bf38517eac265a219e6cc5edd8 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Sat, 11 Dec 2021 10:35:59 +0000 Subject: [PATCH 12/13] Move to utils --- src/rules/no-redundant-flow.ts | 55 +++++----------------------------- src/utils.ts | 44 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/rules/no-redundant-flow.ts b/src/rules/no-redundant-flow.ts index c2bc88b..f548134 100644 --- a/src/rules/no-redundant-flow.ts +++ b/src/rules/no-redundant-flow.ts @@ -1,53 +1,12 @@ -import { - AST_NODE_TYPES, - TSESTree, -} from "@typescript-eslint/experimental-utils"; import { pipe } from "fp-ts/function"; -import * as NonEmptyArray from "fp-ts/NonEmptyArray"; import * as O from "fp-ts/Option"; -import { contextUtils, createRule, prettyPrint } from "../utils"; - -const getArgumentExpression = ( - x: TSESTree.CallExpressionArgument -): O.Option => - // TODO: isExpression? - x.type !== AST_NODE_TYPES.SpreadElement ? O.some(x) : O.none; - -const checkIsArgumentExpression = O.getRefinement(getArgumentExpression); - -type CallExpressionWithExpressionArgs = { - node: TSESTree.CallExpression; - args: NonEmptyArray.NonEmptyArray; -}; - -const getCallExpressionWithExpressionArgs = ( - node: TSESTree.CallExpression -): O.Option => - node.arguments.every(checkIsArgumentExpression) - ? pipe( - node.arguments, - NonEmptyArray.fromArray, - O.map( - (args): CallExpressionWithExpressionArgs => ({ - node, - args, - }) - ) - ) - : O.none; - -const createSequenceExpressionFromCallExpressionWithExpressionArgs = ( - call: CallExpressionWithExpressionArgs -): TSESTree.SequenceExpression => { - const firstArg = pipe(call.args, NonEmptyArray.head); - const lastArg = pipe(call.args, NonEmptyArray.last); - return { - loc: call.node.loc, - range: [firstArg.range[0], lastArg.range[1]], - type: AST_NODE_TYPES.SequenceExpression, - expressions: call.args, - }; -}; +import { + contextUtils, + createRule, + createSequenceExpressionFromCallExpressionWithExpressionArgs, + getCallExpressionWithExpressionArgs, + prettyPrint, +} from "../utils"; export default createRule({ name: "no-redundant-flow", diff --git a/src/utils.ts b/src/utils.ts index e949ca0..c8a1aa7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,6 +18,8 @@ import { } from "@typescript-eslint/experimental-utils/dist/ts-eslint"; import ts from "typescript"; import { Option } from "fp-ts/Option"; +import * as NonEmptyArray from "fp-ts/NonEmptyArray"; +import * as O from "fp-ts/Option"; declare module "typescript" { interface TypeChecker { @@ -471,3 +473,45 @@ export const contextUtils = < parserServices, }; }; + +const getArgumentExpression = ( + x: TSESTree.CallExpressionArgument +): O.Option => + // TODO: isExpression? + x.type !== AST_NODE_TYPES.SpreadElement ? O.some(x) : O.none; + +const checkIsArgumentExpression = O.getRefinement(getArgumentExpression); + +type CallExpressionWithExpressionArgs = { + node: TSESTree.CallExpression; + args: NonEmptyArray.NonEmptyArray; +}; + +export const getCallExpressionWithExpressionArgs = ( + node: TSESTree.CallExpression +): O.Option => + node.arguments.every(checkIsArgumentExpression) + ? pipe( + node.arguments, + NonEmptyArray.fromArray, + O.map( + (args): CallExpressionWithExpressionArgs => ({ + node, + args, + }) + ) + ) + : O.none; + +export const createSequenceExpressionFromCallExpressionWithExpressionArgs = ( + call: CallExpressionWithExpressionArgs +): TSESTree.SequenceExpression => { + const firstArg = pipe(call.args, NonEmptyArray.head); + const lastArg = pipe(call.args, NonEmptyArray.last); + return { + loc: call.node.loc, + range: [firstArg.range[0], lastArg.range[1]], + type: AST_NODE_TYPES.SequenceExpression, + expressions: call.args, + }; +}; From 66cbbfcb8fc646310db9594625f0c6258cf23ee1 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Mon, 13 Dec 2021 18:09:04 +0000 Subject: [PATCH 13/13] Document --- src/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index c8a1aa7..ad821a2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -474,10 +474,16 @@ export const contextUtils = < }; }; +/** + * Ideally we could implement this predicate in terms of an existing + * `isExpression` predicate but it seems like this doesn't exist anywhere. + * + * There is an `isExpression` in `tsutils`. However, in the TS AST, spread is + * classed as an expression (!). + */ const getArgumentExpression = ( x: TSESTree.CallExpressionArgument ): O.Option => - // TODO: isExpression? x.type !== AST_NODE_TYPES.SpreadElement ? O.some(x) : O.none; const checkIsArgumentExpression = O.getRefinement(getArgumentExpression);