Skip to content

Commit 2e8479b

Browse files
committed
refactor(estree-ast-utils): enhance input and output types using Meriyah ESTree defs
1 parent 3c2d35a commit 2e8479b

14 files changed

+115
-83
lines changed

.changeset/mean-waves-retire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/estree-ast-utils": minor
3+
---
4+
5+
Enhance input and output types using Meriyah ESTree defs

workspaces/estree-ast-utils/README.md

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ $ yarn add @nodesecure/estree-ast-utils
2020

2121
## API
2222

23-
<details><summary>arrayExpressionToString(node): IterableIterator< string ></summary>
23+
<details><summary>arrayExpressionToString(node: ESTree.Node | null): IterableIterator< string ></summary>
2424

2525
Translate an ESTree ArrayExpression into an iterable of Literal value.
2626

@@ -32,7 +32,7 @@ will return `"foo"` then `"bar"`.
3232

3333
</details>
3434

35-
<details><summary>concatBinaryExpression(node, options): IterableIterator< string ></summary>
35+
<details><summary>concatBinaryExpression(node: ESTree.BinaryExpression, options?: ConcatBinaryExpressionOptions): IterableIterator< string ></summary>
3636

3737
Return all Literal part of a given Binary Expression.
3838

@@ -42,11 +42,17 @@ Return all Literal part of a given Binary Expression.
4242

4343
will return `"foo"` then `"bar"`.
4444

45-
One of the options of the method is `stopOnUnsupportedNode`, if true it will throw an Error if the left or right side of the Expr is not a supported type.
45+
```ts
46+
export interface ConcatBinaryExpressionOptions extends TracerOptions {
47+
stopOnUnsupportedNode?: boolean;
48+
}
49+
```
50+
51+
If `stopOnUnsupportedNode` option is enabled it will throw an Error if the left or right side of the Expr is not a supported type.
4652

4753
</details>
4854

49-
<details><summary>getCallExpressionIdentifier(node, options): string | null</summary>
55+
<details><summary>getCallExpressionIdentifier(node: ESTree.Node, options?: GetCallExpressionIdentifierOptions): string | null</summary>
5056

5157
Return the identifier name of the CallExpression (or null if there is none).
5258

@@ -69,7 +75,7 @@ With **resolveCallExpression** equal to **false** the function return `null`.
6975

7076
</details>
7177

72-
<details><summary>getMemberExpressionIdentifier(node): IterableIterator< string ></summary>
78+
<details><summary>getMemberExpressionIdentifier(node: ESTree.MemberExpression, options?: TracerOptions): IterableIterator< string ></summary>
7379

7480
Return the identifier name of the CallExpression (or null if there is none).
7581

@@ -81,7 +87,7 @@ will return `"foo"` then `"bar"`.
8187

8288
</details>
8389

84-
<details><summary>getVariableDeclarationIdentifiers(node): IterableIterator< string ></summary>
90+
<details><summary>getVariableDeclarationIdentifiers(node: any, options?: GetVariableDeclarationIdentifiersOptions): IterableIterator< string ></summary>
8591

8692
Get all variables identifier name.
8793

@@ -93,17 +99,7 @@ will return `"foo"` then `"bar"`.
9399

94100
</details>
95101

96-
<details><summary>isLiteralRegex(node): boolean</summary>
97-
98-
Return `true` if the given Node is a Literal Regex Node.
99-
100-
```js
101-
/^hello/g;
102-
```
103-
104-
</details>
105-
106-
<details><summary>extractLogicalExpression(node)</summary>
102+
<details><summary>extractLogicalExpression(node: ESTree.Node): IterableIterator< { operator: string; node: ESTree.Expression; } ></summary>
107103

108104
Extract all LogicalExpression recursively and return an IterableIterator of
109105

workspaces/estree-ast-utils/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
},
3131
"homepage": "https://github.com/NodeSecure/js-x-ray/tree/master/workspaces/estree-ast-utils#readme",
3232
"dependencies": {
33-
"@nodesecure/sec-literal": "^1.1.0"
33+
"@nodesecure/sec-literal": "^1.1.0",
34+
"meriyah": "^6.1.3"
3435
}
3536
}

workspaces/estree-ast-utils/src/arrayExpressionToString.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
3+
14
// Import Internal Dependencies
2-
import type { TracerOptions, NodeAst } from "./types.js";
5+
import type { TracerOptions } from "./types.js";
36

