Compare commits

..
Author SHA1 Message Date
dependabot[bot] 20324bfd8a Bump handlebars from 4.5.3 to 4.7.7
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.5.3 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...v4.7.7)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-08 01:07:34 +00:00
bendtherules fdfd267d95 Merge pull request #4 from bendtherules/dependabot/npm_and_yarn/handlebars-4.5.3
Bump handlebars from 4.1.2 to 4.5.3
2020-01-14 23:38:30 +05:30
dependabot[bot] c2a6000887 Bump handlebars from 4.1.2 to 4.5.3
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-29 14:59:07 +00:00
bendtherules 473d7cc38e TODO - Ctach throw in generators gracefully 2019-09-21 13:01:22 +05:30
bendtherules 1efcb67c56 types - Remove duplicate 2019-09-21 13:00:40 +05:30
bendtherules f10c17bd53 TODO - Add concerns from temp hack in support-css 2019-09-21 10:17:25 +05:30
bendtherules e12438fd4f Release v0.0.8 2019-09-21 10:13:46 +05:30
bendtherules c92c64baa1 build - Support iterating over generators 2019-09-21 10:11:27 +05:30
bendtherules 986f2c0aac package.json - update css-what 2019-09-21 09:30:01 +05:30
bendtherules ef593615ad snaphot - Update snapshot size 2019-09-21 09:25:22 +05:30
bendtherules 2f28cd5eb0 match - Add testcase - negative check for difference between child and descendant 2019-09-20 11:32:47 +05:30
bendtherules c47a4dddbd match - Add css match functions with basic test cases 2019-09-20 11:27:55 +05:30
bendtherules 051bb1f543 traverseGenerator - Add skipSelfForStartNode start param to skip startNode (default:false)
Default false to keep current testcases running
2019-09-20 11:26:33 +05:30
bendtherules 7b27f9c5b7 package.json - Add --runInBand param to test:src:debug script 2019-09-20 11:24:05 +05:30
bendtherules f5c37dc251 temp commit 2019-09-18 11:36:09 +05:30
bendtherules 8c019a5fd2 TODO - COntinue FiberNode selection with css dom selection 2019-09-12 13:55:28 +05:30
bendtherules be7ec5d869 TODO - Query helper also for CLass/Function 2019-09-12 13:53:03 +05:30
bendtherules 6bb43e34e2 TODO - Add CSS, props 2019-09-12 13:51:12 +05:30
bendtherules d630d21b23 TODO - Mark some done 2019-09-12 13:47:49 +05:30
bendtherules 693dd69d32 findNode - Add findNodesByComponentName and findAllNodesByComponentName 2019-09-12 13:46:33 +05:30
bendtherules f01ae4fb2a TODO - Write test for traverseConfig changes 2019-09-11 17:02:53 +05:30
bendtherules 1ef5941a9e findNode* - Support traverseConfig 2019-09-11 16:54:53 +05:30
bendtherules e7e969cf65 traverse - Support traverseConfig 2019-09-11 16:54:32 +05:30
bendtherules 8326ec5bf7 traverseGenerator - Refactor config argument type to separate interface 2019-09-11 16:50:00 +05:30
bendtherules 0bc8c1af99 traverseGenerator - Add option to skip traversing siblings for first node
Which is usually expected, when we think of it as a recursive traversal
2019-09-11 16:18:40 +05:30
bendtherules aced1be6e8 Rewrite traverse.traverse using traverseGenerator 2019-09-11 15:13:21 +05:30
bendtherules 492e69f4dd traverse - Arrange functions in file 2019-09-11 14:58:13 +05:30
bendtherules 94ab7112f7 traverse - Fix prettier formatting 2019-09-11 14:50:28 +05:30
bendtherules 808ed790f3 jsdoc - Add spearator between examples of a function 2019-09-11 14:48:50 +05:30
bendtherules 817242dd25 traverseGenerator - Mark properties in yield object optional 2019-09-11 08:58:17 +05:30
bendtherules 827b282064 ts - Fix vscode version to workspace ts version 2019-09-11 08:57:12 +05:30
bendtherules c71b9ad531 Doc - Add doc for traverseGenerator with example 2019-09-11 08:55:13 +05:30
bendtherules 01e6932cd5 Docs - Update built docs 2019-09-09 18:41:32 +05:30
bendtherules 215153c516 Docs - Add doc for traverse.traverse method 2019-09-09 18:41:13 +05:30
bendtherules fd6dad21ad TODO - rewrite find using generators 2019-09-09 18:30:36 +05:30
bendtherules 30b1bfefea Docs - Update built docs 2019-09-09 18:20:17 +05:30
bendtherules e870a92e4b TODO - Skip sibling 2019-09-09 18:20:02 +05:30
bendtherules 6cffc96d60 Docs - In findNode, move exmaples above note section 2019-09-09 18:19:30 +05:30
bendtherules 4824828b51 Docs - Update built docs 2019-09-09 18:16:42 +05:30
bendtherules 5a2e7f1375 Docs - In findNode, fix example tag code blocks 2019-09-09 18:16:04 +05:30
bendtherules 977a376cad Docs - Update built docs 2019-09-09 17:43:58 +05:30
bendtherules 21231fcb11 Docs - Added for findNode methods 2019-09-09 17:41:58 +05:30
bendtherules b09af700c9 TODO - All optional root node in method params 2019-09-09 16:16:46 +05:30
bendtherules 55152a1be7 Readme - Add testing concern 2019-09-04 11:32:21 +05:30
bendtherules 8a69d1f1ca Docs - Add overview, concern and typedoc file link 2019-09-04 11:29:35 +05:30
bendtherules c40fc9b2c4 Release v0.0.7 2019-09-04 10:51:02 +05:30
bendtherules 18ea2e7d2a package.json - Add docs generation to publish task 2019-09-04 10:46:41 +05:30
bendtherules e01fc3ab0b Release v0.0.6 2019-08-29 17:37:45 +05:30
bendtherules ba2e842338 Readme - Update example with proper working code and CSB link 2019-08-29 17:36:17 +05:30
bendtherules b16012f81e Release v0.0.5 2019-08-29 17:10:43 +05:30
bendtherules 113674df2f Update package-lock 2019-08-29 17:09:25 +05:30
bendtherules 88eb62298e Release v0.0.4 2019-08-29 17:01:43 +05:30
bendtherules 8e484fc074 TODO - findAllNodes added 2019-08-28 09:01:16 +05:30
bendtherules a88e0e0f07 Readme - Update with correct import statements 2019-08-28 09:00:57 +05:30
bendtherules a1204cfc1b lib - export utils from main export 2019-08-27 22:58:47 +05:30
bendtherules ceaa1eee32 TODO - Separate out major compatibility changes into diff item 2019-08-25 17:26:28 +05:30
bendtherules 3c5ea67992 Add testcase - traverseGenerator-skipped
Some simple cases covered. Needs more thought out cases with combination
2019-08-11 22:12:23 +05:30
bendtherules 395dc281ce test.traverseGenerator-ordered - Fix test group title 2019-08-11 20:19:13 +05:30
bendtherules 3e062ef911 Add testcase - getRootFiberNodeFromDOM - without any element as input 2019-08-10 17:20:20 +05:30
bendtherules e3750e9b50 Add TODO for getRootFiberNodeFromDOM changes needed (skip-ci) 2019-08-10 17:13:40 +05:30
bendtherules e1dec601e7 Add testcases - utils.getRootFiberNodeFromDOM 2019-08-10 17:08:32 +05:30
bendtherules d6d32fd847 Add testcase - utils.doesElementContainRootFiberNode 2019-08-10 16:17:01 +05:30
bendtherules 7aff88ecb8 package.json - Remove post-commit hook 2019-08-10 13:49:28 +05:30
bendtherules 400757182f Modify lint-staged - Run prettier and eslint only on changed files 2019-08-10 13:46:21 +05:30
bendtherules 6cd41bc4bd Modify 'lint' cmd - Run eslint for jsx.tsx also 2019-08-10 13:04:17 +05:30
bendtherules 5a33b3272e utils - export doesElementContainRootFiberNode 2019-08-10 13:01:07 +05:30
bendtherules e7e1415039 Add testcases - utils.isConstructorComponentClass 2019-08-10 12:59:40 +05:30
bendtherules 7e676b0edc Add testcases - utils.isConstructorFunctionComponent 2019-08-10 12:58:46 +05:30
bendtherules 9ebc534cc3 Modify isConstructorFunctionComponent - Check type is function 2019-08-10 12:54:30 +05:30
bendtherules d7276eff9e Modify utils.isConstructor* - Allow null type as input 2019-08-10 11:26:39 +05:30
bendtherules c5adcb3152 Add testcase - utils.isConstructorHtmlLike 2019-08-10 10:49:33 +05:30
bendtherules e64d51a3e6 Modify util.isConstructorHtmlLike - Allow null typeas input 2019-08-10 10:46:42 +05:30
bendtherules 887f4b95d1 Modify utils - doesElementContainRootFiberNode also checks for _internalRoot now 2019-08-10 10:37:12 +05:30
bendtherules 39080755ef Add testcase - isNodeComponentClass 2019-08-10 09:58:15 +05:30
bendtherules 69c1d2db86 Edit test title in utils.isNodeFunctionComponent 2019-08-10 01:49:40 +05:30
bendtherules 86216d3b05 Add testcase - utils.isNodeHtmlLike - Add negative test cases where it is false 2019-08-10 01:44:39 +05:30
bendtherules 933639e0ba Add testcase - utils.isNodeFunctionComponent 2019-08-10 01:43:14 +05:30
bendtherules 91ab867f19 Update package-lock 2019-08-09 23:02:15 +05:30
bendtherules 8f29fd8eea Fix prettier - mountInEnzyme
Was missed due to non-installation of husky in this machine
2019-08-09 23:00:08 +05:30
bendtherules c3ca45928a Add testcase - utils.isNodeHtmlLike
Tests isNodeHtmlLike and isNodeNotHtmlLike
2019-08-09 22:28:02 +05:30
bendtherules 2aa7a9bbf3 Test utils - mountInEnzyme - support loading intrinsic elements 2019-08-09 22:10:08 +05:30
bendtherules fb23260efe Add testcase - findNodeByComponentRef-negative
Check cases where ref is not found in fiber tree
2019-08-09 11:54:50 +05:30
bendtherules 6f5826d398 Add testcase - findNodeByComponent-negative
Test cases where component is not found
2019-08-09 10:05:24 +05:30
44 changed files with 4566 additions and 297 deletions
+18 -18
View File
@@ -1,36 +1,36 @@
{
"dist/react-fiber-traverse.cjs.development.js": {
"bundled": 7398,
"minified": 3036,
"gzipped": 967
"bundled": 19424,
"minified": 8388,
"gzipped": 2612
},
"dist/react-fiber-traverse.cjs.production.js": {
"bundled": 7398,
"minified": 3036,
"gzipped": 967
"bundled": 19424,
"minified": 8388,
"gzipped": 2612
},
"dist/react-fiber-traverse.esm.js": {
"bundled": 7048,
"minified": 2736,
"gzipped": 869,
"bundled": 19124,
"minified": 8112,
"gzipped": 2537,
"treeshaked": {
"rollup": {
"code": 49,
"import_statements": 49
"code": 31,
"import_statements": 31
},
"webpack": {
"code": 1066
"code": 1048
}
}
},
"dist/react-fiber-traverse.umd.development.js": {
"bundled": 32560,
"minified": 8698,
"gzipped": 3085
"bundled": 34569,
"minified": 11581,
"gzipped": 4230
},
"dist/react-fiber-traverse.umd.production.js": {
"bundled": 32560,
"minified": 8698,
"gzipped": 3085
"bundled": 34569,
"minified": 11581,
"gzipped": 4230
}
}
+2 -1
View File
@@ -13,5 +13,6 @@
"javascriptreact",
"typescript",
"typescriptreact"
]
],
"typescript.tsdk": "node_modules\\typescript\\lib"
}
+58 -16
View File
@@ -10,29 +10,39 @@
## Basic Usage
```ts
import { render } from 'react-dom'
import React from "react";
import { render } from "react-dom";
import { findNodeByComponentName } from 'react-fiber-traverse'
import { getRootFiberNodeFromDOM } from 'react-fiber-traverse/utils'
import { findNodeByComponentName, Utils } from "react-fiber-traverse";
const rootElement = document.getElementById('root');
render(<App>, 'root');
// Sample component
// Say, if SomeComponentName looks like this -
function SomeComponentName() {
return <div>Some text</div>;
}
const rootFiberNode = getRootFiberNodeFromDOM(rootElement);
// Render component
const rootElement = document.getElementById("root");
render(<SomeComponentName />, rootElement);
// Get root node
const rootFiberNode = Utils.getRootFiberNodeFromDOM(rootElement);
// Get component node
const someFiberNode = findNodeByComponentName(
rootFiberNode,
"SomeComponentName"
); // <- returns FiberNode for first usage of 'SomeComponentName'
console.log(someFiberNode.child.stateNode); // <- returns reference to the div
console.log(someFiberNode.child.stateNode.innerText); // <- returns 'Some text'
const someFiberNode = findNodeByComponentName(rootFiberNode, 'SomeComponentName'); // <- returns FiberNode for first usage of 'SomeComponentName'
// Say, if SomeComponentName renders (<div>Some text</div>)
someFiberNode.stateNode // <- returns reference to the div
someFiberNode.stateNode.innerText // <- returns 'Some text'
```
## Live Examples
- [Basic Usage](https://codesandbox.io/)
- [API Example](https://codesandbox.io/)
- [UMD Build (Development)](https://codesandbox.io/)
- [UMD Build (Production)](https://codesandbox.io/)
- [Basic Usage](https://codesandbox.io/s/react-example-x82zk?expanddevtools=1&fontsize=14)
<!--
## API
**Props**
@@ -43,7 +53,7 @@ someFiberNode.stateNode.innerText // <- returns 'Some text'
**Example**
```jsx
```
``` -->
## Installation
@@ -66,6 +76,38 @@ For the minified production version, make sure you have already included:
- [`React`](https://unpkg.com/react/umd/react.production.min.js)
- [`ReactDOM`](https://unpkg.com/react-dom/umd/react-dom.production.min.js)
## Overview
This package contains few utility functions which operate over react-fiber tree.
Overall characteristics are:
1. Only read-only operations
2. Support inversion of control
There are few categories of helpers, each with their variations:
1. Find node(s)
2. Traverse node
3. Others - Check node type, find root node, etc.
Little more info is present in docs section.
## Concerns and improvements
Currently, it assumes that nodes are created by `react 16.3+` with appropriate `react-dom`.
Because fiber nodes are internal to react and are supported by multiple renderers, this is an incorrect assumption to make. It should:
1. support diff versions of react (which have fiber node, but slight variations of it)
2. be renderer-agnostic (say, support react-fs-renderer) but with extra helpers for react-dom.
3. heavily tested with all these variations (to know when internals have changed).
## Docs
Docs are sparse at the moment. I plan on adding them soon.
Till then, the auto-generated (typedoc) docs available in [docs folder](./docs/globals.md) might be of some help.
## License
MIT
+21 -9
View File
@@ -1,16 +1,28 @@
# TODOs
1. Write docs and examples
2. Reduce testcase boilerplate code for similar tests
3. Publish to npm
4. Build some demo
5. Pack separate files
5. Add `findAllNodes` helpers which searches all usages of the components - by name or class
6. Allow using all methods without explicit root node. Find automatically, if not provided.
Affected parts
---------------
a. Rollup config (input and output) X
b. package.json entrypoints X
c. root index.js for dynamic prod or dev redirection X
d. change unpkg links in readme
e. separate folder for types ?? (change tsconfig)
6. Fix getRootFiberNodeFromDOM and related helpers -
- .\_internalRoot is not present is 16.0.0 but present in 16.9.0
- actual node is available 2 levels nested inside this root node
- add testcase to run across all versions of React 16.0.0 (dev+prod) and above (because internals change)
f. Enable umd build from one index file
7. Make it work with older React versions
8. Make it work with non React-DOM renderers
9. Add test - traverseGenerator - siblings were traversed earlier, not now. Check input config.
10. Find node by CSS (query language) - Make it work for Class/Function reference also
11. Allow easy way to continue FiberNode select with CSS selector for dom node (handling Fragments)
12. Helper and filter by props and state
13. Fix es5, downLevelIteration with generator iteration
14. Tests for match
15. **Catch throw in generator**
+60 -11
View File
@@ -13,20 +13,40 @@
## Basic Usage
```jsx
import React from 'react'
import { render } from 'react-dom'
```ts
import React from "react";
import { render } from "react-dom";
import { findNodeByComponentName, Utils } from "react-fiber-traverse";
// Sample component
// Say, if SomeComponentName looks like this -
function SomeComponentName() {
return <div>Some text</div>;
}
// Render component
const rootElement = document.getElementById("root");
render(<SomeComponentName />, rootElement);
// Get root node
const rootFiberNode = Utils.getRootFiberNodeFromDOM(rootElement);
// Get component node
const someFiberNode = findNodeByComponentName(
rootFiberNode,
"SomeComponentName"
); // <- returns FiberNode for first usage of 'SomeComponentName'
console.log(someFiberNode.child.stateNode); // <- returns reference to the div
console.log(someFiberNode.child.stateNode.innerText); // <- returns 'Some text'
render(, document.getElementById('root'))
```
## Live Examples
- [Basic Usage](https://codesandbox.io/)
- [API Example](https://codesandbox.io/)
- [UMD Build (Development)](https://codesandbox.io/)
- [UMD Build (Production)](https://codesandbox.io/)
- [Basic Usage](https://codesandbox.io/s/react-example-x82zk?expanddevtools=1&fontsize=14)
<!--
## API
**Props**
@@ -37,7 +57,7 @@ render(, document.getElementById('root'))
**Example**
```jsx
```
``` -->
## Installation
@@ -54,13 +74,42 @@ For the non-minified development version, make sure you have already included:
- [`React`](https://unpkg.com/react/umd/react.development.js)
- [`ReactDOM`](https://unpkg.com/react-dom/umd/react-dom.development.js)
- [`PropTypes`](https://unpkg.com/prop-types/prop-types.js)
For the minified production version, make sure you have already included:
- [`React`](https://unpkg.com/react/umd/react.production.min.js)
- [`ReactDOM`](https://unpkg.com/react-dom/umd/react-dom.production.min.js)
## Overview
This package contains few utility functions which operate over react-fiber tree.
Overall characteristics are:
1. Only read-only operations
2. Support inversion of control
There are few categories of helpers, each with their variations:
1. Find node(s)
2. Traverse node
3. Others - Check node type, find root node, etc.
Little more info is present in docs section.
## Concerns and improvements
Currently, it assumes that nodes are created by `react 16.3+` with appropriate `react-dom`.
Because fiber nodes are internal to react and are supported by multiple renderers, this is an incorrect assumption to make. It should:
1. support diff versions of react (which have fiber node, but slight variations of it)
2. be renderer-agnostic (say, support react-fs-renderer) but with extra helpers for react-dom.
3. heavily tested with all these variations (to know when internals have changed).
## Docs
Docs are sparse at the moment. I plan on adding them soon.
Till then, the auto-generated (typedoc) docs available in [docs folder](./docs/globals.md) might be of some help.
## License
MIT
+1
View File
@@ -10,6 +10,7 @@
* ["findNode"](modules/_findnode_.md)
* ["index"](modules/_index_.md)
* ["match"](modules/_match_.md)
* ["mocked-types/index"](modules/_mocked_types_index_.md)
* ["traverse"](modules/_traverse_.md)
* ["utils"](modules/_utils_.md)
File diff suppressed because it is too large Load Diff
@@ -24,7 +24,7 @@
**child**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:20](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L20)*
*Defined in [mocked-types/index.ts:28](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L28)*
___
@@ -32,7 +32,7 @@ ___
**elementType**: *`ComponentClass`*
*Defined in [mocked-types/index.ts:23](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L23)*
*Defined in [mocked-types/index.ts:31](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L31)*
___
@@ -40,7 +40,7 @@ ___
**sibling**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:21](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L21)*
*Defined in [mocked-types/index.ts:29](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L29)*
___
@@ -48,7 +48,7 @@ ___
**stateNode**: *`Component`*
*Defined in [mocked-types/index.ts:26](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L26)*
*Defined in [mocked-types/index.ts:34](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L34)*
___
@@ -56,4 +56,4 @@ ___
**type**: *`ComponentClass`*
*Defined in [mocked-types/index.ts:24](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L24)*
*Defined in [mocked-types/index.ts:32](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L32)*
@@ -24,7 +24,7 @@
**child**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:10](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L10)*
*Defined in [mocked-types/index.ts:18](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L18)*
___
@@ -32,7 +32,7 @@ ___
**elementType**: *`FunctionComponent`*
*Defined in [mocked-types/index.ts:13](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L13)*
*Defined in [mocked-types/index.ts:21](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L21)*
___
@@ -40,7 +40,7 @@ ___
**sibling**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:11](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L11)*
*Defined in [mocked-types/index.ts:19](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L19)*
___
@@ -48,7 +48,7 @@ ___
**stateNode**: *null*
*Defined in [mocked-types/index.ts:16](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L16)*
*Defined in [mocked-types/index.ts:24](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L24)*
___
@@ -56,4 +56,4 @@ ___
**type**: *`FunctionComponent`*
*Defined in [mocked-types/index.ts:14](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L14)*
*Defined in [mocked-types/index.ts:22](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L22)*
@@ -24,9 +24,9 @@
**child**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:30](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L30)*
*Defined in [mocked-types/index.ts:38](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L38)*
*Defined in [mocked-types/index.ts:40](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L40)*
*Defined in [mocked-types/index.ts:48](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L48)*
___
@@ -34,9 +34,9 @@ ___
**elementType**: *keyof IntrinsicElements*
*Defined in [mocked-types/index.ts:33](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L33)*
*Defined in [mocked-types/index.ts:41](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L41)*
*Defined in [mocked-types/index.ts:43](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L43)*
*Defined in [mocked-types/index.ts:51](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L51)*
___
@@ -44,9 +44,9 @@ ___
**sibling**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:31](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L31)*
*Defined in [mocked-types/index.ts:39](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L39)*
*Defined in [mocked-types/index.ts:41](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L41)*
*Defined in [mocked-types/index.ts:49](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L49)*
___
@@ -54,9 +54,9 @@ ___
**stateNode**: *`HTMLElement`*
*Defined in [mocked-types/index.ts:36](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L36)*
*Defined in [mocked-types/index.ts:44](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L44)*
*Defined in [mocked-types/index.ts:46](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L46)*
*Defined in [mocked-types/index.ts:54](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L54)*
___
@@ -64,6 +64,6 @@ ___
**type**: *keyof IntrinsicElements*
*Defined in [mocked-types/index.ts:34](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L34)*
*Defined in [mocked-types/index.ts:42](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L42)*
*Defined in [mocked-types/index.ts:44](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L44)*
*Defined in [mocked-types/index.ts:52](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L52)*
@@ -24,7 +24,7 @@
**child**: *null*
*Defined in [mocked-types/index.ts:50](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L50)*
*Defined in [mocked-types/index.ts:58](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L58)*
___
@@ -32,7 +32,7 @@ ___
**elementType**: *null*
*Defined in [mocked-types/index.ts:53](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L53)*
*Defined in [mocked-types/index.ts:61](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L61)*
___
@@ -40,7 +40,7 @@ ___
**sibling**: *[FiberNode](../modules/_mocked_types_index_.md#fibernode) | null*
*Defined in [mocked-types/index.ts:51](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L51)*
*Defined in [mocked-types/index.ts:59](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L59)*
___
@@ -48,7 +48,7 @@ ___
**stateNode**: *`Text`*
*Defined in [mocked-types/index.ts:56](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L56)*
*Defined in [mocked-types/index.ts:64](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L64)*
___
@@ -56,4 +56,4 @@ ___
**type**: *null*
*Defined in [mocked-types/index.ts:54](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L54)*
*Defined in [mocked-types/index.ts:62](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L62)*
@@ -0,0 +1,41 @@
> **[react-fiber-traverse](../README.md)**
[Globals](../globals.md) / ["traverse"](../modules/_traverse_.md) / [TTraverseConfig](_traverse_.ttraverseconfig.md) /
# Interface: TTraverseConfig
## Hierarchy
* **TTraverseConfig**
## Index
### Properties
* [order](_traverse_.ttraverseconfig.md#optional-order)
* [skipSelfForStartNode](_traverse_.ttraverseconfig.md#optional-skipselfforstartnode)
* [skipSiblingForStartNode](_traverse_.ttraverseconfig.md#optional-skipsiblingforstartnode)
## Properties
### `Optional` order
**order**? : *`Array<"self" | "child" | "sibling">`*
*Defined in [traverse.ts:5](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/traverse.ts#L5)*
___
### `Optional` skipSelfForStartNode
**skipSelfForStartNode**? : *undefined | false | true*
*Defined in [traverse.ts:7](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/traverse.ts#L7)*
___
### `Optional` skipSiblingForStartNode
**skipSiblingForStartNode**? : *undefined | false | true*
*Defined in [traverse.ts:6](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/traverse.ts#L6)*
+108 -22
View File
@@ -8,34 +8,19 @@
### Functions
* [findAllNodesByComponentName](_findnode_.md#findallnodesbycomponentname)
* [findNodeByComponent](_findnode_.md#findnodebycomponent)
* [findNodeByComponentName](_findnode_.md#findnodebycomponentname)
* [findNodeByComponentRef](_findnode_.md#findnodebycomponentref)
* [findNodesByComponentName](_findnode_.md#findnodesbycomponentname)
## Functions
### findNodeByComponent
### findAllNodesByComponentName
**findNodeByComponent**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedClassOrFunction`: `React.ComponentType`): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
**findAllNodesByComponentName**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedName`: string, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *`Array<FiberNode>`*
*Defined in [findNode.ts:32](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/findNode.ts#L32)*
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedClassOrFunction` | `React.ComponentType` |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
___
### findNodeByComponentName
**findNodeByComponentName**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedName`: string): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [findNode.ts:4](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/findNode.ts#L4)*
*Defined in [findNode.ts:58](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/findNode.ts#L58)*
**Parameters:**
@@ -43,6 +28,74 @@ Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedName` | string |
`traverseConfig?` | [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md) |
**Returns:** *`Array<FiberNode>`*
___
### findNodeByComponent
**findNodeByComponent**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedClassOrFunction`: `React.ComponentType`, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [findNode.ts:84](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/findNode.ts#L84)*
Find node by component (i.e. class or function by reference), till first match.
Matches against class and function by reference.
Returns null if no match is found.
**`example`**
```js
// returns FiberNode for first usage of AccordionMenu
findNodeByComponent(startNode, AccordionMenu);
```
**`note`** Medium chance of collision, medium data access needed.
This is safer than findNodeByComponentName, as different components with the same name won't collide.
But, two instances of the same component will still collide.
Needs access to component class or function.
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedClassOrFunction` | `React.ComponentType` |
`traverseConfig?` | [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md) |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
___
### findNodeByComponentName
**findNodeByComponentName**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedName`: string, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [findNode.ts:22](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/findNode.ts#L22)*
Find node by component name, till first match.
Matches against class and function name, doesn't match html-like nodes.
Returns null if no match is found.
**`example`**
```js
// returns FiberNode for first usage of 'AccordionMenu'
findNodeByComponentName(startNode, "AccordionMenu");
```
**`note`** Highest chance of collision, least data access needed.
Different components with same name will collide.
Needs access to component name.
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedName` | string |
`traverseConfig?` | [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md) |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
@@ -50,9 +103,23 @@ ___
### findNodeByComponentRef
**findNodeByComponentRef**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedClassInstance`: `Component`): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
**findNodeByComponentRef**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedClassInstance`: `Component`, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [findNode.ts:63](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/findNode.ts#L63)*
*Defined in [findNode.ts:122](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/findNode.ts#L122)*
Find node by component instance ref, till first match.
Matches against class instances by reference.
Returns null if no match is found.
**`example`**
```js
// menuRef=createRef(); <AccordionMenu ref={menuRef}>
findNodeByComponentRef(startNode, menuRef.current);
```
**`note`** Least chance of collision, maximum data access needed.
Needs access to component instance (through React ref usually).
**Parameters:**
@@ -60,5 +127,24 @@ Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedClassInstance` | `Component` |
`traverseConfig?` | [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md) |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
___
### findNodesByComponentName
**findNodesByComponentName**(`node`: [FiberNode](_mocked_types_index_.md#fibernode) | null, `expectedName`: string, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *`IterableIterator<FiberNode>`*
*Defined in [findNode.ts:41](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/findNode.ts#L41)*
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) \| null |
`expectedName` | string |
`traverseConfig?` | [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md) |
**Returns:** *`IterableIterator<FiberNode>`*
+64
View File
@@ -0,0 +1,64 @@
> **[react-fiber-traverse](../README.md)**
[Globals](../globals.md) / ["match"](_match_.md) /
# External module: "match"
## Index
### Functions
* [matchAll](_match_.md#matchall)
* [matchFirst](_match_.md#matchfirst)
* [matchGenerator](_match_.md#matchgenerator)
## Functions
### matchAll
**matchAll**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `match`: string | `CSSWhat.Selector`[][]): *`Array<FiberNode>`*
*Defined in [match.ts:115](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/match.ts#L115)*
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) |
`match` | string \| `CSSWhat.Selector`[][] |
**Returns:** *`Array<FiberNode>`*
___
### matchFirst
**matchFirst**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `match`: string | `CSSWhat.Selector`[][]): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [match.ts:122](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/match.ts#L122)*
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) |
`match` | string \| `CSSWhat.Selector`[][] |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
___
### matchGenerator
**matchGenerator**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `match`: string | `CSSWhat.Selector`[][]): *`IterableIterator<FiberNode>`*
*Defined in [match.ts:6](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/match.ts#L6)*
**Parameters:**
Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) |
`match` | string \| `CSSWhat.Selector`[][] |
**Returns:** *`IterableIterator<FiberNode>`*
+3 -2
View File
@@ -8,6 +8,7 @@
### Interfaces
* [FiberNodeDOMContainer](../interfaces/_mocked_types_index_.fibernodedomcontainer.md)
* [FiberNodeForComponentClass](../interfaces/_mocked_types_index_.fibernodeforcomponentclass.md)
* [FiberNodeForFunctionComponent](../interfaces/_mocked_types_index_.fibernodeforfunctioncomponent.md)
* [FiberNodeForInstrinsicElement](../interfaces/_mocked_types_index_.fibernodeforinstrinsicelement.md)
@@ -24,7 +25,7 @@
Ƭ **FiberNode**: *[FiberNodeForComponentClass](../interfaces/_mocked_types_index_.fibernodeforcomponentclass.md) | [FiberNodeForFunctionComponent](../interfaces/_mocked_types_index_.fibernodeforfunctioncomponent.md) | [FiberNodeForInstrinsicElement](../interfaces/_mocked_types_index_.fibernodeforinstrinsicelement.md) | [FiberNodeForTextNode](../interfaces/_mocked_types_index_.fibernodefortextnode.md)*
*Defined in [mocked-types/index.ts:3](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L3)*
*Defined in [mocked-types/index.ts:11](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L11)*
___
@@ -32,4 +33,4 @@ ___
Ƭ **FiberNodeisHTMLLike**: *[FiberNodeForInstrinsicElement](../interfaces/_mocked_types_index_.fibernodeforinstrinsicelement.md) | [FiberNodeForTextNode](../interfaces/_mocked_types_index_.fibernodefortextnode.md)*
*Defined in [mocked-types/index.ts:59](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/mocked-types/index.ts#L59)*
*Defined in [mocked-types/index.ts:67](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/mocked-types/index.ts#L67)*
+80 -3
View File
@@ -6,6 +6,10 @@
## Index
### Interfaces
* [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)
### Functions
* [traverse](_traverse_.md#traverse)
@@ -15,9 +19,21 @@
### traverse
**traverse**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `fn`: function): *void*
**traverse**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `fn`: function, `traverseConfig?`: [TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)): *void*
*Defined in [traverse.ts:4](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/traverse.ts#L4)*
*Defined in [traverse.ts:146](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/traverse.ts#L146)*
Traverse nodes recursively in depth-first manner, starting from a start node.
This is the default and basic traversal function, which covers basic use cases.
You can't do advanced things like change the order of traversal, skip or cancel traversal after any node, etc.
For more advanced usecases, see [traverseGenerator](_traverse_.md#traversegenerator)
**`example`**
```js
// calls fn for each node inside startNode
traverse(startNode, fn);
```
**Parameters:**
@@ -33,6 +49,8 @@ Name | Type |
------ | ------ |
`node` | [FiberNode](_mocked_types_index_.md#fibernode) |
`Optional` **traverseConfig**: *[TTraverseConfig](../interfaces/_traverse_.ttraverseconfig.md)*
**Returns:** *void*
___
@@ -41,7 +59,64 @@ ___
**traverseGenerator**(`node`: [FiberNode](_mocked_types_index_.md#fibernode), `__namedParameters`: object): *`IterableIterator<FiberNode>`*
*Defined in [traverse.ts:15](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/traverse.ts#L15)*
*Defined in [traverse.ts:69](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/traverse.ts#L69)*
Traverse nodes recursively using generators.
This is the advanced traverse function, which can be used used
to write other variants of traversal and find.
Type signature for generator.next first argument is `{ skipChild?: boolean; skipSibling?: boolean } | void `
Throw any error into the generator to finish the generator and let it cleanup its internals.
It allows inversion of control -
so, application code can decide to
1. change order of traversal,
2. skip some elements,
3. cancel traversal mid-way.
**`example`**
```js
// Basic use (for-of)
const nodeIterator = traverseGenerator(rootNode);
for (const node of nodeIterator) {
// do something with each node here
}
```
------
**`example`**
```js
// Breadth-first
// note the order below
const nodeIterator = traverseGenerator(rootNode, ["self", "sibling", "child"]);
// rest - same as above
```
-----
**`example`**
```js
// Get first 3 nodes and then stop the generator
const nodeIterator = traverseGenerator(rootNode);
var count = 0;
var next;
while (
count < 3 &&
!(next = nodeIterator.next()).done
) {
count++;
const node = next.value;
// do something with each node here
}
// Finish generator, to prevent memory leak
nodeIterator.throw(new Error());
```
-----
**Parameters:**
@@ -52,5 +127,7 @@ ___
Name | Type | Default |
------ | ------ | ------ |
`order` | "self" \| "child" \| "sibling"[] | ["self", "child", "sibling"] |
`skipSelfForStartNode` | boolean | false |
`skipSiblingForStartNode` | boolean | true |
**Returns:** *`IterableIterator<FiberNode>`*
+51 -14
View File
@@ -8,6 +8,8 @@
### Functions
* [doesElementContainRootFiberNode](_utils_.md#doeselementcontainrootfibernode)
* [getRootFiberNodeFromDOM](_utils_.md#getrootfibernodefromdom)
* [isConstructorComponentClass](_utils_.md#isconstructorcomponentclass)
* [isConstructorFunctionComponent](_utils_.md#isconstructorfunctioncomponent)
* [isConstructorHtmlLike](_utils_.md#isconstructorhtmllike)
@@ -18,17 +20,52 @@
## Functions
### isConstructorComponentClass
### doesElementContainRootFiberNode
**isConstructorComponentClass**(`ctr`: `React.ElementType`): *boolean*
**doesElementContainRootFiberNode**(`element`: `Element`): *boolean*
*Defined in [utils.ts:40](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L40)*
*Defined in [utils.ts:65](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L65)*
**Parameters:**
Name | Type |
------ | ------ |
`ctr` | `React.ElementType` |
`element` | `Element` |
**Returns:** *boolean*
___
### getRootFiberNodeFromDOM
**getRootFiberNodeFromDOM**(`startElement?`: [Element](../interfaces/_mocked_types_index_.fibernodedomcontainer.md#element)): *[FiberNode](_mocked_types_index_.md#fibernode) | null*
*Defined in [utils.ts:82](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L82)*
Util to find root React Fiber node from html DOM tree.
Returns null, if not found.SHould be called after ReactDOM.render is finished.
**Parameters:**
Name | Type | Description |
------ | ------ | ------ |
`startElement?` | [Element](../interfaces/_mocked_types_index_.fibernodedomcontainer.md#element) | Starting DOM element to seach from. If not found, it checks inside its child nodes. Defaults to document.body |
**Returns:** *[FiberNode](_mocked_types_index_.md#fibernode) | null*
___
### isConstructorComponentClass
**isConstructorComponentClass**(`ctr`: `React.ElementType` | null): *boolean*
*Defined in [utils.ts:42](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L42)*
**Parameters:**
Name | Type |
------ | ------ |
`ctr` | `React.ElementType` \| null |
**Returns:** *boolean*
@@ -36,15 +73,15 @@ ___
### isConstructorFunctionComponent
**isConstructorFunctionComponent**(`ctr`: `React.ElementType`): *boolean*
**isConstructorFunctionComponent**(`ctr`: `React.ElementType` | null): *boolean*
*Defined in [utils.ts:57](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L57)*
*Defined in [utils.ts:59](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L59)*
**Parameters:**
Name | Type |
------ | ------ |
`ctr` | `React.ElementType` |
`ctr` | `React.ElementType` \| null |
**Returns:** *boolean*
@@ -52,15 +89,15 @@ ___
### isConstructorHtmlLike
**isConstructorHtmlLike**(`ctr`: `React.ElementType`): *boolean*
**isConstructorHtmlLike**(`ctr`: `React.ElementType` | null): *boolean*
*Defined in [utils.ts:31](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L31)*
*Defined in [utils.ts:33](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L33)*
**Parameters:**
Name | Type |
------ | ------ |
`ctr` | `React.ElementType` |
`ctr` | `React.ElementType` \| null |
**Returns:** *boolean*
@@ -70,7 +107,7 @@ ___
**isNodeComponentClass**(`node`: [FiberNode](_mocked_types_index_.md#fibernode)): *boolean*
*Defined in [utils.ts:25](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L25)*
*Defined in [utils.ts:27](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L27)*
**Parameters:**
@@ -86,7 +123,7 @@ ___
**isNodeFunctionComponent**(`node`: [FiberNode](_mocked_types_index_.md#fibernode)): *boolean*
*Defined in [utils.ts:19](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L19)*
*Defined in [utils.ts:21](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L21)*
**Parameters:**
@@ -102,7 +139,7 @@ ___
**isNodeHtmlLike**(`node`: [FiberNode](_mocked_types_index_.md#fibernode)): *boolean*
*Defined in [utils.ts:9](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L9)*
*Defined in [utils.ts:11](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L11)*
**Parameters:**
@@ -118,7 +155,7 @@ ___
**isNodeNotHtmlLike**(`node`: [FiberNode](_mocked_types_index_.md#fibernode)): *boolean*
*Defined in [utils.ts:13](https://github.com/bendtherules/react-fiber-traverse/blob/c9d7fd7/src/utils.ts#L13)*
*Defined in [utils.ts:15](https://github.com/bendtherules/react-fiber-traverse/blob/c92c64b/src/utils.ts#L15)*
**Parameters:**
+2 -2
View File
@@ -1,7 +1,7 @@
"use strict";
if (process.env.NODE_ENV === "production") {
module.exports = require("./cjs-production/index.js");
module.exports = require("./react-fiber-traverse.cjs.production.js");
} else {
module.exports = require("./cjs-development/index.js");
module.exports = require("./react-fiber-traverse.cjs.development.js");
}
+10 -1
View File
@@ -1,3 +1,12 @@
module.exports = {
"*.{js,jsx,ts,tsx}": () => "run-s check:* lint"
"*.{js,jsx,ts,tsx}": filenames => {
// Escape filenames and join by space
const joinedFilenames = filenames.map(str => `"${str}"`).join(" ");
return [
"run-s check:!(format)",
`npm run check:format -- ${joinedFilenames}`,
`npm run _lint -- ${joinedFilenames}`
];
// `run-s check:!(format) "check:format -- ${joinedFilenames}" "_lint -- ${joinedFilenames}"`;
}
};
+24 -53
View File
@@ -1,6 +1,6 @@
{
"name": "react-fiber-traverse",
"version": "0.0.4",
"version": "0.0.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3775,13 +3775,20 @@
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
},
"dependencies": {
"css-what": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"dev": true
}
}
},
"css-what": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"dev": true
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.0.tgz",
"integrity": "sha512-lukqnlbswsPmDZ5+ViDBCcrk+1fyPBA+ZoHSAQhRuEeXBKUb3Lj2kcTwMqoiFrJAnEeO9u3Oc8X617SUm3apYQ=="
},
"cssom": {
"version": "0.3.8",
@@ -6007,17 +6014,24 @@
}
},
"handlebars": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"version": "4.7.7",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
"dev": true,
"requires": {
"minimist": "^1.2.5",
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4"
"uglify-js": "^3.1.4",
"wordwrap": "^1.0.0"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -9129,30 +9143,6 @@
"integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==",
"dev": true
},
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
},
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
"dev": true
}
}
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
@@ -10547,25 +10537,6 @@
}
}
},
"rollup-plugin-multi-input": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-multi-input/-/rollup-plugin-multi-input-1.0.2.tgz",
"integrity": "sha512-ktLat6+lrvT3Z3kVrUr/Fy3+5xaj/sIfNpBfDQO2P6sd3lAGPI+yi2Dj+fxxkVubIpRocN0Z4jPkN+c28uJimA==",
"dev": true,
"requires": {
"core-js": "^3.1.3",
"fast-glob": "^3.0.0",
"lodash": "^4.17.11"
},
"dependencies": {
"core-js": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz",
"integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==",
"dev": true
}
}
},
"rollup-plugin-node-resolve": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
+11 -9
View File
@@ -1,10 +1,10 @@
{
"name": "react-fiber-traverse",
"version": "0.0.4",
"version": "0.0.8",
"description": "Traverse and other utils on top of React fiber tree",
"main": "dist/index.js",
"module": "dist/esm/index.js",
"jsnext:main": "dist/esm/index.js",
"module": "dist/react-fiber-traverse.esm.js",
"jsnext:main": "dist/react-fiber-traverse.esm.js",
"typings": "dist/index.d.ts",
"files": [
"dist"
@@ -24,7 +24,8 @@
"compile": "tsc -p tsconfig.base.json",
"docs": "npx typedoc ./src/",
"format": "prettier --write \"**/*.{js,ts,tsx}\"",
"lint": "eslint . --ext .js,.ts",
"_lint": "eslint --ext .js,.ts,.jsx,.tsx",
"lint": "npm run _lint -- .",
"postbundle": "del compiled && cp-cli ./index.js ./dist/index.js",
"postversion": "git push && git push --tags && npm publish",
"release": "npm version -m 'Release v%s'",
@@ -34,13 +35,14 @@
"test:es": "jest --config ./scripts/jest/config.es.js",
"test:src": "jest --config ./scripts/jest/config.src.js",
"test:src:watch": "npm run test:src -- --watch",
"test:src:debug": "node --inspect ./node_modules/jest/bin/jest.js --config ./scripts/jest/config.src.js",
"version": "run-s test authors && git add ."
"test:umd": "jest --config ./scripts/jest/config.umd.js",
"test:umdprod": "jest --config ./scripts/jest/config.umdprod.js",
"test:src:debug": "node --inspect ./node_modules/jest/bin/jest.js --runInBand --config ./scripts/jest/config.src.js",
"version": "run-s test authors docs && git add ."
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"post-commit": "npm run fix:format"
"pre-commit": "lint-staged"
}
},
"repository": {
@@ -64,6 +66,7 @@
},
"dependencies": {
"@babel/runtime": "^7.5.4",
"css-what": "^3.2.0",
"prop-types": "^15.7.2"
},
"devDependencies": {
@@ -106,7 +109,6 @@
"rollup-plugin-babel": "4.3.3",
"rollup-plugin-commonjs": "10.0.1",
"rollup-plugin-filesize": "6.1.1",
"rollup-plugin-multi-input": "^1.0.2",
"rollup-plugin-node-resolve": "5.2.0",
"rollup-plugin-replace": "2.2.0",
"rollup-plugin-size-snapshot": "0.9.0",
+14 -12
View File
@@ -2,10 +2,9 @@ import babel from "rollup-plugin-babel";
import commonjs from "rollup-plugin-commonjs";
import nodeResolve from "rollup-plugin-node-resolve";
import replace from "rollup-plugin-replace";
// import { sizeSnapshot } from "rollup-plugin-size-snapshot";
import { sizeSnapshot } from "rollup-plugin-size-snapshot";
import sourcemaps from "rollup-plugin-sourcemaps";
import { terser } from "rollup-plugin-terser";
import multiInput from "rollup-plugin-multi-input";
import pkg from "./package.json";
const CJS_DEV = "CJS_DEV";
@@ -14,7 +13,7 @@ const ES = "ES";
const UMD_DEV = "UMD_DEV";
const UMD_PROD = "UMD_PROD";
const input = ["compiled/*.js"];
const input = "./compiled/index.js";
const getGlobals = bundleType => {
const baseGlobals = {
@@ -125,7 +124,7 @@ const getPlugins = bundleType => [
)
}),
sourcemaps(),
// sizeSnapshot(),
sizeSnapshot(),
isProduction(bundleType) &&
terser({
sourcemap: true,
@@ -137,15 +136,16 @@ const getPlugins = bundleType => [
warnings: true,
ecma: 5,
toplevel: false
}),
multiInput({ relative: "compiled/" })
})
];
const getCjsConfig = bundleType => ({
input,
external: getExternal(bundleType),
output: {
dir: `dist/cjs-${isProduction(bundleType) ? "production" : "development"}`,
file: `dist/react-fiber-traverse.cjs.${
isProduction(bundleType) ? "production" : "development"
}.js`,
format: "cjs",
sourcemap: true
},
@@ -156,7 +156,7 @@ const getEsConfig = () => ({
input,
external: getExternal(ES),
output: {
dir: `dist/esm`,
file: pkg.module,
format: "es",
sourcemap: true
},
@@ -167,7 +167,9 @@ const getUmdConfig = bundleType => ({
input,
external: getExternal(bundleType),
output: {
dir: `dist/umd-${isProduction(bundleType) ? "production" : "development"}`,
file: `dist/react-fiber-traverse.umd.${
isProduction(bundleType) ? "production" : "development"
}.js`,
format: "umd",
globals: getGlobals(bundleType),
name: "reactFiberTraverse",
@@ -179,7 +181,7 @@ const getUmdConfig = bundleType => ({
export default [
getCjsConfig(CJS_DEV),
getCjsConfig(CJS_PROD),
getEsConfig()
// getUmdConfig(UMD_DEV),
// getUmdConfig(UMD_PROD)
getEsConfig(),
getUmdConfig(UMD_DEV),
getUmdConfig(UMD_PROD)
];
+1 -1
View File
@@ -3,6 +3,6 @@ const srcConfig = require("./config.src");
module.exports = Object.assign({}, srcConfig, {
collectCoverage: false,
moduleNameMapper: {
"^../src$": `<rootDir>/dist/esm/index.js`
"^../src$": `<rootDir>/dist/react-fiber-traverse.esm.js`
}
});
+108 -52
View File
@@ -1,94 +1,150 @@
import { FiberNode } from "./mocked-types";
import { traverseGenerator, TTraverseConfig } from "./traverse";
import { isNodeNotHtmlLike } from "./utils";
/**
* Find node by component name, till first match.
*
* Matches against class and function name, doesn't match html-like nodes.
* Returns null if no match is found.
*
* @example
* ```js
* // returns FiberNode for first usage of 'AccordionMenu'
* findNodeByComponentName(startNode, "AccordionMenu");
* ```
*
* @note Highest chance of collision, least data access needed.
* Different components with same name will collide.
* Needs access to component name.
*
*/
function findNodeByComponentName(
node: FiberNode | null,
expectedName: string
expectedName: string,
traverseConfig?: TTraverseConfig
): FiberNode | null {
if (node === null) {
return null;
}
if (isNodeNotHtmlLike(node) && node.type.name === expectedName) {
return node;
}
{
const returnVal = findNodeByComponentName(node.child, expectedName);
if (returnVal !== null) {
return returnVal;
}
}
{
const returnVal = findNodeByComponentName(node.sibling, expectedName);
if (returnVal !== null) {
return returnVal;
const nodeIterator = traverseGenerator(node, traverseConfig);
for (const tmpNode of nodeIterator) {
if (isNodeNotHtmlLike(tmpNode) && tmpNode.type.name === expectedName) {
return tmpNode;
}
}
return null;
}
function* findNodesByComponentName(
node: FiberNode | null,
expectedName: string,
traverseConfig?: TTraverseConfig
): IterableIterator<FiberNode> {
if (node === null) {
return null;
}
const nodeIterator = traverseGenerator(node, traverseConfig);
for (const tmpNode of nodeIterator) {
if (isNodeNotHtmlLike(tmpNode) && tmpNode.type.name === expectedName) {
yield tmpNode;
}
}
}
function findAllNodesByComponentName(
node: FiberNode | null,
expectedName: string,
traverseConfig?: TTraverseConfig
): Array<FiberNode> {
return [...findNodesByComponentName(node, expectedName, traverseConfig)];
}
/**
* Find node by component (i.e. class or function by reference), till first match.
*
* Matches against class and function by reference.
* Returns null if no match is found.
*
* @example
* ```js
* // returns FiberNode for first usage of AccordionMenu
* findNodeByComponent(startNode, AccordionMenu);
* ```
*
* @note Medium chance of collision, medium data access needed.
* This is safer than findNodeByComponentName, as different components with the same name won't collide.
* But, two instances of the same component will still collide.
* Needs access to component class or function.
*
*/
function findNodeByComponent(
node: FiberNode | null,
expectedClassOrFunction: React.ComponentType
expectedClassOrFunction: React.ComponentType,
traverseConfig?: TTraverseConfig
): FiberNode | null {
if (node === null) {
return null;
}
if (isNodeNotHtmlLike(node) && node.type === expectedClassOrFunction) {
return node;
}
{
const returnVal = findNodeByComponent(node.child, expectedClassOrFunction);
if (returnVal !== null) {
return returnVal;
}
}
{
const returnVal = findNodeByComponent(
node.sibling,
expectedClassOrFunction
);
if (returnVal !== null) {
return returnVal;
const nodeIterator = traverseGenerator(node, traverseConfig);
for (const tmpNode of nodeIterator) {
if (
isNodeNotHtmlLike(tmpNode) &&
tmpNode.type === expectedClassOrFunction
) {
return tmpNode;
}
}
return null;
}
/**
* Find node by component instance ref, till first match.
*
* Matches against class instances by reference.
* Returns null if no match is found.
*
* @example
* ```js
* // menuRef=createRef(); <AccordionMenu ref={menuRef}>
* findNodeByComponentRef(startNode, menuRef.current);
* ```
*
* @note Least chance of collision, maximum data access needed.
* Needs access to component instance (through React ref usually).
*
*/
function findNodeByComponentRef(
node: FiberNode | null,
expectedClassInstance: React.Component
expectedClassInstance: React.Component,
traverseConfig?: TTraverseConfig
): FiberNode | null {
if (node === null) {
return null;
}
if (isNodeNotHtmlLike(node) && node.stateNode === expectedClassInstance) {
return node;
}
{
const returnVal = findNodeByComponentRef(node.child, expectedClassInstance);
if (returnVal !== null) {
return returnVal;
}
}
{
const returnVal = findNodeByComponentRef(
node.sibling,
expectedClassInstance
);
if (returnVal !== null) {
return returnVal;
const nodeIterator = traverseGenerator(node, traverseConfig);
for (const tmpNode of nodeIterator) {
if (
isNodeNotHtmlLike(tmpNode) &&
tmpNode.stateNode === expectedClassInstance
) {
return tmpNode;
}
}
return null;
}
export { findNodeByComponentName, findNodeByComponent, findNodeByComponentRef };
export {
findNodeByComponentName,
findNodesByComponentName,
findAllNodesByComponentName,
findNodeByComponent,
findNodeByComponentRef
};
+7 -1
View File
@@ -4,11 +4,17 @@ import {
findNodeByComponentRef,
findNodeByComponentName
} from "./findNode";
import { matchGenerator, matchAll, matchFirst } from "./match";
import * as Utils from "./utils";
export {
traverse,
traverseGenerator,
findNodeByComponent,
findNodeByComponentRef,
findNodeByComponentName
findNodeByComponentName,
matchGenerator,
matchAll,
matchFirst,
Utils
};
+141
View File
@@ -0,0 +1,141 @@
import * as CSSWhat from "css-what";
import { traverseGenerator } from "./traverse";
import { FiberNode } from "./mocked-types";
import { isNodeNotHtmlLike } from "./utils";
function* matchGenerator(
node: FiberNode,
match: string | CSSWhat.Selector[][]
): IterableIterator<FiberNode> {
// Either parse match string or allow parsed match object as it is
let matchParsed: CSSWhat.Selector[][];
if (typeof match === "string") {
matchParsed = CSSWhat.parse(match, {
lowerCaseTags: false,
lowerCaseAttributeNames: false
});
} else {
matchParsed = match;
}
// If selector is a combination of multiple basic selectors (a, b),
// pass them separately to matchGenerator and combine their results one after another
const selectorsCount = matchParsed.length;
if (selectorsCount > 1) {
for (const selectorParsed of matchParsed) {
yield* matchGenerator(node, [selectorParsed]);
}
return;
}
// For simple selector (matchParsed.length == 0), actual logic starts here
{
const parsedSelector = matchParsed[0];
if (parsedSelector.length === 0) {
return;
}
let currentMatchingNodes: FiberNode[] = [node];
let currentMatchingSelectorPartIndex = 0;
let lastRelationshipSelectorPart: CSSWhat.Selector | undefined = undefined;
while (currentMatchingSelectorPartIndex < parsedSelector.length) {
const nextMatchingNodes: FiberNode[] = [];
for (const currentNode of currentMatchingNodes) {
const currentMatchingSelectorPart: CSSWhat.Selector =
parsedSelector[currentMatchingSelectorPartIndex];
if (["tag"].includes(currentMatchingSelectorPart.type)) {
const startParams = {
skipSelfForStartNode: true,
skipSiblingForStartNode: true
};
let nextParams: {
skipChild?: boolean;
skipSibling?: boolean;
} = {};
if (
lastRelationshipSelectorPart === undefined ||
lastRelationshipSelectorPart.type === "descendant"
) {
nextParams = { skipChild: false, skipSibling: false };
} else if (lastRelationshipSelectorPart.type === "child") {
// visit only first level of child
nextParams = { skipChild: true };
} else if (lastRelationshipSelectorPart.type === "sibling") {
// visit only siblings of start node
nextParams = { skipChild: true, skipSibling: true };
startParams.skipSiblingForStartNode = false;
}
const traverseIterator = traverseGenerator(currentNode, startParams);
// Handle supported non-traversal parts here
if (currentMatchingSelectorPart.type == "tag") {
let tmpNode: FiberNode;
while (
!({ value: tmpNode } = traverseIterator.next(nextParams)).done
) {
if (
isNodeNotHtmlLike(tmpNode) &&
tmpNode.type.name === currentMatchingSelectorPart.name
) {
nextMatchingNodes.push(tmpNode);
}
}
}
// traverseIterator.throw &&
// traverseIterator.throw(new Error("cleanup"));
} else if (
["descendant", "child"].includes(currentMatchingSelectorPart.type)
) {
// Handle traversal parts here - Save for look back in next part
lastRelationshipSelectorPart = currentMatchingSelectorPart;
// Preserve currentMatchingNodes
nextMatchingNodes.push(...currentMatchingNodes);
} else {
// For unhandled parts
lastRelationshipSelectorPart = undefined;
}
}
currentMatchingNodes = nextMatchingNodes;
currentMatchingSelectorPartIndex += 1;
}
for (const tmpNode of currentMatchingNodes) {
yield tmpNode;
}
return;
}
}
function matchAll(
node: FiberNode,
match: string | CSSWhat.Selector[][]
): Array<FiberNode> {
return [...matchGenerator(node, match)];
}
function matchFirst(
node: FiberNode,
match: string | CSSWhat.Selector[][]
): FiberNode | null {
const matchIterator = matchGenerator(node, match);
const firstResult = matchIterator.next();
// Cancel generator
matchIterator.throw && matchIterator.throw(new Error("Cleanup"));
// If match found, return that
if (!firstResult.done) {
return firstResult.value;
}
// Else return null
return null;
}
export { matchGenerator, matchAll, matchFirst };
-10
View File
@@ -44,16 +44,6 @@ export interface FiberNodeForInstrinsicElement {
stateNode: HTMLElement;
}
export interface FiberNodeForInstrinsicElement {
child: FiberNode | null;
sibling: FiberNode | null;
elementType: keyof JSX.IntrinsicElements;
type: keyof JSX.IntrinsicElements;
stateNode: HTMLElement;
}
export interface FiberNodeForTextNode {
child: null;
sibling: FiberNode | null;
+112 -20
View File
@@ -1,47 +1,114 @@
// import { isNodeSimple } from './utils';
import { FiberNode } from "./mocked-types";
function traverse(node: FiberNode, fn: (node: FiberNode) => any) {
fn.call(null, node);
if (node.child !== null) {
traverse(node.child, fn);
}
if (node.sibling !== null) {
traverse(node.sibling, fn);
}
interface TTraverseConfig {
order?: Array<"self" | "child" | "sibling">;
skipSiblingForStartNode?: boolean;
skipSelfForStartNode?: boolean;
}
/**
* Traverse nodes recursively using generators.
*
* This is the advanced traverse function, which can be used used
* to write other variants of traversal and find.
*
* Type signature for generator.next first argument is `{ skipChild?: boolean; skipSibling?: boolean } | void `
* Throw any error into the generator to finish the generator and let it cleanup its internals.
*
* It allows inversion of control -
* so, application code can decide to
* 1. change order of traversal,
* 2. skip some elements,
* 3. cancel traversal mid-way.
*
* @example
* ```js
* // Basic use (for-of)
*
* const nodeIterator = traverseGenerator(rootNode);
* for (const node of nodeIterator) {
* // do something with each node here
* }
* ```
* ------
*
* @example
* ```js
* // Breadth-first
*
* // note the order below
* const nodeIterator = traverseGenerator(rootNode, ["self", "sibling", "child"]);
* // rest - same as above
* ```
* -----
*
* @example
* ```js
* // Get first 3 nodes and then stop the generator
*
* const nodeIterator = traverseGenerator(rootNode);
*
* var count = 0;
* var next;
* while (
* count < 3 &&
* !(next = nodeIterator.next()).done
* ) {
* count++;
* const node = next.value;
* // do something with each node here
* }
*
* // Finish generator, to prevent memory leak
* nodeIterator.throw(new Error());
* ```
* -----
*
*/
function* traverseGenerator(
node: FiberNode,
{
order = ["self", "child", "sibling"]
}: { order?: Array<"self" | "child" | "sibling"> } = {}
order = ["self", "child", "sibling"],
skipSiblingForStartNode = true,
skipSelfForStartNode = false
}: TTraverseConfig = {}
): IterableIterator<FiberNode> {
let skipChild = false,
skipSibling = false;
skipSibling = skipSiblingForStartNode,
skipSelf = skipSelfForStartNode;
function* traverseSelf() {
const controlInput:
| { skipChild: boolean; skipSibling: boolean }
| undefined = yield node;
if (!skipSelf) {
const controlInput:
| { skipChild?: boolean; skipSibling?: boolean }
| undefined = yield node;
if (controlInput !== undefined) {
({ skipChild = skipChild, skipSibling = skipSibling } = controlInput);
if (controlInput !== undefined) {
({ skipChild = skipChild, skipSibling = skipSibling } = controlInput);
}
}
}
function* traverseChild() {
if (!skipChild && node.child !== null) {
const nextNode = node.child;
yield* traverseGenerator(nextNode, { order });
yield* traverseGenerator(nextNode, {
order,
skipSiblingForStartNode: false,
skipSelfForStartNode: false
});
}
}
function* traverseSibling() {
if (!skipSibling && node.sibling !== null) {
const nextNode = node.sibling;
yield* traverseGenerator(nextNode, { order });
yield* traverseGenerator(nextNode, {
order,
skipSiblingForStartNode: false,
skipSelfForStartNode: false
});
}
}
@@ -62,4 +129,29 @@ function* traverseGenerator(
}
}
export { traverse, traverseGenerator };
/**
* Traverse nodes recursively in depth-first manner, starting from a start node.
*
* This is the default and basic traversal function, which covers basic use cases.
* You can't do advanced things like change the order of traversal, skip or cancel traversal after any node, etc.
* For more advanced usecases, see {@link traverseGenerator}
*
* @example
* ```js
* // calls fn for each node inside startNode
* traverse(startNode, fn);
* ```
*
*/
function traverse(
node: FiberNode,
fn: (node: FiberNode) => any,
traverseConfig?: TTraverseConfig
) {
const nodeIterator = traverseGenerator(node, traverseConfig);
for (const tmpNode of nodeIterator) {
fn.call(null, tmpNode);
}
}
export { traverse, traverseGenerator, TTraverseConfig };
+14 -7
View File
@@ -7,6 +7,7 @@ import {
FiberNodeDOMContainer
} from "./mocked-types";
// Support null in all of these
function isNodeHtmlLike(node: FiberNode): node is FiberNodeisHTMLLike {
return typeof node.type === "string" || node.type === null;
}
@@ -30,8 +31,8 @@ function isNodeComponentClass(
}
function isConstructorHtmlLike(
ctr: React.ElementType
): ctr is Exclude<React.ElementType, React.ComponentType> {
ctr: React.ElementType | null
): ctr is Exclude<React.ElementType | null, React.ComponentType> {
if (typeof ctr === "string" || ctr === null) {
return true;
}
@@ -39,7 +40,7 @@ function isConstructorHtmlLike(
}
function isConstructorComponentClass(
ctr: React.ElementType
ctr: React.ElementType | null
): ctr is React.ComponentClass {
if (isConstructorHtmlLike(ctr)) {
return false;
@@ -56,15 +57,20 @@ function isConstructorComponentClass(
}
function isConstructorFunctionComponent(
ctr: React.ElementType
ctr: React.ElementType | null
): ctr is React.FunctionComponent {
return !isConstructorComponentClass(ctr);
return typeof ctr === "function" && !isConstructorComponentClass(ctr);
}
function doesElementContainRootFiberNode(
element: Element
): element is FiberNodeDOMContainer {
return element.hasOwnProperty("_reactRootContainer");
return (
element.hasOwnProperty("_reactRootContainer") &&
(element as (Element & {
_reactRootContainer: any;
}))._reactRootContainer.hasOwnProperty("_internalRoot")
);
}
/**
@@ -83,7 +89,7 @@ function getRootFiberNodeFromDOM(startElement?: Element): FiberNode | null {
}
let returnFiberNode = null;
for (const childNode of startElement.children) {
for (const childNode of [].slice.call(startElement.children)) {
returnFiberNode = getRootFiberNodeFromDOM(childNode);
if (returnFiberNode !== null) {
return returnFiberNode;
@@ -101,5 +107,6 @@ export {
isConstructorHtmlLike,
isConstructorComponentClass,
isConstructorFunctionComponent,
doesElementContainRootFiberNode,
getRootFiberNodeFromDOM
};
+177
View File
@@ -0,0 +1,177 @@
import * as React from "react";
// Import stuff from src
import { findNodeByComponent } from "../src";
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import getWrappedComponent from "./utils/getWrappedComponent";
// Import test helpers and sample components
import CDepth1 from "./sample-components/depth-1-simple";
import FnDepth1 from "./sample-components/depth-1-fn-simple";
import { createClassComponent } from "./utils/createComponent";
describe("findNodeByComponent", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("missing", () => {
it("should not work for top-level class with same component name", () => {
const WrappedC = getWrappedComponent(CDepth1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeCDepth1 = createClassComponent(CDepth1.name);
const found = findNodeByComponent(rootNode, FakeCDepth1);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for top-level class with different component name", () => {
const WrappedC = getWrappedComponent(CDepth1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeCDepth1 = createClassComponent("randomname");
const found = findNodeByComponent(rootNode, FakeCDepth1);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for 2nd-level class with same component name", () => {
class C1 extends React.Component {
render() {
return <C2 />;
}
}
class C2 extends React.Component {
render() {
return <div>C2 here</div>;
}
}
const WrappedC = getWrappedComponent(C1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeC2 = createClassComponent(C2.name);
const found = findNodeByComponent(rootNode, FakeC2);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for 2nd-level class with different component name", () => {
class C1 extends React.Component {
render() {
return <C2 />;
}
}
class C2 extends React.Component {
render() {
return <div>C2 here</div>;
}
}
const WrappedC = getWrappedComponent(C1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeC2 = createClassComponent("randomName");
const found = findNodeByComponent(rootNode, FakeC2);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for top-level function with same function name", () => {
const WrappedC = getWrappedComponent(FnDepth1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeFnDepth1 = createClassComponent(FnDepth1.name);
const found = findNodeByComponent(rootNode, FakeFnDepth1);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for top-level function with different function name", () => {
const WrappedC = getWrappedComponent(FnDepth1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeFnDepth1 = createClassComponent("randomName");
const found = findNodeByComponent(rootNode, FakeFnDepth1);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for 2nd-level function with same function name", () => {
function Fn1() {
return <Fn2 />;
}
function Fn2() {
return <div>Fn2 here</div>;
}
const WrappedC = getWrappedComponent(Fn1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeFn2 = createClassComponent(Fn2.name);
const found = findNodeByComponent(rootNode, FakeFn2);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for 2nd-level function with different function name", () => {
function Fn1() {
return <Fn2 />;
}
function Fn2() {
return <div>Fn2 here</div>;
}
const WrappedC = getWrappedComponent(Fn1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeFn2 = createClassComponent("randomName");
const found = findNodeByComponent(rootNode, FakeFn2);
expect(found).toBeFalsy();
expect(found).toBe(null);
});
it("should not work for 5th-level function with same or diff fn name", () => {
function Fn1() {
return (
<div>
<div>
<span></span>
<Fn2></Fn2>
</div>
</div>
);
}
function Fn2() {
return <a href="google.com">Fn2 here</a>;
}
const WrappedC = getWrappedComponent(Fn1);
const rootNode = mountAndGetRootNode(WrappedC, container);
const FakeFn2Same = createClassComponent(Fn2.name);
const FakeFn2Diff = createClassComponent("randomname");
const foundSame = findNodeByComponent(rootNode, FakeFn2Same);
const foundDiff = findNodeByComponent(rootNode, FakeFn2Diff);
expect(foundSame).toBeFalsy();
expect(foundSame).toBe(null);
expect(foundDiff).toBeFalsy();
expect(foundDiff).toBe(null);
});
});
});
@@ -0,0 +1,95 @@
import * as React from "react";
// Import stuff from src
import { findNodeByComponentRef } from "../src";
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import getWrappedComponent from "./utils/getWrappedComponent";
class RandomClass extends React.Component {
render() {
return <div></div>;
}
}
// Import test helpers and sample components
describe("findNodeByComponentRef", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("negative", () => {
it("should not work for 2nd-level class", () => {
const C2Ref = React.createRef<C2>();
class C1 extends React.Component {
render() {
return <C2 ref={C2Ref} />;
}
}
class C2 extends React.Component {
render() {
return <div>C2 here</div>;
}
}
const WrappedC = getWrappedComponent(C1);
const rootNode = mountAndGetRootNode(WrappedC, container);
if (C2Ref.current === null) {
throw new Error("Ref is not yet set");
}
const foundSame = findNodeByComponentRef(rootNode, new C2({}));
const foundDiff = findNodeByComponentRef(rootNode, new RandomClass({}));
expect(foundSame).toBeFalsy();
expect(foundSame).toBe(null);
expect(foundDiff).toBeFalsy();
expect(foundDiff).toBe(null);
});
it("should work for 5th-level class", () => {
const C2Ref = React.createRef<C2>();
class C1 extends React.Component {
render() {
return (
<div>
<div>
<span></span>
<C2 ref={C2Ref}></C2>
</div>
</div>
);
}
}
class C2 extends React.Component {
render() {
return <a href="google.com">Fn2 here</a>;
}
}
const WrappedC = getWrappedComponent(C1);
const rootNode = mountAndGetRootNode(WrappedC, container);
if (C2Ref.current === null) {
throw new Error("Ref is not yet set");
}
const foundSame = findNodeByComponentRef(rootNode, new C2({}));
const foundDiff = findNodeByComponentRef(rootNode, new RandomClass({}));
expect(foundSame).toBeFalsy();
expect(foundSame).toBe(null);
expect(foundDiff).toBeFalsy();
expect(foundDiff).toBe(null);
});
});
});
+139
View File
@@ -0,0 +1,139 @@
import * as React from "react";
// Import stuff from src
import {
// matchGenerator,
matchAll
// matchFirst
} from "../src";
import {
FiberNodeForComponentClass
// FiberNodeForInstrinsicElement,
// FiberNodeForFunctionComponent
} from "../src/mocked-types";
// Import test helpers and sample components
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import {
// createClassComponents,
// createFunctionComponents,
createClassComponent,
createClassComponents
} from "./utils/createComponent";
describe("matchGenerator", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("basic", () => {
it("should work for depth=1 class", () => {
const C1 = createClassComponent("C1");
function CRoot() {
return <C1 />;
}
const rootNode = mountAndGetRootNode(CRoot, container);
const nodes = matchAll(rootNode, "C1");
// Can't be zero, in any case
expect(nodes.length).not.toBe(0);
// Check that only one node is yielded
expect(nodes.length).toBe(1);
// Check that type is correct
expect((nodes[0] as FiberNodeForComponentClass).type).toBe(C1);
});
it("should work for depth=2 class", () => {
const [C1, C2] = createClassComponents(["C1", "C2"]);
function CRoot() {
return (
<C1>
<C2 />
</C1>
);
}
const rootNode = mountAndGetRootNode(CRoot, container);
const nodes = matchAll(rootNode, "C2");
// Can't be zero, in any case
expect(nodes.length).not.toBe(0);
// Check that only one node is yielded
expect(nodes.length).toBe(1);
// Check that type is correct
expect((nodes[0] as FiberNodeForComponentClass).type).toBe(C2);
expect((nodes[0] as FiberNodeForComponentClass).type).not.toBe(C1);
});
it("should work for depth=2 class with descendant selector", () => {
const [C1, C2] = createClassComponents(["C1", "C2"]);
function CRoot() {
return (
<C1>
<C2 />
</C1>
);
}
const rootNode = mountAndGetRootNode(CRoot, container);
const nodes = matchAll(rootNode, "C1 C2");
// Can't be zero, in any case
expect(nodes.length).not.toBe(0);
// Check that only one node is yielded
expect(nodes.length).toBe(1);
// Check that type is correct
expect((nodes[0] as FiberNodeForComponentClass).type).toBe(C2);
expect((nodes[0] as FiberNodeForComponentClass).type).not.toBe(C1);
});
it("should work for depth=2 class with child selector", () => {
const [C1, C2] = createClassComponents(["C1", "C2"]);
function CRoot() {
return (
<C1>
<C2 />
</C1>
);
}
const rootNode = mountAndGetRootNode(CRoot, container);
const nodes = matchAll(rootNode, "C1>C2");
// Can't be zero, in any case
expect(nodes.length).not.toBe(0);
// Check that only one node is yielded
expect(nodes.length).toBe(1);
// Check that type is correct
expect((nodes[0] as FiberNodeForComponentClass).type).toBe(C2);
expect((nodes[0] as FiberNodeForComponentClass).type).not.toBe(C1);
});
it("should not work with child selector for nth-level descendant", () => {
const [C1, C2, C3] = createClassComponents(["C1", "C2", "C3"]);
function CRoot() {
return (
<C1>
<C2>
<C3 />
</C2>
</C1>
);
}
const rootNode = mountAndGetRootNode(CRoot, container);
const nodes = matchAll(rootNode, "C1>C3");
// No matcch found
expect(nodes.length).toBe(0);
});
});
});
+1 -1
View File
@@ -26,7 +26,7 @@ describe("traverseGenerator", () => {
document.body.removeChild(container);
});
describe("basic", () => {
describe("ordered", () => {
it("order doesn't matter for 1 node if self is present - case 1", () => {
const rootNode = mountAndGetRootNode(CDepth1, container);
+143
View File
@@ -0,0 +1,143 @@
import * as React from "react";
// Import stuff from src
import { FiberNodeForComponentClass, FiberNode } from "../src/mocked-types";
import { traverseGenerator } from "../src";
// Import test helpers and sample components
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import {
createClassComponents
// createFunctionComponents
} from "./utils/createComponent";
describe("traverseGenerator", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("skipped", () => {
it("should traverse just top-level with skipChild", () => {
const [C2, C3, C4, C5] = createClassComponents(["C2", "C3", "C4", "C5"]);
class C1 extends React.Component {
render() {
return (
<React.Fragment>
<C2>
<C3 />
</C2>
<C4>
<C5 />
</C4>
</React.Fragment>
);
}
}
const rootNode = mountAndGetRootNode(C1, container);
const nodeIterator = traverseGenerator(rootNode);
// Consume generator
let nodes: Array<FiberNode> = [];
const genArgs = { skipChild: true };
for (
let result = nodeIterator.next();
!result.done;
result = nodeIterator.next(genArgs)
) {
const currentNode = result.value;
nodes.push(currentNode);
}
expect(nodes.length).toBe(1);
expect(
nodes.map(tmpNode => (tmpNode as FiberNodeForComponentClass).type)
).toEqual([C1]);
});
it("should traverse just first 2 levels with inner skipChild", () => {
const [C2, C3, C4, C5] = createClassComponents(["C2", "C3", "C4", "C5"]);
class C1 extends React.Component {
render() {
return (
<React.Fragment>
<C2>
<C3 />
</C2>
<C4>
<C5 />
</C4>
</React.Fragment>
);
}
}
const rootNode = mountAndGetRootNode(C1, container);
const nodeIterator = traverseGenerator(rootNode);
// Consume generator
let nodes: Array<FiberNode> = [];
const genArgs = { skipChild: true };
for (
let result = nodeIterator.next();
!result.done;
result = nodeIterator.next(nodes.length > 1 ? genArgs : undefined)
) {
const currentNode = result.value;
nodes.push(currentNode);
}
expect(nodes.length).toBe(3);
expect(
nodes.map(tmpNode => (tmpNode as FiberNodeForComponentClass).type)
).toEqual([C1, C2, C4]);
});
it("should traverse one branch correctly with skipSibling", () => {
const [C2, C3, C4, C5] = createClassComponents(["C2", "C3", "C4", "C5"]);
class C1 extends React.Component {
render() {
return (
<React.Fragment>
<C2>
<C3 />
</C2>
<C4>
<C5 />
</C4>
</React.Fragment>
);
}
}
const rootNode = mountAndGetRootNode(C1, container);
const nodeIterator = traverseGenerator(rootNode);
// Consume generator
let nodes: Array<FiberNode> = [];
const genArgs = { skipSibling: true };
for (
let result = nodeIterator.next();
!result.done;
result = nodeIterator.next(genArgs)
) {
const currentNode = result.value;
nodes.push(currentNode);
}
expect(nodes.length).toBe(3);
expect(
nodes.map(tmpNode => (tmpNode as FiberNodeForComponentClass).type)
).toEqual([C1, C2, C3]);
});
});
});
@@ -0,0 +1,77 @@
// import * as React from "react";
// Import stuff from src
import { doesElementContainRootFiberNode } from "../src/utils";
// Import test helpers and sample components
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import { createFunctionComponent } from "./utils/createComponent";
describe("traverse", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
try {
document.body.removeChild(container);
} catch (error) {
if (!(error instanceof DOMException)) {
throw error;
}
}
});
describe("doesElementContainRootFiberNode", () => {
it("should work for direct element", () => {
const fn1 = createFunctionComponent("fn1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(fn1, containerInner);
const resultPositive = doesElementContainRootFiberNode(containerInner);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should not work for parent element", () => {
const fn1 = createFunctionComponent("fn1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(fn1, containerInner);
const resultNegative = doesElementContainRootFiberNode(container);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for child element", () => {
const fn1 = createFunctionComponent("fn1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(fn1, container);
const resultNegative = doesElementContainRootFiberNode(containerInner);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should work for body", () => {
const fn1 = createFunctionComponent("fn1");
mountAndGetRootNode(fn1, document.body);
const resultPositive = doesElementContainRootFiberNode(document.body);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
});
});
@@ -0,0 +1,94 @@
// import * as React from "react";
// Import stuff from src
import { getRootFiberNodeFromDOM } from "../src/utils";
// Import test helpers and sample components
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import { createClassComponent } from "./utils/createComponent";
describe("traverse", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
try {
document.body.removeChild(container);
} catch (error) {
if (!(error instanceof DOMException)) {
throw error;
}
}
});
describe("getRootFiberNodeFromDOM", () => {
it("should work for direct element", () => {
const C1 = createClassComponent("C1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(C1, containerInner);
const resultPositive = getRootFiberNodeFromDOM(containerInner);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).not.toBe(null);
expect((resultPositive as any).child.child.type).toBe(C1);
});
it("should work for parent element", () => {
const C1 = createClassComponent("C1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(C1, containerInner);
const resultPositive = getRootFiberNodeFromDOM(container);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).not.toBe(null);
expect((resultPositive as any).child.child.type).toBe(C1);
});
it("should work without any element - default args", () => {
const C1 = createClassComponent("C1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(C1, containerInner);
const resultPositive = getRootFiberNodeFromDOM();
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).not.toBe(null);
expect((resultPositive as any).child.child.type).toBe(C1);
});
it("should not work for child element", () => {
const C1 = createClassComponent("C1");
const containerInner = container.appendChild(
document.createElement("span")
);
mountAndGetRootNode(C1, container);
const resultNegative = getRootFiberNodeFromDOM(containerInner);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(null);
});
it("should work for body", () => {
const C1 = createClassComponent("C1");
mountAndGetRootNode(C1, document.body);
const resultPositive = getRootFiberNodeFromDOM(document.body);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).not.toBe(null);
expect((resultPositive as any).child.child.type).toBe(C1);
});
});
});
@@ -0,0 +1,74 @@
// import * as React from "react";
// Import stuff from src
import { isConstructorComponentClass } from "../src/utils";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isConstructorComponentClass", () => {
it("should work for class components", () => {
const C1 = createClassComponent("C1");
const resultPositive = isConstructorComponentClass(C1);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should not work for any class", () => {
const C1 = class {};
const resultNegative = isConstructorComponentClass(C1 as any);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for any function", () => {
const fn1 = function() {};
const resultNegative = isConstructorComponentClass(fn1 as any);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for function components", () => {
const fn1 = createFunctionComponent();
const resultNegative = isConstructorComponentClass(fn1);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for string", () => {
const resultNegative = isConstructorComponentClass("div");
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for null", () => {
const resultNegative = isConstructorComponentClass(null);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
});
});
@@ -0,0 +1,74 @@
// import * as React from "react";
// Import stuff from src
import { isConstructorFunctionComponent } from "../src/utils";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isConstructorFunctionComponent", () => {
it("should work for any function - current limitation", () => {
const fn1 = function() {};
const resultPositive = isConstructorFunctionComponent(fn1 as any);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should work for function components", () => {
const fn1 = createFunctionComponent();
const resultPositive = isConstructorFunctionComponent(fn1);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should not work for string", () => {
const resultNegative = isConstructorFunctionComponent("div");
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for null", () => {
const resultNegative = isConstructorFunctionComponent(null);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should work for any class - current limitation", () => {
const C1 = class {};
const resultPositive = isConstructorFunctionComponent(C1 as any);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should not work for class components", () => {
const C1 = createClassComponent("C1");
const resultNegative = isConstructorFunctionComponent(C1);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
});
});
+74
View File
@@ -0,0 +1,74 @@
// import * as React from "react";
// Import stuff from src
import { isConstructorHtmlLike } from "../src/utils";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isConstructorHtmlLike", () => {
it("should work for string", () => {
const resultPositive = isConstructorHtmlLike("div");
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should work for null", () => {
const resultPositive = isConstructorHtmlLike(null);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
});
it("should not work for any function", () => {
const fn1 = function() {};
const resultNegative = isConstructorHtmlLike(fn1 as any);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for function components", () => {
const fn1 = createFunctionComponent();
const resultNegative = isConstructorHtmlLike(fn1);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for any class", () => {
const C1 = class {};
const resultNegative = isConstructorHtmlLike(C1 as any);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for class components", () => {
const C1 = createClassComponent("C1");
const resultNegative = isConstructorHtmlLike(C1);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
});
});
+63
View File
@@ -0,0 +1,63 @@
// import * as React from "react";
// Import stuff from src
import { isNodeComponentClass } from "../src/utils";
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isNodeComponentClass", () => {
it("should work for class component", () => {
const C1 = createClassComponent("C1");
const rootNode = mountAndGetRootNode(C1, container);
const result = isNodeComponentClass(rootNode);
expect(result).not.toBeFalsy();
expect(result).toBe(true);
});
it("should not work for function component", () => {
const fn1 = createFunctionComponent("fn1");
const rootNode = mountAndGetRootNode(fn1, container);
const result = isNodeComponentClass(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
it("should not work for html like component - div", () => {
const rootNode = mountAndGetRootNode("div", container);
const result = isNodeComponentClass(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
it("should not work for html like component - svg", () => {
const rootNode = mountAndGetRootNode("svg", container);
const result = isNodeComponentClass(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
});
});
@@ -0,0 +1,63 @@
// import * as React from "react";
// Import stuff from src
import { isNodeFunctionComponent } from "../src/utils";
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isNodeFunctionComponent", () => {
it("should work for function component", () => {
const fn1 = createFunctionComponent("fn1");
const rootNode = mountAndGetRootNode(fn1, container);
const result = isNodeFunctionComponent(rootNode);
expect(result).not.toBeFalsy();
expect(result).toBe(true);
});
it("should not work for class component", () => {
const C1 = createClassComponent("C1");
const rootNode = mountAndGetRootNode(C1, container);
const result = isNodeFunctionComponent(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
it("should not work for html like component - div", () => {
const rootNode = mountAndGetRootNode("div", container);
const result = isNodeFunctionComponent(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
it("should work for html like component - svg", () => {
const rootNode = mountAndGetRootNode("svg", container);
const result = isNodeFunctionComponent(rootNode);
expect(result).toBeFalsy();
expect(result).toBe(false);
});
});
});
+102
View File
@@ -0,0 +1,102 @@
import * as React from "react";
// Import stuff from src
import { isNodeHtmlLike, isNodeNotHtmlLike } from "../src/utils";
import { mountAndGetRootNode } from "./utils/mountInEnzyme";
import { FiberNodeForInstrinsicElement } from "../src/mocked-types";
import {
createFunctionComponent,
createClassComponent
} from "./utils/createComponent";
// Import test helpers and sample components
describe("utils", () => {
let container: HTMLDivElement;
beforeEach(() => {
container = document.body.appendChild(document.createElement("div"));
});
afterEach(() => {
document.body.removeChild(container);
});
describe("isNodeHtmlLike", () => {
it("should work for div", () => {
const rootNode = mountAndGetRootNode("div", container);
const resultPositive = isNodeHtmlLike(rootNode);
const resultNegative = isNodeNotHtmlLike(rootNode);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should work for svg root element", () => {
const rootNode = mountAndGetRootNode("svg", container);
const resultPositive = isNodeHtmlLike(rootNode);
const resultNegative = isNodeNotHtmlLike(rootNode);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should work for svg inner elements", () => {
function SomeSVG() {
return (
<svg>
<circle cx={5} />
</svg>
);
}
const rootNode = mountAndGetRootNode(SomeSVG, container);
expect(isNodeHtmlLike(rootNode)).toBeFalsy();
const circleNode = (rootNode.child as FiberNodeForInstrinsicElement)
.child as FiberNodeForInstrinsicElement;
expect(circleNode).not.toBe(null);
expect(circleNode.type).toBe("circle");
const resultPositive = isNodeHtmlLike(circleNode);
const resultNegative = isNodeNotHtmlLike(circleNode);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for function component", () => {
const fn1 = createFunctionComponent("fn1");
const rootNode = mountAndGetRootNode(fn1, container);
const resultPositive = isNodeNotHtmlLike(rootNode);
const resultNegative = isNodeHtmlLike(rootNode);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
it("should not work for class component", () => {
const C1 = createClassComponent("C1");
const rootNode = mountAndGetRootNode(C1, container);
const resultPositive = isNodeNotHtmlLike(rootNode);
const resultNegative = isNodeHtmlLike(rootNode);
expect(resultPositive).not.toBeFalsy();
expect(resultPositive).toBe(true);
expect(resultNegative).toBeFalsy();
expect(resultNegative).toBe(false);
});
});
});
+5 -5
View File
@@ -1,7 +1,7 @@
import * as React from "react";
import { mount } from "enzyme";
import { FiberNode, FiberNodeForComponentClass } from "../../src/mocked-types";
import { isConstructorFunctionComponent } from "../../src/utils";
import { isConstructorComponentClass } from "../../src/utils";
import getWrappedComponent from "./getWrappedComponent";
export class RootNodeNotFoundError extends Error {
@@ -13,14 +13,14 @@ export class RootNodeNotFoundError extends Error {
}
export function mountAndGetRootNode(
SomeComponent: React.ComponentType,
SomeComponent: React.ElementType,
container: HTMLElement
): FiberNode {
const rootRef = React.createRef<React.Component>();
let ToMount = undefined;
let ToMount: React.ComponentClass | undefined = undefined;
// Wrap function components in ComponentClass to be able to set ref
if (isConstructorFunctionComponent(SomeComponent)) {
if (!isConstructorComponentClass(SomeComponent)) {
ToMount = getWrappedComponent(SomeComponent);
} else {
ToMount = SomeComponent;
@@ -41,7 +41,7 @@ export function mountAndGetRootNode(
}
// Unwrap function components to return expected root node
if (isConstructorFunctionComponent(SomeComponent)) {
if (!isConstructorComponentClass(SomeComponent)) {
return (rootNode as FiberNodeForComponentClass).child as FiberNode;
} else {
return rootNode;
+2 -1
View File
@@ -17,7 +17,8 @@
"removeComments": true,
"sourceMap": true,
"strict": true,
"target": "es6"
"target": "es5",
"downlevelIteration": true
},
"exclude": ["node_modules", "dist"],
"include": ["src"]