Skip to content

Commit 08d1dfe

Browse files
committed
Preps for v2 release.
1 parent 53c6527 commit 08d1dfe

File tree

6 files changed

+435
-13
lines changed

6 files changed

+435
-13
lines changed

.gitignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ npm-debug.log
1111
# Jest
1212
coverage
1313

14-
# Build output
15-
umd
16-
commonjs
17-
build
18-
1914
# Flow
2015
flow-coverage
2116
flow-typed

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,27 @@ const values = [];
6868
* @param context - The current "React Context". Any provided childContexTypes
6969
* will be passed down the tree.
7070
*
71-
* @return `undefined` if you want to continue walking down the current branch,
72-
* or return `false` if you wish to stop the traversal down the
73-
* current branch. Stopping the traversal can be quite handy if
74-
* you want to resolve a Promise for example. You can wait for the
75-
* Promise to resolve and then execute a function to continue
76-
* traversal of the branch where you left off.
71+
* @return `true` to continue walking down the current branch,
72+
* OR
73+
* `false` if you wish to stop the traversal down the current branch,
74+
* OR
75+
* `Promise<true|false>` a promise that resolves to either true/false
7776
*/
7877
function visitor(element, instance, context) {
7978
if (instance && typeof instance.getValue) {
79+
const value = instance.getValue()
80+
if (value === 4) {
81+
// stop traversal on this branch of tree.
82+
return false
83+
}
8084
values.push(instance.getValue());
8185
}
86+
return true
8287
};
8388

8489
reactTreeWalker(app, visitor);
8590

86-
console.log(values); // [1, 2, 4, 5, 3];
91+
console.log(values); // [1, 2, 4, 3];
8792
```
8893

8994
## FAQs

commonjs/index.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.isPromise = undefined;
7+
exports.default = reactTreeWalker;
8+
9+
var _react = require('react');
10+
11+
// Lifted from https://github.com/sindresorhus/p-reduce
12+
// Thanks @sindresorhus!
13+
var pReduce = function pReduce(iterable, reducer, initVal) {
14+
return new Promise(function (resolve, reject) {
15+
var iterator = iterable[Symbol.iterator]();
16+
var i = 0;
17+
18+
var next = function next(total) {
19+
var el = iterator.next();
20+
21+
if (el.done) {
22+
resolve(total);
23+
return;
24+
}
25+
26+
Promise.all([total, el.value]).then(function (value) {
27+
// eslint-disable-next-line no-plusplus
28+
next(reducer(value[0], value[1], i++));
29+
}).catch(reject);
30+
};
31+
32+
next(initVal);
33+
});
34+
};
35+
36+
// Lifted from https://github.com/sindresorhus/p-map-series
37+
// Thanks @sindresorhus!
38+
/* eslint-disable no-console */
39+
40+
// Inspired by the awesome work done by the Apollo team.
41+
// See https://github.com/apollostack/react-apollo/blob/master/src/server.ts
42+
// This version has been adapted to be promise based.
43+
44+
// eslint-disable-next-line import/no-extraneous-dependencies
45+
var pMapSeries = function pMapSeries(iterable, iterator) {
46+
var ret = [];
47+
48+
return pReduce(iterable, function (a, b, i) {
49+
return Promise.resolve(iterator(b, i)).then(function (val) {
50+
ret.push(val);
51+
});
52+
}).then(function () {
53+
return ret;
54+
});
55+
};
56+
57+
var isPromise = exports.isPromise = function isPromise(x) {
58+
return x != null && typeof x.then === 'function';
59+
};
60+
61+
// Recurse an React Element tree, running visitor on each element.
62+
// If visitor returns `false`, don't call the element's render function
63+
// or recurse into its child elements
64+
function reactTreeWalker(element, visitor, context) {
65+
return new Promise(function (resolve) {
66+
var doVisit = function doVisit(getChildren, visitorResult, childContext, isChildren) {
67+
var doTraverse = function doTraverse(shouldContinue) {
68+
if (!shouldContinue) {
69+
// We recieved a false, which indicates a desire to stop traversal.
70+
resolve();
71+
}
72+
73+
var child = getChildren();
74+
var theChildContext = typeof childContext === 'function' ? childContext() : childContext;
75+
76+
if (child == null) {
77+
// If no children then we can't traverse. We've reached the leaf.
78+
resolve();
79+
} else if (isChildren) {
80+
// If its a react Children collection we need to breadth-first
81+
// traverse each of them.
82+
var mapper = function mapper(aChild) {
83+
return aChild ? reactTreeWalker(aChild, visitor, theChildContext) : undefined;
84+
};
85+
// pMapSeries allows us to do depth-first traversal. Thanks @sindresorhus!
86+
pMapSeries(_react.Children.map(child, function (cur) {
87+
return cur;
88+
}), mapper).then(resolve);
89+
} else {
90+
// Otherwise we pass the individual child to the next recursion.
91+
reactTreeWalker(child, visitor, theChildContext).then(resolve);
92+
}
93+
};
94+
95+
if (visitorResult === false) {
96+
// Visitor returned false, indicating a desire to not traverse.
97+
resolve();
98+
} else if (isPromise(visitorResult)) {
99+
// We need to execute the result and pass it's result through to our
100+
// continuer.
101+
visitorResult.then(doTraverse).catch(function (e) {
102+
console.log('Error occurred in Promise based visitor result provided to react-tree-walker.');
103+
if (e) {
104+
console.log(e);
105+
if (e.stack) {
106+
console.log(e.stack);
107+
}
108+
}
109+
});
110+
} else {
111+
doTraverse(true);
112+
}
113+
};
114+
115+
// Is this element a Component?
116+
if (typeof element.type === 'function') {
117+
var Component = element.type;
118+
var props = Object.assign({}, Component.defaultProps, element.props);
119+
120+
// Is this a class component? (http://bit.ly/2j9Ifk3)
121+
var isReactClassComponent = Component.prototype && (Component.prototype.isReactComponent || Component.prototype.isPureReactComponent);
122+
123+
if (isReactClassComponent) {
124+
// React class component
125+
126+
var instance = new Component(props, context);
127+
128+
// In case the user doesn't pass these to super in the constructor
129+
instance.props = instance.props || props;
130+
instance.context = instance.context || context;
131+
132+
// Make the setState synchronous.
133+
instance.setState = function (newState) {
134+
instance.state = Object.assign({}, instance.state, newState);
135+
};
136+
137+
doVisit(function () {
138+
// Call componentWillMount if it exists.
139+
if (instance.componentWillMount) {
140+
instance.componentWillMount();
141+
}
142+
143+
return instance.render();
144+
}, visitor(element, instance, context), function () {
145+
return (
146+
// Ensure the child context is initialised if it is available. We will
147+
// need to pass it down the tree.
148+
instance.getChildContext ? Object.assign({}, context, instance.getChildContext()) : context
149+
);
150+
});
151+
} else {
152+
// Stateless Functional Component
153+
doVisit(function () {
154+
return Component(props, context);
155+
}, visitor(element, null, context), context);
156+
}
157+
} else {
158+
// This must be a basic element, such as a string or dom node.
159+
doVisit(function () {
160+
return element.props && element.props.children ? element.props.children : undefined;
161+
}, visitor(element, null, context), context, true);
162+
}
163+
});
164+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-tree-walker",
3-
"version": "2.0.0-alpha.3",
3+
"version": "2.0.0",
44
"description": "Walk a React element tree, executing a provided function against each node.",
55
"license": "MIT",
66
"main": "commonjs/index.js",

0 commit comments

Comments
 (0)