47
export function* arrayExpressionToString(
5-
node: NodeAst,
8+
node: ESTree.Node | null,
69
options: TracerOptions = {}
710
): IterableIterator<string> {
811
const { tracer = null } = options;
@@ -12,18 +15,26 @@ export function* arrayExpressionToString(
1215
}
1316

1417
for (const row of node.elements) {
18+
if (row === null) {
19+
continue;
20+
}
21+
1522
switch (row.type) {
1623
case "Literal": {
17-
if (row.value === "") {
24+
if (
25+
row.value === ""
26+
) {
1827
continue;
1928
}
2029

2130
const value = Number(row.value);
22-
yield Number.isNaN(value) ? row.value : String.fromCharCode(value);
31+
yield Number.isNaN(value) ?
32+
String(row.value) :
33+
String.fromCharCode(value);
2334
break;
2435
}
2536
case "Identifier": {
26-
if (tracer !== null && tracer.literalIdentifiers.has(row.name)) {
37+
if (tracer?.literalIdentifiers.has(row.name)) {
2738
yield tracer.literalIdentifiers.get(row.name);
2839
}
2940
break;

workspaces/estree-ast-utils/src/concatBinaryExpression.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
3+
14
// Import Internal Dependencies
25
import { arrayExpressionToString } from "./arrayExpressionToString.js";
3-
import type { TracerOptions, NodeAst } from "./types.js";
6+
import type { TracerOptions } from "./types.js";
47

58
// CONSTANTS
69
const kBinaryExprTypes = new Set([
@@ -11,11 +14,19 @@ const kBinaryExprTypes = new Set([
1114
]);
1215

1316
export interface ConcatBinaryExpressionOptions extends TracerOptions {
17+
/**
18+
* When set to true, the function will throw an error if it encounters
19+
* a node type that is not supported (i.e., not a Literal, BinaryExpr, ArrayExpr or Identifier).
20+
*
21+
* @default false
22+
* @example
23+
* "foo" + fn() + "bar" // <- will throw an error if `stopOnUnsupportedNode` is true
24+
*/
1425
stopOnUnsupportedNode?: boolean;
1526
}
1627

1728
export function* concatBinaryExpression(
18-
node: NodeAst,
29+
node: ESTree.BinaryExpression,
1930
options: ConcatBinaryExpressionOptions = {}
2031
): IterableIterator<string> {
2132
const {
@@ -45,7 +56,9 @@ export function* concatBinaryExpression(
4556
break;
4657
}
4758
case "Literal":
48-
yield childNode.value;
59+
if (typeof childNode.value === "string") {
60+
yield childNode.value;
61+
}
4962
break;
5063
case "Identifier":
5164
if (tracer !== null && tracer.literalIdentifiers.has(childNode.name)) {

workspaces/estree-ast-utils/src/extractLogicalExpression.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// Import Internal Dependencies
2-
import type { NodeAst } from "./types.js";
3-
4-
export type LogicalExpressionOperators = "||" | "&&" | "??";
1+
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
53

64
export function* extractLogicalExpression(
7-
node: NodeAst
8-
): IterableIterator<{ operator: LogicalExpressionOperators; node: NodeAst; }> {
5+
node: ESTree.Node
6+
): IterableIterator<{ operator: string; node: ESTree.Expression; }> {
97
if (node.type !== "LogicalExpression") {
108
return;
119
}

workspaces/estree-ast-utils/src/getCallExpressionArguments.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// Import Third-party Dependencies
22
import { Hex } from "@nodesecure/sec-literal";
3+
import type { ESTree } from "meriyah";
34

45
// Import Internal Dependencies
56
import { concatBinaryExpression } from "./concatBinaryExpression.js";
6-
import type { TracerOptions, NodeAst } from "./types.js";
7+
import type { TracerOptions } from "./types.js";
78

89
export function getCallExpressionArguments(
9-
node: NodeAst,
10+
node: ESTree.Node,
1011
options: TracerOptions = {}
1112
): string[] | null {
1213
const { tracer = null } = options;
@@ -26,7 +27,9 @@ export function getCallExpressionArguments(
2627
break;
2728
}
2829
case "Literal": {
29-
literalsNode.push(hexToString(arg.value));
30+
if (typeof arg.value === "string") {
31+
literalsNode.push(hexToString(arg.value));
32+
}
3033

3134
break;
3235
}

workspaces/estree-ast-utils/src/getCallExpressionIdentifier.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1+
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
3+
14
// Import Internal Dependencies
25
import { getMemberExpressionIdentifier } from "./getMemberExpressionIdentifier.js";
3-
import type { TracerOptions, NodeAst } from "./types.js";
6+
import type { TracerOptions } from "./types.js";
47

58
export interface GetCallExpressionIdentifierOptions extends TracerOptions {
9+
/**
10+
* Resolve the CallExpression callee if it is a MemberExpression.
11+
*
12+
* @default true
13+
* @example
14+
* require('./file.js')();
15+
^ Second ^ First
16+
*/
617
resolveCallExpression?: boolean;
718
}
819

920
export function getCallExpressionIdentifier(
10-
node: NodeAst,
21+
node: ESTree.Node,
1122
options: GetCallExpressionIdentifierOptions = {}
1223
): string | null {
1324
if (node.type !== "CallExpression") {

workspaces/estree-ast-utils/src/getMemberExpressionIdentifier.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
23
import { Hex } from "@nodesecure/sec-literal";
34

45
// Import Internal Dependencies
56
import { concatBinaryExpression } from "./concatBinaryExpression.js";
6-
import type { TracerOptions, NodeAst } from "./types.js";
7+
import type { TracerOptions } from "./types.js";
78

89
/**
910
* Return the complete identifier of a MemberExpression
1011
*/
1112
export function* getMemberExpressionIdentifier(
12-
node: NodeAst,
13+
node: ESTree.MemberExpression,
1314
options: TracerOptions = {}
1415
): IterableIterator<string> {
1516
const { tracer = null } = options;
@@ -24,7 +25,9 @@ export function* getMemberExpressionIdentifier(
2425
break;
2526
// Literal is used when the property is computed
2627
case "Literal":
27-
yield node.object.value;
28+
if (typeof node.object.value === "string") {
29+
yield node.object.value;
30+
}
2831
break;
2932
}
3033

@@ -41,13 +44,20 @@ export function* getMemberExpressionIdentifier(
4144
}
4245
// Literal is used when the property is computed
4346
case "Literal":
44-
yield node.property.value;
47+
if (typeof node.property.value === "string") {
48+
yield node.property.value;
49+
}
4550
break;
4651

4752
// foo.bar[callexpr()]
4853
case "CallExpression": {
4954
const args = node.property.arguments;
50-
if (args.length > 0 && args[0].type === "Literal" && Hex.isHex(args[0].value)) {
55+
if (
56+
args.length > 0 &&
57+
args[0].type === "Literal" &&
58+
typeof args[0].value === "string" &&
59+
Hex.isHex(args[0].value)
60+
) {
5161
yield Buffer.from(args[0].value, "hex").toString();
5262
}
5363
break;

workspaces/estree-ast-utils/src/getVariableDeclarationIdentifiers.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
// Import Internal Dependencies
2-
import type { NodeAst } from "./types.js";
1+
// Import Third-party Dependencies
2+
import type { ESTree } from "meriyah";
33

44
export interface GetVariableDeclarationIdentifiersOptions {
5+
/**
6+
* Prefix to add to the variable name.
7+
* @default void
8+
*/
59
prefix?: string;
610
}
711

812
export function* getVariableDeclarationIdentifiers(
9-
node: NodeAst,
13+
node: ESTree.Node,
1014
options: GetVariableDeclarationIdentifiersOptions = {}
1115
): IterableIterator<{
1216
name: string;
13-
assignmentId: NodeAst;
17+
assignmentId: ESTree.Identifier;
1418
}> {
1519
const { prefix = null } = options;
1620

@@ -34,11 +38,14 @@ export function* getVariableDeclarationIdentifiers(
3438
break;
3539

3640
case "Property": {
37-
if (node.kind !== "init") {
41+
if (node.kind !== "init" || node.key.type !== "Identifier") {
3842
break;
3943
}
4044

41-
if (node.value.type === "ObjectPattern" || node.value.type === "ArrayPattern") {
45+
if (
46+
node.value.type === "ObjectPattern" ||
47+
node.value.type === "ArrayPattern"
48+
) {
4249
yield* getVariableDeclarationIdentifiers(node.value, {
4350
prefix: autoPrefix(node.key.name, prefix)
4451
});
@@ -50,10 +57,14 @@ export function* getVariableDeclarationIdentifiers(
5057
assignmentId = node.value;
5158
}
5259
else if (node.value.type === "AssignmentPattern") {
60+
// @ts-ignore
5361
assignmentId = node.value.left;
5462
}
5563

56-
yield { name: autoPrefix(node.key.name, prefix), assignmentId };
64+
yield {
65+
name: autoPrefix(node.key.name, prefix),
66+
assignmentId
67+
};
5768

5869
break;
5970
}
@@ -64,7 +75,12 @@ export function* getVariableDeclarationIdentifiers(
6475
* const {...foo} = {}
6576
*/
6677
case "RestElement":
67-
yield { name: autoPrefix(node.argument.name, prefix), assignmentId: node.argument };
78+
if (node.argument.type === "Identifier") {
79+
yield {
80+
name: autoPrefix(node.argument.name, prefix),
81+
assignmentId: node.argument
82+
};
83+
}
6884

6985
break;
7086

@@ -83,7 +99,7 @@ export function* getVariableDeclarationIdentifiers(
8399
*/
84100
case "AssignmentPattern":
85101
if (node.left.type === "Identifier") {
86-
yield node.left.name;
102+
yield { name: node.left.name, assignmentId: node.left };
87103
}
88104
else {
89105
yield* getVariableDeclarationIdentifiers(node.left);

0 commit comments

Comments
 (0)