Skip to content

Commit aea4d8f

Browse files
feat: explicitly curry all functions (#8)
1 parent 7fba472 commit aea4d8f

File tree

6 files changed

+101
-90
lines changed

6 files changed

+101
-90
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,27 @@ $ npm install babel-walk
2828
var walk = require('babel-walk');
2929
```
3030

31-
### walk.simple(node, visitors, state)
31+
### walk.simple(visitors)(node, state)
3232

3333
Do a simple walk over the AST. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state)`, where `node` is the AST node, and `state` is the same `state` passed to `walk.simple`.
3434

35-
When `walk.simple` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babel-walk is that the state is only accessible through the `state` variable, never as `this`.)
35+
When `walk.simple` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to cache the result of calling `walk.simple(visitors)` and communicate state leveraging the `state` parameter.
3636

3737
All [babel-types] aliases (e.g. `Expression`) work, but the union syntax (e.g. `'Identifier|AssignmentPattern'(node, state) {}`) does not.
3838

39-
### walk.ancestor(node, visitors, state)
39+
### walk.ancestor(visitors)(node, state)
4040

4141
Do a simple walk over the AST, but memoizing the ancestors of the node and making them available to the visitors. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state, ancestors)`, where `node` is the AST node, `state` is the same `state` passed to `walk.ancestor`, and `ancestors` is an array of ancestors to the node (with the outermost node being `[0]` and the current node being `[ancestors.length - 1]`). If `state` is not specified in the call to `walk.ancestor`, the `state` parameter will be set to `ancestors`.
4242

43-
When `walk.ancestor` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babel-walk is that the state is only accessible through the `state` variable, never as `this`.)
43+
When `walk.ancestor` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to cache the result of calling `walk.ancestor(visitors)` and communicate state leveraging the `state` parameter.
4444

4545
All [babel-types] aliases (e.g. `Expression`) work, but the union syntax (e.g. `'Identifier|AssignmentPattern'(node, state) {}`) does not.
4646

47-
### walk.recursive(node, visitors, state)
47+
### walk.recursive(visitors)(node, state)
4848

4949
Do a recursive walk over the AST, where the visitors are responsible for continuing the walk on the child nodes of their target node. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state, c)`, where `node` is the AST node, `state` is the same `state` passed to `walk.recursive`, and `c` is a function that takes a single node as argument and continues walking _that_ node. If no visitor for a node is provided, the default walker algorithm will still be used.
5050

51-
When `walk.recursive` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babel-walk is that the state is only accessible through the `state` variable, never as `this`.)
51+
When `walk.recursive` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to cache the result of calling `walk.recursive(visitors)` and communicate state leveraging the `state` parameter.
5252

5353
Unlike other babel-walk walkers, `walk.recursive` does not call the `exit` visitor, only the `enter` (the default) visitor, of a specific node type.
5454

@@ -61,7 +61,7 @@ import * as t from 'babel-types';
6161
import {parse} from 'babel';
6262
import * as walk from 'babel-walk';
6363

