Skip to content

Commit b74044b

Browse files
authored
feat(getCallExpressionIdentifier): add resolveCallExpression option (#194)
1 parent 5787de9 commit b74044b

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

workspaces/estree-ast-utils/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ One of the options of the method is `stopOnUnsupportedNode`, if true it will thr
5858

5959
</details>
6060

61-
<details><summary>getCallExpressionIdentifier(node): string | null</summary>
61+
<details><summary>getCallExpressionIdentifier(node, options): string | null</summary>
6262

6363
Return the identifier name of the CallExpression (or null if there is none).
6464

@@ -68,6 +68,17 @@ foobar();
6868

6969
will return `"foobar"`.
7070

71+
One of the options of the method is `resolveCallExpression` (which is true by default).
72+
73+
Sometimes you don't want to resolve/jump early CallExpression like in the following example:
74+
```js
75+
require('./file.js')();
76+
// ^ Second ^ First
77+
```
78+
79+
With **resolveCallExpression** equal to **false** the function return `null`.
80+
81+
7182
</details>
7283

7384
<details><summary>getMemberExpressionIdentifier(node): IterableIterator< string ></summary>
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
// Import Internal Dependencies
22
import { getMemberExpressionIdentifier } from "./getMemberExpressionIdentifier.js";
3+
import { VariableTracer } from "./utils/VariableTracer.js";
34

45
/**
56
* @param {any} node
7+
* @param {object} options
8+
* @param {VariableTracer} [options.tracer=null]
9+
* @param {boolean} [options.resolveCallExpression=true]
610
* @returns {string | null}
711
*/
8-
export function getCallExpressionIdentifier(node) {
12+
export function getCallExpressionIdentifier(node, options = {}) {
913
if (node.type !== "CallExpression") {
1014
return null;
1115
}
16+
const { tracer = null, resolveCallExpression = true } = options;
1217

1318
if (node.callee.type === "Identifier") {
1419
return node.callee.name;
1520
}
1621
if (node.callee.type === "MemberExpression") {
17-
return [...getMemberExpressionIdentifier(node.callee)].join(".");
22+
return [
23+
...getMemberExpressionIdentifier(node.callee, { tracer })
24+
].join(".");
1825
}
1926

20-
return getCallExpressionIdentifier(node.callee);
27+
return resolveCallExpression ?
28+
getCallExpressionIdentifier(node.callee, { tracer }) : null;
2129
}

workspaces/estree-ast-utils/src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function getCallExpressionArguments(
1616
): string[] | null;
1717

1818
export function getCallExpressionIdentifier(
19-
node: any
19+
node: any, options?: { tracer?: VariableTracer, resolveCallExpression?: boolean }
2020
): string | null;
2121

2222
export function getMemberExpressionIdentifier(

workspaces/estree-ast-utils/test/getCallExpressionIdentifier.spec.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,54 @@ test("given a JavaScript eval CallExpression then it must return eval", (tape) =
1313
tape.end();
1414
});
1515

16-
test("given a JavaScript Function() CallExpression then it must return Function", (tape) => {
16+
test("given a Function(`...`)() Double CallExpression then it must return the Function literal identifier", (tape) => {
1717
const [astNode] = codeToAst("Function(\"return this\")();");
1818
const nodeIdentifier = getCallExpressionIdentifier(getExpressionFromStatement(astNode));
1919

2020
tape.strictEqual(nodeIdentifier, "Function");
2121
tape.end();
2222
});
2323

24+
test(`given a Function("...")() Double CallExpression with resolveCallExpression options disabled
25+
then it must return null`, (tape) => {
26+
const [astNode] = codeToAst("Function(\"return this\")();");
27+
const nodeIdentifier = getCallExpressionIdentifier(
28+
getExpressionFromStatement(astNode),
29+
{ resolveCallExpression: false }
30+
);
31+
32+
tape.strictEqual(nodeIdentifier, null);
33+
tape.end();
34+
});
35+
2436
test("given a JavaScript AssignmentExpression then it must return null", (tape) => {
2537
const [astNode] = codeToAst("foo = 10;");
2638
const nodeIdentifier = getCallExpressionIdentifier(getExpressionFromStatement(astNode));
2739

2840
tape.strictEqual(nodeIdentifier, null);
2941
tape.end();
3042
});
43+
44+
test(`given a require statement immediatly invoked with resolveCallExpression options enabled
45+
then it must return require literal identifier`, (tape) => {
46+
const [astNode] = codeToAst("require('foo')();");
47+
const nodeIdentifier = getCallExpressionIdentifier(
48+
getExpressionFromStatement(astNode),
49+
{ resolveCallExpression: true }
50+
);
51+
52+
tape.strictEqual(nodeIdentifier, "require");
53+
tape.end();
54+
});
55+
56+
test(`given a require statement immediatly invoked with resolveCallExpression options disabled
57+
then it must return null`, (tape) => {
58+
const [astNode] = codeToAst("require('foo')();");
59+
const nodeIdentifier = getCallExpressionIdentifier(
60+
getExpressionFromStatement(astNode),
61+
{ resolveCallExpression: false }
62+
);
63+
64+
tape.strictEqual(nodeIdentifier, null);
65+
tape.end();
66+
});

0 commit comments

Comments
 (0)