react-tree-walker
Advanced tools
| const uglify = require('rollup-plugin-uglify') | ||
| const packageJson = require('./package.json') | ||
| const baseConfig = require('./rollup.config.js') | ||
| baseConfig.plugins.push(uglify()) | ||
| baseConfig.output.file = `dist/${packageJson.name}.min.js` | ||
| module.exports = baseConfig |
| const babel = require('rollup-plugin-babel') | ||
| const changeCase = require('change-case') | ||
| const packageJson = require('./package.json') | ||
| process.env.BABEL_ENV = 'production' | ||
| module.exports = { | ||
| external: ['react'], | ||
| input: 'src/index.js', | ||
| output: { | ||
| file: `dist/${packageJson.name}.js`, | ||
| format: 'cjs', | ||
| sourcemap: true, | ||
| name: changeCase | ||
| .titleCase(packageJson.name.replace(/-/g, ' ')) | ||
| .replace(/ /g, ''), | ||
| }, | ||
| plugins: [ | ||
| babel({ | ||
| babelrc: false, | ||
| exclude: 'node_modules/**', | ||
| presets: [['env', { modules: false }], 'stage-3', 'react'], | ||
| plugins: ['external-helpers'], | ||
| }), | ||
| ], | ||
| } |
+13
-12
| { | ||
| "name": "react-tree-walker", | ||
| "version": "3.0.0", | ||
| "version": "4.0.0", | ||
| "description": | ||
@@ -17,8 +17,7 @@ "Walk a React element tree, executing a provided function against each node.", | ||
| "scripts": { | ||
| "precommit": "lint-staged && npm run test", | ||
| "build": "babel-node ./tools/scripts/build.js", | ||
| "check": "npm run lint && npm run test", | ||
| "build": "node ./tools/scripts/build.js", | ||
| "clean": | ||
| "rimraf ./commonjs && rimraf ./umd && rimraf ./coverage && rimraf ./umd", | ||
| "lint": "eslint src", | ||
| "precommit": "lint-staged && npm run test", | ||
| "prepublish": "npm run build", | ||
@@ -39,8 +38,9 @@ "test": "jest", | ||
| "babel-loader": "^7.1.2", | ||
| "babel-plugin-external-helpers": "^6.22.0", | ||
| "babel-polyfill": "^6.26.0", | ||
| "babel-preset-env": "^1.6.0", | ||
| "babel-preset-latest": "6.24.1", | ||
| "babel-preset-react": "6.24.1", | ||
| "babel-preset-stage-3": "6.24.1", | ||
| "babel-register": "^6.26.0", | ||
| "change-case": "^3.0.2", | ||
| "codecov": "^2.3.0", | ||
@@ -61,2 +61,3 @@ "cross-env": "^5.0.5", | ||
| "lint-staged": "^4.2.3", | ||
| "preact": "^8.2.7", | ||
| "prettier": "^1.7.4", | ||
@@ -71,6 +72,5 @@ "pretty-bytes": "4.0.2", | ||
| "rimraf": "^2.6.2", | ||
| "sinon": "^4.0.1", | ||
| "webpack": "^3.6.0", | ||
| "webpack-dev-middleware": "^1.12.0", | ||
| "webpack-hot-middleware": "^2.19.1" | ||
| "rollup": "^0.56.5", | ||
| "rollup-plugin-babel": "^3.0.3", | ||
| "rollup-plugin-uglify": "^3.0.0" | ||
| }, | ||
@@ -84,5 +84,2 @@ "jest": { | ||
| }, | ||
| "lint-staged": { | ||
| "src/**/*.js": ["prettier --write", "git add"] | ||
| }, | ||
| "eslintConfig": { | ||
@@ -102,2 +99,3 @@ "root": true, | ||
| "import/no-extraneous-dependencies": 0, | ||
| "no-nested-ternary": 0, | ||
| "no-underscore-dangle": 0, | ||
@@ -124,3 +122,6 @@ "react/no-array-index-key": 0, | ||
| "trailingComma": "all" | ||
| }, | ||
| "lint-staged": { | ||
| "*.js": ["prettier --write \"src/**/*.js\"", "git add"] | ||
| } | ||
| } |
+176
-52
| # react-tree-walker 🌲 | ||
| Walk a React element tree, executing a provided visitor function against each element. | ||
| Walk a React (or Preact) element tree, executing a "visitor" function against each element. | ||
@@ -12,34 +12,36 @@ [](http://npm.im/react-tree-walker) | ||
| - [Introduction](#introduction) | ||
| - [Example](#example) | ||
| - [FAQs](#faqs) | ||
| * [Introduction](#introduction) | ||
| * [Illustrative Example](#illustrative-example) | ||
| * [Order of Execution](#order-of-execution) | ||
| * [API](#api) | ||
| ## Introduction | ||
| Originally inspired/lifted from the awesome [`react-apollo`](https://github.com/apollostack/react-apollo) project. | ||
| Inspired/lifted from the awesome [`react-apollo`](https://github.com/apollostack/react-apollo) project. 😗 | ||
| This modified version expands upon the design, making it `Promise` based, allowing the visitor to return a `Promise`, which would subsequently delay the tree walking until the `Promise` is resolved. The tree is still walked in a depth-first fashion. | ||
| This modified version expands upon the design, making it `Promise` based, allowing the visitor to return a `Promise`, which would subsequently delay the tree walking until the `Promise` is resolved. The tree is still walked in a depth-first fashion. | ||
| With this you could, for example, perform pre-rendering parses on your React element tree to do things like data prefetching. 🤛 | ||
| With this you could, for example, perform pre-rendering parses on your React element tree to do things like data prefetching. Which can be especially helpful when dealing with declarative APIs such as the one provided by React Router 4. | ||
| # Example | ||
| # Illustrative Example | ||
| In the below example we walk the tree and execute the `getValue` function on every element instance that has the function available. We then push the value into a values array. | ||
| In the below example we will create a visitor that will walk a React application, looking for any "class" component that has a `getData` method on it. We will then execute the `getData` function, storing the results into an array. | ||
| ```jsx | ||
| import reactTreeWalker from 'react-tree-walker'; | ||
| import reactTreeWalker from 'react-tree-walker' | ||
| class Foo extends React.Component { | ||
| class DataFetcher extends React.Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.getData = this.getData.bind(this); | ||
| super(props) | ||
| this.getData = this.getData.bind(this) | ||
| } | ||
| getData() { | ||
| // Return a promise or a sync value | ||
| return Promise.resolve(this.props.value); | ||
| // Supports promises! You could call an API for example to fetch some | ||
| // data, or do whatever "bootstrapping" you desire. | ||
| return Promise.resove(this.props.id) | ||
| } | ||
| render() { | ||
| return <div>{this.props.children}</div>; | ||
| return <div>{this.props.children}</div> | ||
| } | ||
@@ -51,38 +53,23 @@ } | ||
| <h1>Hello World!</h1> | ||
| <Foo value={1} /> | ||
| <Foo value={2}> | ||
| <Foo value={4}> | ||
| <Foo value={5} /> | ||
| </Foo> | ||
| </Foo> | ||
| <Foo value={3} /> | ||
| <DataFetcher id={1} /> | ||
| <DataFetcher id={2}> | ||
| <DataFetcher id={3}> | ||
| <DataFetcher id={4} /> | ||
| </DataFetcher> | ||
| </DataFetcher> | ||
| <DataFetcher id={5} /> | ||
| </div> | ||
| ); | ||
| ) | ||
| const values = []; | ||
| const values = [] | ||
| /** | ||
| * Visitor to be executed on each element being walked. | ||
| * | ||
| * @param element - The current element being walked. | ||
| * @param instance - If the current element is a Component or PureComponent | ||
| * then this will hold the reference to the created | ||
| * instance. For any other element type this will be null. | ||
| * @param context - The current "React Context". Any provided childContextTypes | ||
| * will be passed down the tree. | ||
| * | ||
| * @return Anything other than `false` to continue walking down the current branch | ||
| * OR | ||
| * `false` if you wish to stop the traversal down the current branch, | ||
| * OR | ||
| * `Promise<true|false>` a promise that resolves to either true/false | ||
| */ | ||
| function visitor(element, instance, context) { | ||
| // You provide this! See the API docs below for full details. | ||
| function visitor(element, instance) { | ||
| if (instance && typeof instance.getData) { | ||
| return instance.getData() | ||
| .then((value) => { | ||
| values.push(value); | ||
| // Return "false" to indicate that we do not want to traverse "4"'s children | ||
| return value !== 4 | ||
| }) | ||
| return instance.getData().then(value => { | ||
| values.push(value) | ||
| // Return "false" to indicate that we do not want to visit "3"'s children, | ||
| // therefore we do not expect "4" to make it into our values array. | ||
| return value !== 3 | ||
| }) | ||
| } | ||
@@ -93,11 +80,148 @@ } | ||
| .then(() => { | ||
| console.log(values); // [1, 2, 4, 3]; | ||
| console.log(values) // [1, 2, 3, 5]; | ||
| // Now is a good time to call React's renderToString whilst exposing | ||
| // whatever values you built up to your app. | ||
| }) | ||
| // since v3.0.0 you need to do your own error handling! | ||
| .catch(err => console.error(err)); | ||
| .catch(err => console.error(err)) | ||
| ``` | ||
| Not a particularly useful piece of code, but hopefully it is illustrative enough as to indicate the posibilities. One could use this to warm a cache or a `redux` state, subsequently performing a `renderToString` execution with all the required data in place. | ||
| ## Order of Execution | ||
| `react-tree-walker` walks your React application in a depth-first fashion, i.e. from the top down, visiting each child until their are no more children available before moving on to the next element. We can illustrate this behaviour using the below example: | ||
| ```jsx | ||
| <div> | ||
| <h1>Foo</h1> | ||
| <section> | ||
| <p>One</p> | ||
| <p>Two</p> | ||
| </section> | ||
| <Footer /> | ||
| </div> | ||
| ``` | ||
| ## FAQs | ||
| In this example the order of elements being visited would be: | ||
| > Let me know if you have any... | ||
| div -> h1 -> "Foo" -> section -> p -> "One" -> p -> "Two" -> Footer | ||
| Whilst your application is being walked its behaviour will be much the same as if it were being rendered on the server - i.e. the `componentWillMount` lifecycle will be executed for any "class" components, and context provided by any components will be passed down and become available to child components. | ||
| Despite emulating a server side render, the tree walking process is far cheaper as it doesn't actually perform any rendering of the element tree to a string. It simply interogates your app building up an object/element tree. The really expensive cycles will likely be the API calls that you make. 😀 | ||
| That being said you do have a bail-out ability allowing you to suspend the traversal down a branch of the tree. To do so you simply need to return `false` from your visitor function, or if returning a `Promise` ensure that the `Promise` resolves a `false` for the same behaviour. | ||
| ## API | ||
| The API is very simple at the moment, only exposing a single function, which you can import as follows | ||
| --- | ||
| ### **reactTreeWalker** | ||
| The default export of the library. The function that performs the magic. | ||
| ``` | ||
| const reactTreeWalker = require('react-tree-walker') | ||
| ``` | ||
| _or_ | ||
| ``` | ||
| import reactTreeWalker from 'react-tree-walker' | ||
| ``` | ||
| **Paramaters** | ||
| * **tree** (React/Preact element, _required_) | ||
| The react application you wish to walk. | ||
| e.g. `<div>Hello world</div>` | ||
| * **visitor** (`Function`, _required_) | ||
| The function you wish to execute against _each_ element that is walked on the `tree`. | ||
| See its [API docs](#visitor) below. | ||
| * **context** (`Object`, _optional_) | ||
| Any root context you wish to provide to your application. | ||
| e.g. `{ myContextItem: 'foo' }` | ||
| * **options** (`Object`, _optional_) | ||
| Additional options/configuration. It currently supports the following values: | ||
| * _componentWillUnmount_: Enable this to have the `componentWillUnmount` lifecycle event be executed whilst walking your tree. Defaults to `false`. This was added as an experimental additional flag to help with applications where they have critical disposal logic being executed within the `componentWillUnmount` lifecycle event. | ||
| **Returns** | ||
| A `Promise` that resolves when the tree walking is completed. | ||
| --- | ||
| ### **visitor** | ||
| The function that you create and provide to `reactTreeWalker`. | ||
| It should encapsulates the logic you wish to execute against each element. | ||
| **Parameters** | ||
| * **element** (React/Preact element, _required_) | ||
| The current element being walked. | ||
| * **instance** (Component Instance, _optional_) | ||
| If the current element being walked is a "class" Component then this will contain the instance of the Component - allowing you to interface with its methods etc. | ||
| * **context** (`Object`, _required_) | ||
| The React context that is available to the current element. `react-tree-walker` emulates React in exposing context down the tree. | ||
| * **childContext** (`Object`, _optional_) | ||
| If the current element being walked is a "class" Component and it exposes additional "child" context (via the `getChildContext` method) then this will contain the context that is being provided by the component instance. | ||
| **Returns** | ||
| If you return `false` then the children of the current element will not be visited. | ||
| e.g. | ||
| ```javascript | ||
| function visitor(element) { | ||
| if (element.type === 'menu') { | ||
| // We will not traverse the children for any <menu /> nodes | ||
| return 'false' | ||
| } | ||
| } | ||
| ``` | ||
| You can also return a `Promise` which will cause the tree walking to wait for the `Promise` to be resolved before attempting to visit the children for the current element. | ||
| ```javascript | ||
| function visitor(element, instance) { | ||
| // This will make every visit take 1 second to execution. | ||
| return new Promise(resolve => setTimeout(resolve, 1000)) | ||
| } | ||
| ``` | ||
| You can make the Promise resolve a `false` to indicate that you do not want the children of the current element to be visited. | ||
| ```javascript | ||
| function visitor(element, instance) { | ||
| // Only the first element will be executed, and it will take 1 second to complete. | ||
| return ( | ||
| new Promise(resolve => setTimeout(resolve, 1000)) | ||
| // This prevents any walking down the current elements children | ||
| .then(() => false) | ||
| ) | ||
| } | ||
| ``` |
| 'use strict'; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| exports.isPromise = undefined; | ||
| exports.default = reactTreeWalker; | ||
| var _react = require('react'); | ||
| var defaultOptions = { | ||
| componentWillUnmount: false | ||
| // Lifted from https://github.com/sindresorhus/p-reduce | ||
| // Thanks @sindresorhus! | ||
| }; /* eslint-disable no-console */ | ||
| // Inspired by the awesome work done by the Apollo team. | ||
| // See https://github.com/apollostack/react-apollo/blob/master/src/server.ts | ||
| // This version has been adapted to be promise based. | ||
| // eslint-disable-next-line import/no-extraneous-dependencies | ||
| var pReduce = function pReduce(iterable, reducer, initVal) { | ||
| return new Promise(function (resolve, reject) { | ||
| var iterator = iterable[Symbol.iterator](); | ||
| var i = 0; | ||
| var next = function next(total) { | ||
| var el = iterator.next(); | ||
| if (el.done) { | ||
| resolve(total); | ||
| return; | ||
| } | ||
| Promise.all([total, el.value]).then(function (value) { | ||
| // eslint-disable-next-line no-plusplus | ||
| next(reducer(value[0], value[1], i++)); | ||
| }).catch(reject); | ||
| }; | ||
| next(initVal); | ||
| }); | ||
| }; | ||
| // Lifted from https://github.com/sindresorhus/p-map-series | ||
| // Thanks @sindresorhus! | ||
| var pMapSeries = function pMapSeries(iterable, iterator) { | ||
| var ret = []; | ||
| return pReduce(iterable, function (a, b, i) { | ||
| return Promise.resolve(iterator(b, i)).then(function (val) { | ||
| ret.push(val); | ||
| }); | ||
| }).then(function () { | ||
| return ret; | ||
| }); | ||
| }; | ||
| var ensureChild = function ensureChild(child) { | ||
| return child && typeof child.render === 'function' ? ensureChild(child.render()) : child; | ||
| }; | ||
| var isPromise = exports.isPromise = function isPromise(x) { | ||
| return x != null && typeof x.then === 'function'; | ||
| }; | ||
| // Recurse an React Element tree, running visitor on each element. | ||
| // If visitor returns `false`, don't call the element's render function | ||
| // or recurse into its child elements | ||
| function reactTreeWalker(rootElement, visitor, rootContext) { | ||
| var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultOptions; | ||
| return new Promise(function (resolve, reject) { | ||
| var safeVisitor = visitor.isSafe ? visitor : function () { | ||
| try { | ||
| return visitor.apply(undefined, arguments); | ||
| } catch (err) { | ||
| reject(err); | ||
| } | ||
| return undefined; | ||
| }; | ||
| var recursive = function recursive(currentElement, currentContext) { | ||
| return new Promise(function (innerResolve) { | ||
| var doVisit = function doVisit(getChildren, visitResult, childContext) { | ||
| var visitChildren = function visitChildren() { | ||
| var child = ensureChild(getChildren()); | ||
| var theChildContext = typeof childContext === 'function' ? childContext() : childContext; | ||
| if (child == null) { | ||
| // If no children then we can't traverse. We've reached the leaf. | ||
| innerResolve(); | ||
| } else if (_react.Children.count(child)) { | ||
| // If its a react Children collection we need to breadth-first | ||
| // traverse each of them. | ||
| var mapper = function mapper(aChild) { | ||
| return aChild ? recursive(aChild, theChildContext) : undefined; | ||
| }; | ||
| var children = _react.Children.map(child, function (cur) { | ||
| return cur; | ||
| }); | ||
| // pMapSeries allows us to do depth-first traversal. Thanks @sindresorhus! | ||
| pMapSeries(children, mapper).then(innerResolve, reject).catch(reject); | ||
| } else { | ||
| // Otherwise we pass the individual child to the next recursion. | ||
| recursive(child, theChildContext).then(innerResolve, reject).catch(reject); | ||
| } | ||
| }; | ||
| if (visitResult === false) { | ||
| // Visitor returned false, indicating a desire to not traverse. | ||
| innerResolve(); | ||
| } else if (isPromise(visitResult)) { | ||
| // We need to execute the result and pass it's result through to our | ||
| // continuer. | ||
| visitResult.then(function (promiseResult) { | ||
| if (promiseResult === false) { | ||
| innerResolve(); | ||
| } else { | ||
| visitChildren(); | ||
| } | ||
| }).catch(reject); | ||
| } else { | ||
| // Visitor returned true, indicating a desire to continue traversing. | ||
| visitChildren(); | ||
| } | ||
| }; | ||
| // Is this element a Component? | ||
| if (typeof currentElement.type === 'function') { | ||
| var Component = currentElement.type; | ||
| var props = Object.assign({}, Component.defaultProps, currentElement.props); | ||
| // Is this a class component? (http://bit.ly/2j9Ifk3) | ||
| var isReactClassComponent = Component.prototype && (Component.prototype.isReactComponent || Component.prototype.isPureReactComponent); | ||
| if (isReactClassComponent) { | ||
| // React class component | ||
| var instance = new Component(props, currentContext); | ||
| // In case the user doesn't pass these to super in the constructor | ||
| instance.props = instance.props || props; | ||
| instance.context = instance.context || currentContext; | ||
| // Make the setState synchronous. | ||
| instance.setState = function (newState) { | ||
| if (typeof newState === 'function') { | ||
| // eslint-disable-next-line no-param-reassign | ||
| newState = newState(instance.state, instance.props, instance.context); | ||
| } | ||
| instance.state = Object.assign({}, instance.state, newState); | ||
| }; | ||
| doVisit(function () { | ||
| // Call componentWillMount if it exists. | ||
| if (instance.componentWillMount) { | ||
| instance.componentWillMount(); | ||
| } | ||
| var children = instance.render(); | ||
| if (options.componentWillUnmount && instance.componentWillUnmount) { | ||
| try { | ||
| instance.componentWillUnmount(); | ||
| } catch (err) { | ||
| // This is an experimental feature, we don't want to break | ||
| // the bootstrapping process, but lets warn the user it | ||
| // occurred. | ||
| console.warn('Error calling componentWillUnmount whilst walking your react tree'); | ||
| console.warn(err); | ||
| } | ||
| } | ||
| return children; | ||
| }, safeVisitor(currentElement, instance, currentContext), function () { | ||
| return ( | ||
| // Ensure the child context is initialised if it is available. We will | ||
| // need to pass it down the tree. | ||
| instance.getChildContext ? Object.assign({}, currentContext, instance.getChildContext()) : currentContext | ||
| ); | ||
| }); | ||
| } else { | ||
| // Stateless Functional Component | ||
| doVisit(function () { | ||
| return Component(props, currentContext); | ||
| }, safeVisitor(currentElement, null, currentContext), currentContext); | ||
| } | ||
| } else { | ||
| // This must be a basic element, such as a string or dom node. | ||
| doVisit(function () { | ||
| return currentElement.props && currentElement.props.children ? currentElement.props.children : undefined; | ||
| }, safeVisitor(currentElement, null, currentContext), currentContext); | ||
| } | ||
| }); | ||
| }; | ||
| recursive(rootElement, rootContext).then(resolve, reject); | ||
| }); | ||
| } |
| (function webpackUniversalModuleDefinition(root, factory) { | ||
| if(typeof exports === 'object' && typeof module === 'object') | ||
| module.exports = factory(require("react")); | ||
| else if(typeof define === 'function' && define.amd) | ||
| define(["react"], factory); | ||
| else if(typeof exports === 'object') | ||
| exports["ReactTreeWalker"] = factory(require("react")); | ||
| else | ||
| root["ReactTreeWalker"] = factory(root["React"]); | ||
| })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) { | ||
| return /******/ (function(modules) { // webpackBootstrap | ||
| /******/ // The module cache | ||
| /******/ var installedModules = {}; | ||
| /******/ | ||
| /******/ // The require function | ||
| /******/ function __webpack_require__(moduleId) { | ||
| /******/ | ||
| /******/ // Check if module is in cache | ||
| /******/ if(installedModules[moduleId]) { | ||
| /******/ return installedModules[moduleId].exports; | ||
| /******/ } | ||
| /******/ // Create a new module (and put it into the cache) | ||
| /******/ var module = installedModules[moduleId] = { | ||
| /******/ i: moduleId, | ||
| /******/ l: false, | ||
| /******/ exports: {} | ||
| /******/ }; | ||
| /******/ | ||
| /******/ // Execute the module function | ||
| /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
| /******/ | ||
| /******/ // Flag the module as loaded | ||
| /******/ module.l = true; | ||
| /******/ | ||
| /******/ // Return the exports of the module | ||
| /******/ return module.exports; | ||
| /******/ } | ||
| /******/ | ||
| /******/ | ||
| /******/ // expose the modules object (__webpack_modules__) | ||
| /******/ __webpack_require__.m = modules; | ||
| /******/ | ||
| /******/ // expose the module cache | ||
| /******/ __webpack_require__.c = installedModules; | ||
| /******/ | ||
| /******/ // define getter function for harmony exports | ||
| /******/ __webpack_require__.d = function(exports, name, getter) { | ||
| /******/ if(!__webpack_require__.o(exports, name)) { | ||
| /******/ Object.defineProperty(exports, name, { | ||
| /******/ configurable: false, | ||
| /******/ enumerable: true, | ||
| /******/ get: getter | ||
| /******/ }); | ||
| /******/ } | ||
| /******/ }; | ||
| /******/ | ||
| /******/ // getDefaultExport function for compatibility with non-harmony modules | ||
| /******/ __webpack_require__.n = function(module) { | ||
| /******/ var getter = module && module.__esModule ? | ||
| /******/ function getDefault() { return module['default']; } : | ||
| /******/ function getModuleExports() { return module; }; | ||
| /******/ __webpack_require__.d(getter, 'a', getter); | ||
| /******/ return getter; | ||
| /******/ }; | ||
| /******/ | ||
| /******/ // Object.prototype.hasOwnProperty.call | ||
| /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||
| /******/ | ||
| /******/ // __webpack_public_path__ | ||
| /******/ __webpack_require__.p = ""; | ||
| /******/ | ||
| /******/ // Load entry module and return exports | ||
| /******/ return __webpack_require__(__webpack_require__.s = 0); | ||
| /******/ }) | ||
| /************************************************************************/ | ||
| /******/ ([ | ||
| /* 0 */ | ||
| /***/ (function(module, exports, __webpack_require__) { | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| exports.isPromise = undefined; | ||
| exports.default = reactTreeWalker; | ||
| var _react = __webpack_require__(1); | ||
| var defaultOptions = { | ||
| componentWillUnmount: false | ||
| // Lifted from https://github.com/sindresorhus/p-reduce | ||
| // Thanks @sindresorhus! | ||
| }; /* eslint-disable no-console */ | ||
| // Inspired by the awesome work done by the Apollo team. | ||
| // See https://github.com/apollostack/react-apollo/blob/master/src/server.ts | ||
| // This version has been adapted to be promise based. | ||
| // eslint-disable-next-line import/no-extraneous-dependencies | ||
| var pReduce = function pReduce(iterable, reducer, initVal) { | ||
| return new Promise(function (resolve, reject) { | ||
| var iterator = iterable[Symbol.iterator](); | ||
| var i = 0; | ||
| var next = function next(total) { | ||
| var el = iterator.next(); | ||
| if (el.done) { | ||
| resolve(total); | ||
| return; | ||
| } | ||
| Promise.all([total, el.value]).then(function (value) { | ||
| // eslint-disable-next-line no-plusplus | ||
| next(reducer(value[0], value[1], i++)); | ||
| }).catch(reject); | ||
| }; | ||
| next(initVal); | ||
| }); | ||
| }; | ||
| // Lifted from https://github.com/sindresorhus/p-map-series | ||
| // Thanks @sindresorhus! | ||
| var pMapSeries = function pMapSeries(iterable, iterator) { | ||
| var ret = []; | ||
| return pReduce(iterable, function (a, b, i) { | ||
| return Promise.resolve(iterator(b, i)).then(function (val) { | ||
| ret.push(val); | ||
| }); | ||
| }).then(function () { | ||
| return ret; | ||
| }); | ||
| }; | ||
| var ensureChild = function ensureChild(child) { | ||
| return child && typeof child.render === 'function' ? ensureChild(child.render()) : child; | ||
| }; | ||
| var isPromise = exports.isPromise = function isPromise(x) { | ||
| return x != null && typeof x.then === 'function'; | ||
| }; | ||
| // Recurse an React Element tree, running visitor on each element. | ||
| // If visitor returns `false`, don't call the element's render function | ||
| // or recurse into its child elements | ||
| function reactTreeWalker(rootElement, visitor, rootContext) { | ||
| var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultOptions; | ||
| return new Promise(function (resolve, reject) { | ||
| var safeVisitor = visitor.isSafe ? visitor : function () { | ||
| try { | ||
| return visitor.apply(undefined, arguments); | ||
| } catch (err) { | ||
| reject(err); | ||
| } | ||
| return undefined; | ||
| }; | ||
| var recursive = function recursive(currentElement, currentContext) { | ||
| return new Promise(function (innerResolve) { | ||
| var doVisit = function doVisit(getChildren, visitResult, childContext) { | ||
| var visitChildren = function visitChildren() { | ||
| var child = ensureChild(getChildren()); | ||
| var theChildContext = typeof childContext === 'function' ? childContext() : childContext; | ||
| if (child == null) { | ||
| // If no children then we can't traverse. We've reached the leaf. | ||
| innerResolve(); | ||
| } else if (_react.Children.count(child)) { | ||
| // If its a react Children collection we need to breadth-first | ||
| // traverse each of them. | ||
| var mapper = function mapper(aChild) { | ||
| return aChild ? recursive(aChild, theChildContext) : undefined; | ||
| }; | ||
| var children = _react.Children.map(child, function (cur) { | ||
| return cur; | ||
| }); | ||
| // pMapSeries allows us to do depth-first traversal. Thanks @sindresorhus! | ||
| pMapSeries(children, mapper).then(innerResolve, reject).catch(reject); | ||
| } else { | ||
| // Otherwise we pass the individual child to the next recursion. | ||
| recursive(child, theChildContext).then(innerResolve, reject).catch(reject); | ||
| } | ||
| }; | ||
| if (visitResult === false) { | ||
| // Visitor returned false, indicating a desire to not traverse. | ||
| innerResolve(); | ||
| } else if (isPromise(visitResult)) { | ||
| // We need to execute the result and pass it's result through to our | ||
| // continuer. | ||
| visitResult.then(function (promiseResult) { | ||
| if (promiseResult === false) { | ||
| innerResolve(); | ||
| } else { | ||
| visitChildren(); | ||
| } | ||
| }).catch(reject); | ||
| } else { | ||
| // Visitor returned true, indicating a desire to continue traversing. | ||
| visitChildren(); | ||
| } | ||
| }; | ||
| // Is this element a Component? | ||
| if (typeof currentElement.type === 'function') { | ||
| var Component = currentElement.type; | ||
| var props = Object.assign({}, Component.defaultProps, currentElement.props); | ||
| // Is this a class component? (http://bit.ly/2j9Ifk3) | ||
| var isReactClassComponent = Component.prototype && (Component.prototype.isReactComponent || Component.prototype.isPureReactComponent); | ||
| if (isReactClassComponent) { | ||
| // React class component | ||
| var instance = new Component(props, currentContext); | ||
| // In case the user doesn't pass these to super in the constructor | ||
| instance.props = instance.props || props; | ||
| instance.context = instance.context || currentContext; | ||
| // Make the setState synchronous. | ||
| instance.setState = function (newState) { | ||
| if (typeof newState === 'function') { | ||
| // eslint-disable-next-line no-param-reassign | ||
| newState = newState(instance.state, instance.props, instance.context); | ||
| } | ||
| instance.state = Object.assign({}, instance.state, newState); | ||
| }; | ||
| doVisit(function () { | ||
| // Call componentWillMount if it exists. | ||
| if (instance.componentWillMount) { | ||
| instance.componentWillMount(); | ||
| } | ||
| var children = instance.render(); | ||
| if (options.componentWillUnmount && instance.componentWillUnmount) { | ||
| try { | ||
| instance.componentWillUnmount(); | ||
| } catch (err) { | ||
| // This is an experimental feature, we don't want to break | ||
| // the bootstrapping process, but lets warn the user it | ||
| // occurred. | ||
| console.warn('Error calling componentWillUnmount whilst walking your react tree'); | ||
| console.warn(err); | ||
| } | ||
| } | ||
| return children; | ||
| }, safeVisitor(currentElement, instance, currentContext), function () { | ||
| return ( | ||
| // Ensure the child context is initialised if it is available. We will | ||
| // need to pass it down the tree. | ||
| instance.getChildContext ? Object.assign({}, currentContext, instance.getChildContext()) : currentContext | ||
| ); | ||
| }); | ||
| } else { | ||
| // Stateless Functional Component | ||
| doVisit(function () { | ||
| return Component(props, currentContext); | ||
| }, safeVisitor(currentElement, null, currentContext), currentContext); | ||
| } | ||
| } else { | ||
| // This must be a basic element, such as a string or dom node. | ||
| doVisit(function () { | ||
| return currentElement.props && currentElement.props.children ? currentElement.props.children : undefined; | ||
| }, safeVisitor(currentElement, null, currentContext), currentContext); | ||
| } | ||
| }); | ||
| }; | ||
| recursive(rootElement, rootContext).then(resolve, reject); | ||
| }); | ||
| } | ||
| /***/ }), | ||
| /* 1 */ | ||
| /***/ (function(module, exports) { | ||
| module.exports = __WEBPACK_EXTERNAL_MODULE_1__; | ||
| /***/ }) | ||
| /******/ ]); | ||
| }); |
| !function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactTreeWalker=t(require("react")):n.ReactTreeWalker=t(n.React)}(this,function(n){return function(n){function t(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var e={};return t.m=n,t.c=e,t.d=function(n,e,o){t.o(n,e)||Object.defineProperty(n,e,{configurable:!1,enumerable:!0,get:o})},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=0)}([function(n,t,e){"use strict";function o(n,t,e){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:i;return new Promise(function(i,u){var a=t.isSafe?t:function(){try{return t.apply(void 0,arguments)}catch(n){u(n)}};(function n(t,e){return new Promise(function(i){var p=function(t,e,o){var a=function(){var e=f(t()),l="function"==typeof o?o():o;if(null==e)i();else if(r.Children.count(e)){var a=function(t){return t?n(t,l):void 0},p=r.Children.map(e,function(n){return n});c(p,a).then(i,u).catch(u)}else n(e,l).then(i,u).catch(u)};!1===e?i():l(e)?e.then(function(n){!1===n?i():a()}).catch(u):a()};if("function"==typeof t.type){var s=t.type,d=Object.assign({},s.defaultProps,t.props);if(s.prototype&&(s.prototype.isReactComponent||s.prototype.isPureReactComponent)){var m=new s(d,e);m.props=m.props||d,m.context=m.context||e,m.setState=function(n){"function"==typeof n&&(n=n(m.state,m.props,m.context)),m.state=Object.assign({},m.state,n)},p(function(){m.componentWillMount&&m.componentWillMount();var n=m.render();if(o.componentWillUnmount&&m.componentWillUnmount)try{m.componentWillUnmount()}catch(n){console.warn("Error calling componentWillUnmount whilst walking your react tree"),console.warn(n)}return n},a(t,m,e),function(){return m.getChildContext?Object.assign({},e,m.getChildContext()):e})}else p(function(){return s(d,e)},a(t,null,e),e)}else p(function(){return t.props&&t.props.children?t.props.children:void 0},a(t,null,e),e)})})(n,e).then(i,u)})}Object.defineProperty(t,"__esModule",{value:!0}),t.isPromise=void 0,t.default=o;var r=e(1),i={componentWillUnmount:!1},u=function(n,t,e){return new Promise(function(o,r){var i=n[Symbol.iterator](),u=0;!function n(e){var c=i.next();if(c.done)return void o(e);Promise.all([e,c.value]).then(function(e){n(t(e[0],e[1],u++))}).catch(r)}(e)})},c=function(n,t){var e=[];return u(n,function(n,o,r){return Promise.resolve(t(o,r)).then(function(n){e.push(n)})}).then(function(){return e})},f=function n(t){return t&&"function"==typeof t.render?n(t.render()):t},l=t.isPromise=function(n){return null!=n&&"function"==typeof n.then}},function(t,e){t.exports=n}])}); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
0
-100%225
122.77%14059
-52.1%41
2.5%6
-14.29%47
-89.37%1
Infinity%