64-
const visitors = {
64+
const visitors = walk.recursive({
6565
Statement(node, state, c) {
6666
if (t.isVariableDeclaration(node)) {
6767
for (let declarator of node.declarations) {
@@ -78,13 +78,13 @@ const visitors = {
7878
state.counter++;
7979
}
8080
},
81-
};
81+
});
8282

8383
function countFunctions(node) {
8484
const state = {
8585
counter: 0,
8686
};
87-
walk.recursive(node, visitors, state);
87+
visitors(node, state);
8888
return state.counter;
8989
}
9090

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"devDependencies": {
2929
"@forbeslindesay/tsconfig": "^2.0.0",
30+
"@types/node": "^14.0.5",
3031
"prettier": "^2.0.5",
3132
"rimraf": "^3.0.2",
3233
"tslint": "^6.1.2",

src/explode.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ if (
3939
* 3. make the enter and exit handlers arrays, so that multiple handlers can be merged
4040
*/
4141
export default function explode(input: any): any {
42-
if (input._babel_walk_exploded) {
43-
return input._babel_walk_exploded;
44-
}
4542
const results: any = {};
4643
for (const key in input) {
4744
const aliases = FLIPPED_ALIAS_KEYS[key];
@@ -93,6 +90,5 @@ export default function explode(input: any): any {
9390
}
9491
}
9592
}
96-
input._babel_walk_exploded = results;
9793
return results;
9894
}

src/index.ts

Lines changed: 71 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,38 @@ export type SimpleVisitors<TState = void> = {
3838
};
3939
};
4040

41-
export function simple<TState>(
42-
node: t.Node,
43-
visitors: SimpleVisitors<TState>,
44-
state: TState,
45-
) {
41+
export function simple<TState = void>(visitors: SimpleVisitors<TState>) {
4642
const vis = explode(visitors);
47-
(function recurse(node) {
48-
if (!node) return;
43+
return (node: t.Node, state: TState) => {
44+
(function recurse(node) {
45+
if (!node) return;
4946

50-
const visitor = vis[node.type];
47+
const visitor = vis[node.type];
5148

52-
if (visitor?.enter) {
53-
for (const v of visitor.enter) {
54-
v(node, state);
49+
if (visitor?.enter) {
50+
for (const v of visitor.enter) {
51+
v(node, state);
52+
}
5553
}
56-
}
5754

58-
for (const key of VISITOR_KEYS[node.type] || []) {
59-
const subNode = (node as any)[key];
60-
if (Array.isArray(subNode)) {
61-
for (const subSubNode of subNode) {
62-
recurse(subSubNode);
55+
for (const key of VISITOR_KEYS[node.type] || []) {
56+
const subNode = (node as any)[key];
57+
if (Array.isArray(subNode)) {
58+
for (const subSubNode of subNode) {
59+
recurse(subSubNode);
60+
}
61+
} else {
62+
recurse(subNode);
6363
}
64-
} else {
65-
recurse(subNode);
6664
}
67-
}
6865

69-
if (visitor?.exit) {
70-
for (const v of visitor.exit) {
71-
v(node, state);
66+
if (visitor?.exit) {
67+
for (const v of visitor.exit) {
68+
v(node, state);
69+
}
7270
}
73-
}
74-
})(node);
71+
})(node);
72+
};
7573
}
7674

7775
export type AncestorFunction<TKey extends string, TState> = (
@@ -89,47 +87,45 @@ export type AncestorVisitor<TState = void> = {
8987
};
9088
};
9189

92-
export function ancestor<TState = void>(
93-
node: t.Node,
94-
visitors: AncestorVisitor<TState>,
95-
state: TState,
96-
) {
90+
export function ancestor<TState = void>(visitors: AncestorVisitor<TState>) {
9791
const vis = explode(visitors);
98-
const ancestors: t.Node[] = [];
92+
return (node: t.Node, state: TState) => {
93+
const ancestors: t.Node[] = [];
9994

100-
(function recurse(node) {
101-
if (!node) return;
95+
(function recurse(node) {
96+
if (!node) return;
10297

103-
const visitor = vis[node.type];
98+
const visitor = vis[node.type];
10499

105-
const isNew = node !== ancestors[ancestors.length - 1];
106-
if (isNew) ancestors.push(node);
100+
const isNew = node !== ancestors[ancestors.length - 1];
101+
if (isNew) ancestors.push(node);
107102

108-
if (visitor?.enter) {
109-
for (const v of visitor.enter) {
110-
v(node, state, ancestors);
103+
if (visitor?.enter) {
104+
for (const v of visitor.enter) {
105+
v(node, state, ancestors);
106+
}
111107
}
112-
}
113108

114-
for (const key of VISITOR_KEYS[node.type] || []) {
115-
const subNode = (node as any)[key];
116-
if (Array.isArray(subNode)) {
117-
for (const subSubNode of subNode) {
118-
recurse(subSubNode);
109+
for (const key of VISITOR_KEYS[node.type] || []) {
110+
const subNode = (node as any)[key];
111+
if (Array.isArray(subNode)) {
112+
for (const subSubNode of subNode) {
113+
recurse(subSubNode);
114+
}
115+
} else {
116+
recurse(subNode);
119117
}
120-
} else {
121-
recurse(subNode);
122118
}
123-
}
124119

125-
if (visitor?.exit) {
126-
for (const v of visitor.exit) {
127-
v(node, state, ancestors);
120+
if (visitor?.exit) {
121+
for (const v of visitor.exit) {
122+
v(node, state, ancestors);
123+
}
128124
}
129-
}
130125

131-
if (isNew) ancestors.pop();
132-
})(node);
126+
if (isNew) ancestors.pop();
127+
})(node);
128+
};
133129
}
134130

135131
export type RecursiveVisitors<TState = void> = {
@@ -140,31 +136,29 @@ export type RecursiveVisitors<TState = void> = {
140136
) => void;
141137
};
142138

143-
export function recursive<TState>(
144-
node: t.Node,
145-
visitors: RecursiveVisitors<TState>,
146-
state: TState,
147-
) {
139+
export function recursive<TState = void>(visitors: RecursiveVisitors<TState>) {
148140
const vis = explode(visitors);
149-
(function recurse(node: t.Node) {
150-
if (!node) return;
151-
152-
const visitor = vis[node.type];
153-
if (visitor?.enter) {
154-
for (const v of visitor.enter) {
155-
v(node, state, recurse);
156-
}
157-
} else {
158-
for (const key of VISITOR_KEYS[node.type] || []) {
159-
const subNode = (node as any)[key];
160-
if (Array.isArray(subNode)) {
161-
for (const subSubNode of subNode) {
162-
recurse(subSubNode);
141+
return (node: t.Node, state: TState) => {
142+
(function recurse(node: t.Node) {
143+
if (!node) return;
144+
145+
const visitor = vis[node.type];
146+
if (visitor?.enter) {
147+
for (const v of visitor.enter) {
148+
v(node, state, recurse);
149+
}
150+
} else {
151+
for (const key of VISITOR_KEYS[node.type] || []) {
152+
const subNode = (node as any)[key];
153+
if (Array.isArray(subNode)) {
154+
for (const subSubNode of subNode) {
155+
recurse(subSubNode);
156+
}
157+
} else {
158+
recurse(subNode);
163159
}
164-
} else {
165-
recurse(subNode);
166160
}
167161
}
168-
}
169-
})(node);
162+
})(node);
163+
};
170164
}

src/test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as t from '@babel/types';
2+
import {ancestor} from './';
3+
4+
ancestor({})(t.program([]), undefined);
5+
ancestor({
6+
Function(node) {
7+
console.info(node);
8+
},
9+
})(t.program([]), undefined);
10+
11+
ancestor<string>({
12+
Function(node, state) {
13+
console.info(node, state);
14+
},
15+
})(t.program([]), 'hello world');

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@
3737
resolved "https://registry.yarnpkg.com/@forbeslindesay/tsconfig/-/tsconfig-2.0.0.tgz#71a8a92afb366ea7ca05fe46e68bc033060c2e2d"
3838
integrity sha512-SqkFDsM1vgB5iXCjJKnnvYwIlQZhLfGjKQfmwp3PZjvqoDVbng76iQvppJAG1pX2nSmkPz8Z1rmEylXop/Ma8A==
3939

40+
"@types/node@^14.0.5":
41+
version "14.0.5"
42+
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.5.tgz#3d03acd3b3414cf67faf999aed11682ed121f22b"
43+
integrity sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==
44+
4045
ansi-styles@^3.2.1:
4146
version "3.2.1"
4247
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"

0 commit comments

Comments
 (0)