mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-13 18:01:53 +02:00
Add benchmarks (#368)
* Add script for benchmark * Add error handling * Rename folder to perf/benchmarks * Add README * Avoid memoization between benchmark runs * Handle multiple benchmark. Add setup to benchmarks * Run benchmarks through Travis * Add command line options for JSON output * Add export to JSON, and comparison with reference * Improve serialize and fix results display * Add perf/ to .npmignore * Print error message * Create normal example for normalize * Add normalize-document wide and deep * Add split-block normal, deep and wide * Add delete-backward benchmarks * Fix too much newlines * Use microtime for better results maybe? * Print number of runs * Add minSamples options for better accuracy * Use babel-node to launch benchmarks * Use jsdom-global instead of mocha-jsdom (deprecated) * Add rendering benchmark example * Fix jsdom usage. * Use JSX because we can * Only use on('cycle') that is called even on error * Example of successive rendering benchmark * Rename README, and explain how to add a benchmark * Add C++11 to Travis to install microtime * Update Readme.md # Understanding the results * Try to fix Travis build with microtime * Travis: use before_install Instead of overwriting install * Forgot to remove mocha-jsdom import Thanks node_modules... * Add jsdom as devDependency (required as peer dependency by jsdom-global) * Add --only option to run only a specific benchmark * Print name onStart rather than at end
This commit is contained in:
parent
582603a7e8
commit
f1a5d6f3b4
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ examples/build.prod.js
|
||||
node_modules
|
||||
tmp
|
||||
_book
|
||||
perf/reference.json
|
@ -3,3 +3,4 @@ examples
|
||||
src
|
||||
test
|
||||
tmp
|
||||
perf
|
12
.travis.yml
12
.travis.yml
@ -1,6 +1,16 @@
|
||||
language: node_js
|
||||
script: npm run lint && npm test
|
||||
script: npm run lint && npm test && npm run benchmarks
|
||||
node_js:
|
||||
- "node"
|
||||
- "6"
|
||||
- "4"
|
||||
# Compiling package microtime requires C++11 compiler. Benchmarks will
|
||||
# automatically use microtime if installed.
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
before_install:
|
||||
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then export CXX=g++-4.8; fi
|
||||
|
@ -32,6 +32,7 @@
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"babelify": "^7.3.0",
|
||||
"benchmark": "^2.1.1",
|
||||
"browserify": "^13.0.1",
|
||||
"browserify-global-shim": "^1.0.3",
|
||||
"browserify-shim": "^3.8.12",
|
||||
@ -46,8 +47,10 @@
|
||||
"http-server": "^0.9.0",
|
||||
"is-image": "^1.0.1",
|
||||
"is-url": "^1.2.2",
|
||||
"jsdom": "9.6.0",
|
||||
"jsdom-global": "2.1.0",
|
||||
"microtime": "2.1.1",
|
||||
"mocha": "^2.5.3",
|
||||
"mocha-jsdom": "^1.1.0",
|
||||
"np": "^2.9.0",
|
||||
"npm-run-all": "^2.3.0",
|
||||
"prismjs": "^1.5.1",
|
||||
@ -86,6 +89,10 @@
|
||||
"gh-pages": "npm run build && npm run examples && gh-pages --dist ./examples",
|
||||
"lint": "eslint --ignore-pattern 'build.dev.js' --ignore-pattern 'build.prod.js' '{examples,src}/**/*.js'",
|
||||
"open": "open http://localhost:8080/dev.html",
|
||||
"perf": "npm-run-all lint build:npm benchmarks",
|
||||
"perf:save": "npm-run-all lint build:npm benchmarks:save",
|
||||
"benchmarks": "babel-node ./perf/index.js --compare ./perf/reference.json",
|
||||
"benchmarks:save": "babel-node ./perf/index.js --output ./perf/reference.json",
|
||||
"prepublish": "npm run build",
|
||||
"postpublish": "npm run gh-pages",
|
||||
"release": "np",
|
||||
|
63
perf/Readme.md
Normal file
63
perf/Readme.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Benchmarks
|
||||
|
||||
This folder contains a set of benchmarks used to compare performances between Slate's version. We use [BenchmarkJS](https://benchmarkjs.com/) to measure performances.
|
||||
|
||||
## Running the benchmark
|
||||
|
||||
The following command will make sure to compile Slate before running the benchmarks.
|
||||
|
||||
```
|
||||
npm run perf
|
||||
```
|
||||
|
||||
You can skip Slate's compilation by running directly
|
||||
|
||||
```
|
||||
npm run benchmarks
|
||||
```
|
||||
|
||||
### Comparing results
|
||||
|
||||
You can save the results of the benchmarks with:
|
||||
|
||||
```shell
|
||||
npm run perf:save
|
||||
```
|
||||
|
||||
The results are saved as JSON in `./perf/reference.json`. You can then checkout a different implementation, and run a comparison benchmark with the usual command:
|
||||
|
||||
```
|
||||
npm run perf
|
||||
```
|
||||
|
||||
`perf` and `benchmarks` automatically look for an existing `reference.json` to use for comparison.
|
||||
|
||||
### Understanding the results
|
||||
|
||||
Each benchmark prints its results, showing:
|
||||
- The number of **operation per second**. This is the relevant value, that must be compared with values from different implementation.
|
||||
- The **number of samples** run. BenchmarkJS has a special heuristic to choose how many samples must be made. The results are more accurate with a high number of samples. Low samples count is often tied with high relative margin of error
|
||||
- The **relative margin** of error for the measure. The lower the value, the more accurate the results are. When compared with previous results, we display the average relative margin of error.
|
||||
- (comparison only) A **comparison** of the two implementation, according to BenchmarkJS. It can be Slower, Faster, or Indeterminate.
|
||||
- (comparison only) The **difference** in operations per second. Expressed as a percentage of the reference.
|
||||
|
||||
## Writing a benchmark
|
||||
|
||||
To add a benchmark, create a new folder in the `perf/benchmarks/` directory. It must contain two files:
|
||||
|
||||
1. `input.yaml` to provide an initial State
|
||||
2. `index.js` to tell what to run
|
||||
|
||||
`index.js` must export a `run(state)` function. This whole function will be benchmarked. It will be run several times, with the parsed state from `input.yaml` as parameter. You can optionally export a `setup(state) -> state` function, to modify the state parsed from `input.yaml`.
|
||||
|
||||
Note 1: Everything must be sync.
|
||||
|
||||
Note 2: To avoid unwanted memoization, a different instance of `state` will be passed for every `run` call.
|
||||
|
||||
## Detailed options for the benchmark script
|
||||
|
||||
You can also launch the benchmark script directly. See usage:
|
||||
|
||||
``` shell
|
||||
babel-node ./perf/index.js -h
|
||||
```
|
14
perf/benchmarks/delete-backward-deep/index.js
Normal file
14
perf/benchmarks/delete-backward-deep/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().deleteBackward().apply()
|
||||
}
|
||||
}
|
71
perf/benchmarks/delete-backward-deep/input.yaml
Normal file
71
perf/benchmarks/delete-backward-deep/input.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but nested in 3 levels of paragraphs
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
key: _cursor_
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
14
perf/benchmarks/delete-backward-normal/index.js
Normal file
14
perf/benchmarks/delete-backward-normal/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().deleteBackward().apply()
|
||||
}
|
||||
}
|
41
perf/benchmarks/delete-backward-normal/input.yaml
Normal file
41
perf/benchmarks/delete-backward-normal/input.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
key: _cursor_
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
14
perf/benchmarks/delete-backward-wide/index.js
Normal file
14
perf/benchmarks/delete-backward-wide/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().deleteBackward().apply()
|
||||
}
|
||||
}
|
120
perf/benchmarks/delete-backward-wide/input.yaml
Normal file
120
perf/benchmarks/delete-backward-wide/input.yaml
Normal file
@ -0,0 +1,120 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but concatened 3 times
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
key: _cursor_
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
12
perf/benchmarks/first-render-normal/index.js
Normal file
12
perf/benchmarks/first-render-normal/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
const { Editor } = require('../../../')
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
|
||||
module.exports = {
|
||||
run(state) {
|
||||
const div = document.createElement('div')
|
||||
const props = { state }
|
||||
|
||||
ReactDOM.render(<Editor {...props} />, div)
|
||||
}
|
||||
}
|
40
perf/benchmarks/first-render-normal/input.yaml
Normal file
40
perf/benchmarks/first-render-normal/input.yaml
Normal file
@ -0,0 +1,40 @@
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
6
perf/benchmarks/normalize-document-deep/index.js
Normal file
6
perf/benchmarks/normalize-document-deep/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
module.exports = {
|
||||
run(state) {
|
||||
return state.document.normalize()
|
||||
}
|
||||
}
|
70
perf/benchmarks/normalize-document-deep/input.yaml
Normal file
70
perf/benchmarks/normalize-document-deep/input.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but nested in 3 levels of paragraphs
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
6
perf/benchmarks/normalize-document-normal/index.js
Normal file
6
perf/benchmarks/normalize-document-normal/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
module.exports = {
|
||||
run(state) {
|
||||
return state.document.normalize()
|
||||
}
|
||||
}
|
40
perf/benchmarks/normalize-document-normal/input.yaml
Normal file
40
perf/benchmarks/normalize-document-normal/input.yaml
Normal file
@ -0,0 +1,40 @@
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
6
perf/benchmarks/normalize-document-wide/index.js
Normal file
6
perf/benchmarks/normalize-document-wide/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
module.exports = {
|
||||
run(state) {
|
||||
return state.document.normalize()
|
||||
}
|
||||
}
|
119
perf/benchmarks/normalize-document-wide/input.yaml
Normal file
119
perf/benchmarks/normalize-document-wide/input.yaml
Normal file
@ -0,0 +1,119 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but concatened 3 times
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
24
perf/benchmarks/render-split-block/index.js
Normal file
24
perf/benchmarks/render-split-block/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
const { Editor } = require('../../../')
|
||||
const React = require('react')
|
||||
const ReactDOM = require('react-dom')
|
||||
|
||||
// Benchmarks a first rendering, followed by a new rendering after a split-block
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
const div = document.createElement('div')
|
||||
|
||||
ReactDOM.render(<Editor state={state} />, div)
|
||||
|
||||
state = state.transform().splitBlock().apply()
|
||||
|
||||
ReactDOM.render(<Editor state={state} />, div)
|
||||
}
|
||||
}
|
41
perf/benchmarks/render-split-block/input.yaml
Normal file
41
perf/benchmarks/render-split-block/input.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
key: _cursor_
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
14
perf/benchmarks/split-block-deep/index.js
Normal file
14
perf/benchmarks/split-block-deep/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().splitBlock().apply()
|
||||
}
|
||||
}
|
71
perf/benchmarks/split-block-deep/input.yaml
Normal file
71
perf/benchmarks/split-block-deep/input.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but nested in 3 levels of paragraphs
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
key: _cursor_
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
14
perf/benchmarks/split-block-normal/index.js
Normal file
14
perf/benchmarks/split-block-normal/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().splitBlock().apply()
|
||||
}
|
||||
}
|
41
perf/benchmarks/split-block-normal/input.yaml
Normal file
41
perf/benchmarks/split-block-normal/input.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
nodes:
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
key: _cursor_
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
14
perf/benchmarks/split-block-wide/index.js
Normal file
14
perf/benchmarks/split-block-wide/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
module.exports = {
|
||||
setup(state) {
|
||||
// Move cursor
|
||||
return state.transform()
|
||||
.collapseToStartOf({ key: '_cursor_' })
|
||||
.moveForward(10) // Move inside the text
|
||||
.apply()
|
||||
},
|
||||
|
||||
run(state) {
|
||||
return state.transform().splitBlock().apply()
|
||||
}
|
||||
}
|
120
perf/benchmarks/split-block-wide/input.yaml
Normal file
120
perf/benchmarks/split-block-wide/input.yaml
Normal file
@ -0,0 +1,120 @@
|
||||
nodes:
|
||||
# Same than normalize-document-normal, but concatened 3 times
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
key: _cursor_
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'This is editable '
|
||||
- text: 'rich'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ' text, '
|
||||
- text: 'much'
|
||||
marks:
|
||||
- type: italic
|
||||
- text: ' better than a '
|
||||
- text: '<textarea>'
|
||||
marks:
|
||||
- type: code
|
||||
- text: '!'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: 'Since it''s rich text, you can do things like turn a selection of text '
|
||||
- text: 'bold'
|
||||
marks:
|
||||
- type: bold
|
||||
- text: ', or add a semantically rendered block quote in the middle of the page,
|
||||
like this:'
|
||||
- kind: block
|
||||
type: block-quote
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'A wise quote.'
|
||||
- kind: block
|
||||
type: paragraph
|
||||
nodes:
|
||||
- kind: text
|
||||
text: 'Try it out for yourself!'
|
347
perf/index.js
Normal file
347
perf/index.js
Normal file
@ -0,0 +1,347 @@
|
||||
// Performance benchmark
|
||||
|
||||
const USAGE = `
|
||||
Usage: babel-node ./perf/index.js [--compare referencePath] [--only benchmarkName] [--output outputPath]
|
||||
|
||||
--compare referencePath Compare with results stored in the JSON at referencePath
|
||||
--only benchmarkName Only run the designated benchmark (named after the benchmark directory)
|
||||
--output outputPath Output the benchmarks results as JSON at outputPath
|
||||
`
|
||||
|
||||
const Benchmark = require('benchmark')
|
||||
const jsdomGlobal = require('jsdom-global')
|
||||
|
||||
// Setup virtual DOM for rendering tests, before loading React (so it
|
||||
// see the fake DOM), but after loading BenchmarkJS so that it does
|
||||
// not think we are running inside a browser.
|
||||
jsdomGlobal()
|
||||
|
||||
const fs = require('fs')
|
||||
const _ = require('lodash')
|
||||
const readMetadata = require('read-metadata')
|
||||
const { Raw } = require('..')
|
||||
const { resolve } = require('path')
|
||||
|
||||
const DEFAULT_BENCHMARK = {
|
||||
setup(state) { return state },
|
||||
run(state) {}
|
||||
}
|
||||
|
||||
const BENCHMARK_OPTIONS = {
|
||||
// To ensure a better accuracy, force a minimum number of samples
|
||||
minSamples: 50 // default 10
|
||||
}
|
||||
|
||||
// Because BenchmarkJS does not support scoped variables well, use
|
||||
// globals... Each benchmark has its own namespace scope, that can be
|
||||
// accessed through the `getScope` global function
|
||||
const scopes = {}
|
||||
global.currentBenchmark = undefined // The benchmark being run
|
||||
global.setScope = function (benchmarkName, scope) {
|
||||
scopes[benchmarkName] = scope
|
||||
}
|
||||
global.getScope = function () {
|
||||
return scopes[global.currentBenchmark]
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Run benchmarks
|
||||
// --------------------------------------------------
|
||||
|
||||
function runBenchmarks() {
|
||||
print('Benchmarks\n')
|
||||
|
||||
// Command line options
|
||||
const { outputPath, reference, only, help } = parseCommandLineOptions(process)
|
||||
if (help) return printUsage()
|
||||
|
||||
let suite = new Benchmark.Suite()
|
||||
let results = {} // Can be saved as JSON
|
||||
|
||||
// For each benchmark
|
||||
const suiteDir = resolve(__dirname, './benchmarks')
|
||||
const benchmarks = fs.readdirSync(suiteDir)
|
||||
for (const benchmarkName of benchmarks) {
|
||||
if (benchmarkName[0] == '.') continue
|
||||
if (only && benchmarkName != only) continue
|
||||
|
||||
const benchmarkDir = resolve(suiteDir, benchmarkName)
|
||||
|
||||
// Read benchmark specification
|
||||
const benchmark = Object.assign({}, DEFAULT_BENCHMARK, require(benchmarkDir))
|
||||
// Parse input Slate.State
|
||||
const input = readMetadata.sync(resolve(benchmarkDir, 'input.yaml'))
|
||||
|
||||
// Setup global scope for this benchmark
|
||||
global.setScope(benchmarkName, {
|
||||
Raw,
|
||||
benchmark,
|
||||
input
|
||||
})
|
||||
|
||||
// Add it to the benchmark suite
|
||||
suite.add(Object.assign({}, BENCHMARK_OPTIONS, {
|
||||
name: benchmarkName,
|
||||
|
||||
onStart() {
|
||||
print(indent(1), benchmarkName)
|
||||
// Use this test's scope
|
||||
global.currentBenchmark = benchmarkName
|
||||
},
|
||||
|
||||
// Time spent in setup is not taken into account
|
||||
setup() {
|
||||
// Create as much independant Slate.State as needed, to avoid
|
||||
// memoization between calls to `fn`
|
||||
const scope = global.getScope()
|
||||
|
||||
let states = []
|
||||
let numberOfExecution = this.count
|
||||
while (numberOfExecution--) {
|
||||
states.push(
|
||||
// Each benchmark is given the chance to do its own setup
|
||||
scope.benchmark.setup(
|
||||
scope.Raw.deserialize(scope.input, { terse: true })
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let stateIndex = 0
|
||||
},
|
||||
|
||||
// Because of the way BenchmarkJS compiles the functions,
|
||||
// the variables declared in `setup` are visible to `fn`
|
||||
|
||||
fn() {
|
||||
scope.benchmark.run(states[stateIndex]) // eslint-disable-line no-undef
|
||||
// Next call will use another State instance
|
||||
stateIndex++ // eslint-disable-line no-undef
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
suite
|
||||
// On benchmark completion
|
||||
.on('cycle', (event) => {
|
||||
const result = serializeResult(event)
|
||||
results[result.name] = result
|
||||
compareResult(result, reference)
|
||||
})
|
||||
// On suite completion
|
||||
.on('complete', (event) => {
|
||||
if (outputPath) {
|
||||
save(results, outputPath)
|
||||
print(`\nSaved results as JSON to ${outputPath}`)
|
||||
}
|
||||
})
|
||||
// Run async to properly flush logs
|
||||
.run({ 'async': true })
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node.Process} process
|
||||
* @return {Object} { reference: JSON?, outputPath: String?, only: String? }
|
||||
*/
|
||||
|
||||
function parseCommandLineOptions(process) {
|
||||
let outputPath,
|
||||
reference,
|
||||
only,
|
||||
help = false
|
||||
|
||||
const options = process.argv.slice(2)
|
||||
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let option = options[i]
|
||||
|
||||
switch (option) {
|
||||
|
||||
case '-h':
|
||||
case '--help':
|
||||
help = true
|
||||
break
|
||||
|
||||
case '--output':
|
||||
outputPath = options[i + 1]
|
||||
i++
|
||||
break
|
||||
|
||||
case '--only':
|
||||
only = options[i + 1]
|
||||
i++
|
||||
break
|
||||
|
||||
case '--compare':
|
||||
let refPath = resolve(process.cwd(), options[i + 1])
|
||||
if (exists(refPath)) {
|
||||
let fileContents = fs.readFileSync(refPath, 'utf-8')
|
||||
reference = JSON.parse(fileContents)
|
||||
}
|
||||
|
||||
i++
|
||||
break
|
||||
|
||||
default:
|
||||
printUsage()
|
||||
throw new Error(`Invalid argument ${option}`)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
outputPath,
|
||||
reference,
|
||||
only,
|
||||
help
|
||||
}
|
||||
}
|
||||
|
||||
function printUsage() {
|
||||
print(USAGE)
|
||||
}
|
||||
|
||||
function exists(filepath) {
|
||||
try {
|
||||
fs.statSync(filepath)
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function save(results, path) {
|
||||
path = resolve(process.cwd(), path)
|
||||
fs.writeFileSync(path, JSON.stringify(results))
|
||||
}
|
||||
|
||||
function serializeResult(event) {
|
||||
const { target } = event
|
||||
const { error, name } = target
|
||||
|
||||
const result = {
|
||||
name
|
||||
}
|
||||
|
||||
if (target.error) {
|
||||
Object.assign(result, { error })
|
||||
}
|
||||
|
||||
else {
|
||||
const { hz } = target
|
||||
const { mean, rme } = target.stats
|
||||
const stats = _.pick(target.stats, [
|
||||
'rme',
|
||||
'mean',
|
||||
'sample'
|
||||
])
|
||||
|
||||
Object.assign(result, {
|
||||
hz,
|
||||
stats
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty print a benchmark result, along with its reference.
|
||||
* Mean difference, and rme computations inspired from
|
||||
* https://github.com/facebook/immutable-js/blob/master/resources/bench.js
|
||||
*
|
||||
* @param {Object} result
|
||||
* @param {Object} reference (optional)
|
||||
*/
|
||||
|
||||
function compareResult(result, reference = {}) {
|
||||
const { name } = result
|
||||
const ref = reference[name]
|
||||
const errored = ref && (ref.error || result.error)
|
||||
|
||||
print(indent(2), 'Current: ', formatPerf(result))
|
||||
|
||||
if (ref) {
|
||||
print(indent(2), 'Reference: ', formatPerf(ref))
|
||||
}
|
||||
|
||||
// Print comparison
|
||||
|
||||
if (ref && !errored) {
|
||||
print(indent(2), `comparison: ${compare(result, ref)}`)
|
||||
}
|
||||
|
||||
// Print difference as percentage
|
||||
if (ref && !errored) {
|
||||
const newMean = 1 / result.stats.mean
|
||||
const prevMean = 1 / ref.stats.mean
|
||||
const diffMean = 100 * (newMean - prevMean) / prevMean
|
||||
|
||||
print(indent(2), `diff: ${signed(diffMean.toFixed(2))}%`) // diff: -3.45%
|
||||
}
|
||||
|
||||
// Print relative mean error
|
||||
if (ref && !errored) {
|
||||
const aRme = 100 * Math.sqrt(
|
||||
(square(result.stats.rme / 100) + square(ref.stats.rme / 100)) / 2
|
||||
)
|
||||
|
||||
print(indent(2), `rme: \xb1${aRme.toFixed(2)}%`) // rme: ±6.22%
|
||||
} else if (!result.error) {
|
||||
print(indent(2), `rme: \xb1${result.stats.rme.toFixed(2)}%`) // rme: ±6.22%
|
||||
}
|
||||
|
||||
print('') // newline
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty format a benchmark's ops/sec along with its sample size
|
||||
* @param {Object} result
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
function formatPerf(result) {
|
||||
if (result.error) return result.error
|
||||
const { hz } = result
|
||||
const runs = result.stats.sample.length
|
||||
const opsSec = Benchmark.formatNumber(`${hz.toFixed(hz < 100 ? 2 : 0)}`)
|
||||
return `${opsSec} ops/sec (${runs} runs sampled)`
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} newResult
|
||||
* @param {Object} oldResult
|
||||
* @return {String} Faster, Slower, or Indeterminate
|
||||
*/
|
||||
|
||||
function compare(newResult, oldResult) {
|
||||
const comparison = (new Benchmark()).compare.call(newResult, oldResult)
|
||||
|
||||
switch (comparison) {
|
||||
case 1:
|
||||
return 'Faster'
|
||||
case -1:
|
||||
return 'Slower'
|
||||
default:
|
||||
return 'Indeterminate'
|
||||
}
|
||||
}
|
||||
|
||||
function indent(level = 0) {
|
||||
return Array(level + 1).join(' ')
|
||||
}
|
||||
|
||||
function square(x) {
|
||||
return x * x
|
||||
}
|
||||
|
||||
function signed(x) {
|
||||
return x > 0 ? `+${x}` : `${x}`
|
||||
}
|
||||
|
||||
function print(...strs) {
|
||||
console.log(...strs) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Main
|
||||
// --------------------------------------------------
|
||||
runBenchmarks()
|
@ -1,7 +1,7 @@
|
||||
|
||||
import 'jsdom-global/register'
|
||||
import React from 'react'
|
||||
import fs from 'fs'
|
||||
import jsdom from 'mocha-jsdom'
|
||||
import readMetadata from 'read-metadata'
|
||||
import strip from '../helpers/strip-dynamic'
|
||||
import { Raw, Editor, Schema } from '../..'
|
||||
@ -14,8 +14,6 @@ import { strictEqual } from '../helpers/assert-json'
|
||||
*/
|
||||
|
||||
describe('schema', () => {
|
||||
jsdom()
|
||||
|
||||
const tests = fs.readdirSync(resolve(__dirname, './fixtures'))
|
||||
|
||||
for (const test of tests) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user