summaryrefslogtreecommitdiff
path: root/preact
diff options
context:
space:
mode:
Diffstat (limited to 'preact')
-rw-r--r--preact/.codesandbox/ci.json4
-rw-r--r--preact/.editorconfig16
-rw-r--r--preact/.github/CODE_OF_CONDUCT.md46
-rw-r--r--preact/.github/FUNDING.yml2
-rw-r--r--preact/.github/ISSUE_TEMPLATE/bug_report.md25
-rw-r--r--preact/.github/ISSUE_TEMPLATE/feature_request.md14
-rw-r--r--preact/.github/workflows/benchmarks.yml256
-rw-r--r--preact/.github/workflows/ci.yml57
-rw-r--r--preact/.github/workflows/pr-reporter.yml51
-rw-r--r--preact/.github/workflows/saucelabs.yml42
-rw-r--r--preact/.github/workflows/size.yml17
-rw-r--r--preact/.gitignore16
-rw-r--r--preact/CODE_OF_CONDUCT.md46
-rw-r--r--preact/CONTRIBUTING.md237
-rw-r--r--preact/LICENSE21
-rw-r--r--preact/README.md187
-rw-r--r--preact/babel.config.js47
-rw-r--r--preact/benches/.gitignore6
-rw-r--r--preact/benches/LICENSE21
-rw-r--r--preact/benches/README.md72
-rw-r--r--preact/benches/TODO.md10
-rw-r--r--preact/benches/jsconfig.json8
-rw-r--r--preact/benches/package.json30
-rw-r--r--preact/benches/proxy-packages/preact-local-proxy/index.js18
-rw-r--r--preact/benches/proxy-packages/preact-local-proxy/package.json10
-rw-r--r--preact/benches/proxy-packages/preact-master-proxy/index.js18
-rw-r--r--preact/benches/proxy-packages/preact-master-proxy/package.json10
-rw-r--r--preact/benches/proxy-packages/preact-v8-proxy/index.js23
-rw-r--r--preact/benches/proxy-packages/preact-v8-proxy/package.json10
-rw-r--r--preact/benches/scripts/analyze.js363
-rw-r--r--preact/benches/scripts/bench.js70
-rw-r--r--preact/benches/scripts/config.js317
-rw-r--r--preact/benches/scripts/deopts.js253
-rw-r--r--preact/benches/scripts/global.d.ts15
-rw-r--r--preact/benches/scripts/index.js110
-rw-r--r--preact/benches/scripts/prepare.js44
-rw-r--r--preact/benches/scripts/tracing.d.ts224
-rw-r--r--preact/benches/scripts/utils.js65
-rw-r--r--preact/benches/src/02_replace1k.html67
-rw-r--r--preact/benches/src/03_update10th1k_x16.html78
-rw-r--r--preact/benches/src/07_create10k.html49
-rw-r--r--preact/benches/src/filter_list.html92
-rw-r--r--preact/benches/src/hydrate1k.html145
-rw-r--r--preact/benches/src/keyed-children/components.js152
-rw-r--r--preact/benches/src/keyed-children/index.js29
-rw-r--r--preact/benches/src/keyed-children/store.js119
-rw-r--r--preact/benches/src/many_updates.html112
-rw-r--r--preact/benches/src/text_update.html34
-rw-r--r--preact/benches/src/util.js98
-rw-r--r--preact/compat/LICENSE21
-rw-r--r--preact/compat/jsx-dev-runtime.js1
-rw-r--r--preact/compat/jsx-dev-runtime.mjs1
-rw-r--r--preact/compat/jsx-runtime.js1
-rw-r--r--preact/compat/jsx-runtime.mjs1
-rw-r--r--preact/compat/mangle.json21
-rw-r--r--preact/compat/package.json19
-rw-r--r--preact/compat/scheduler.js15
-rw-r--r--preact/compat/scheduler.mjs23
-rw-r--r--preact/compat/server.js15
-rw-r--r--preact/compat/server.mjs4
-rw-r--r--preact/compat/src/Children.js21
-rw-r--r--preact/compat/src/PureComponent.js15
-rw-r--r--preact/compat/src/forwardRef.js51
-rw-r--r--preact/compat/src/index.d.ts140
-rw-r--r--preact/compat/src/index.js187
-rw-r--r--preact/compat/src/internal.d.ts47
-rw-r--r--preact/compat/src/memo.js34
-rw-r--r--preact/compat/src/portals.js80
-rw-r--r--preact/compat/src/render.js219
-rw-r--r--preact/compat/src/suspense-list.d.ts14
-rw-r--r--preact/compat/src/suspense-list.js126
-rw-r--r--preact/compat/src/suspense.d.ts15
-rw-r--r--preact/compat/src/suspense.js270
-rw-r--r--preact/compat/src/util.js28
-rw-r--r--preact/compat/test-utils.js1
-rw-r--r--preact/compat/test/browser/Children.test.js185
-rw-r--r--preact/compat/test/browser/PureComponent.test.js125
-rw-r--r--preact/compat/test/browser/cloneElement.test.js96
-rw-r--r--preact/compat/test/browser/compat.options.test.js85
-rw-r--r--preact/compat/test/browser/component.test.js243
-rw-r--r--preact/compat/test/browser/createElement.test.js49
-rw-r--r--preact/compat/test/browser/createFactory.test.js26
-rw-r--r--preact/compat/test/browser/events.test.js278
-rw-r--r--preact/compat/test/browser/exports.test.js85
-rw-r--r--preact/compat/test/browser/findDOMNode.test.js51
-rw-r--r--preact/compat/test/browser/forwardRef.test.js460
-rw-r--r--preact/compat/test/browser/hydrate.test.js34
-rw-r--r--preact/compat/test/browser/isValidElement.test.js22
-rw-r--r--preact/compat/test/browser/memo.test.js234
-rw-r--r--preact/compat/test/browser/portals.test.js627
-rw-r--r--preact/compat/test/browser/render.test.js454
-rw-r--r--preact/compat/test/browser/scheduler.test.js39
-rw-r--r--preact/compat/test/browser/select.test.js33
-rw-r--r--preact/compat/test/browser/suspense-hydration.test.js778
-rw-r--r--preact/compat/test/browser/suspense-list.test.js588
-rw-r--r--preact/compat/test/browser/suspense-utils.js116
-rw-r--r--preact/compat/test/browser/suspense.test.js2091
-rw-r--r--preact/compat/test/browser/svg.test.js94
-rw-r--r--preact/compat/test/browser/testUtils.js24
-rw-r--r--preact/compat/test/browser/textarea.test.js64
-rw-r--r--preact/compat/test/browser/unmountComponentAtNode.test.js28
-rw-r--r--preact/compat/test/browser/unstable_batchedUpdates.test.js15
-rw-r--r--preact/compat/test/ts/forward-ref.tsx26
-rw-r--r--preact/compat/test/ts/lazy.tsx17
-rw-r--r--preact/compat/test/ts/memo.tsx56
-rw-r--r--preact/compat/test/ts/react-default.tsx6
-rw-r--r--preact/compat/test/ts/react-star.tsx7
-rw-r--r--preact/compat/test/ts/scheduler.ts19
-rw-r--r--preact/compat/test/ts/suspense.tsx52
-rw-r--r--preact/compat/test/ts/tsconfig.json20
-rw-r--r--preact/compat/test/ts/utils.ts4
-rw-r--r--preact/config/codemod-const.js43
-rw-r--r--preact/config/codemod-let-name.js16
-rw-r--r--preact/config/codemod-strip-tdz.js60
-rw-r--r--preact/config/compat-entries.js25
-rw-r--r--preact/config/node-13-exports.js32
-rw-r--r--preact/debug/LICENSE21
-rw-r--r--preact/debug/mangle.json21
-rw-r--r--preact/debug/package.json18
-rw-r--r--preact/debug/src/check-props.js54
-rw-r--r--preact/debug/src/component-stack.js146
-rw-r--r--preact/debug/src/constants.js3
-rw-r--r--preact/debug/src/debug.js442
-rw-r--r--preact/debug/src/index.js6
-rw-r--r--preact/debug/src/internal.d.ts82
-rw-r--r--preact/debug/src/util.js11
-rw-r--r--preact/debug/test/browser/component-stack-2.test.js54
-rw-r--r--preact/debug/test/browser/component-stack.test.js86
-rw-r--r--preact/debug/test/browser/debug-compat.test.js81
-rw-r--r--preact/debug/test/browser/debug-hooks.test.js111
-rw-r--r--preact/debug/test/browser/debug-suspense.test.js190
-rw-r--r--preact/debug/test/browser/debug.options.test.js135
-rw-r--r--preact/debug/test/browser/debug.test.js624
-rw-r--r--preact/debug/test/browser/fakeDevTools.js1
-rw-r--r--preact/debug/test/browser/serializeVNode.test.js66
-rw-r--r--preact/demo/contenteditable.js25
-rw-r--r--preact/demo/context.js69
-rw-r--r--preact/demo/devtools.js42
-rw-r--r--preact/demo/fragments.js26
-rw-r--r--preact/demo/index.js187
-rw-r--r--preact/demo/key_bug.js32
-rw-r--r--preact/demo/list.js63
-rw-r--r--preact/demo/logger.js170
-rw-r--r--preact/demo/mobx.js75
-rw-r--r--preact/demo/nested-suspense/addnewcomponent.js5
-rw-r--r--preact/demo/nested-suspense/component-container.js17
-rw-r--r--preact/demo/nested-suspense/dropzone.js5
-rw-r--r--preact/demo/nested-suspense/editor.js5
-rw-r--r--preact/demo/nested-suspense/index.js69
-rw-r--r--preact/demo/nested-suspense/subcomponent.js5
-rw-r--r--preact/demo/old.js.bak103
-rw-r--r--preact/demo/package.json44
-rw-r--r--preact/demo/people/Readme.md3
-rw-r--r--preact/demo/people/index.tsx59
-rw-r--r--preact/demo/people/profile.tsx59
-rw-r--r--preact/demo/people/router.tsx153
-rw-r--r--preact/demo/people/store.ts83
-rw-r--r--preact/demo/people/styles/animations.scss34
-rw-r--r--preact/demo/people/styles/app.scss100
-rw-r--r--preact/demo/people/styles/avatar.scss16
-rw-r--r--preact/demo/people/styles/button.scss115
-rw-r--r--preact/demo/people/styles/index.scss168
-rw-r--r--preact/demo/people/styles/profile.scss26
-rw-r--r--preact/demo/preact.js39
-rw-r--r--preact/demo/profiler.js88
-rw-r--r--preact/demo/pythagoras/index.js86
-rw-r--r--preact/demo/pythagoras/pythagoras.js97
-rw-r--r--preact/demo/redux.js48
-rw-r--r--preact/demo/reduxUpdate.js61
-rw-r--r--preact/demo/reorder.js104
-rw-r--r--preact/demo/spiral.js140
-rw-r--r--preact/demo/stateOrderBug.js80
-rw-r--r--preact/demo/style.css24
-rw-r--r--preact/demo/style.scss149
-rw-r--r--preact/demo/styled-components.js31
-rw-r--r--preact/demo/suspense-router/bye.js12
-rw-r--r--preact/demo/suspense-router/hello.js12
-rw-r--r--preact/demo/suspense-router/index.js30
-rw-r--r--preact/demo/suspense-router/simple-router.js87
-rw-r--r--preact/demo/suspense.js97
-rw-r--r--preact/demo/textFields.js37
-rw-r--r--preact/demo/todo.js47
-rw-r--r--preact/demo/tsconfig.json15
-rw-r--r--preact/demo/webpack.config.js112
-rw-r--r--preact/devtools/LICENSE21
-rw-r--r--preact/devtools/mangle.json21
-rw-r--r--preact/devtools/package.json16
-rw-r--r--preact/devtools/src/devtools.js10
-rw-r--r--preact/devtools/src/index.d.ts8
-rw-r--r--preact/devtools/src/index.js15
-rw-r--r--preact/devtools/test/browser/addHookName.test.js51
-rw-r--r--preact/hooks/LICENSE21
-rw-r--r--preact/hooks/mangle.json21
-rw-r--r--preact/hooks/package.json26
-rw-r--r--preact/hooks/src/index.d.ts133
-rw-r--r--preact/hooks/src/index.js386
-rw-r--r--preact/hooks/src/internal.d.ts75
-rw-r--r--preact/hooks/test/_util/useEffectUtil.js10
-rw-r--r--preact/hooks/test/browser/combinations.test.js301
-rw-r--r--preact/hooks/test/browser/errorBoundary.test.js92
-rw-r--r--preact/hooks/test/browser/hooks.options.test.js154
-rw-r--r--preact/hooks/test/browser/useCallback.test.js41
-rw-r--r--preact/hooks/test/browser/useContext.test.js351
-rw-r--r--preact/hooks/test/browser/useDebugValue.test.js71
-rw-r--r--preact/hooks/test/browser/useEffect.test.js373
-rw-r--r--preact/hooks/test/browser/useEffectAssertions.test.js142
-rw-r--r--preact/hooks/test/browser/useImperativeHandle.test.js182
-rw-r--r--preact/hooks/test/browser/useLayoutEffect.test.js326
-rw-r--r--preact/hooks/test/browser/useMemo.test.js125
-rw-r--r--preact/hooks/test/browser/useReducer.test.js214
-rw-r--r--preact/hooks/test/browser/useRef.test.js50
-rw-r--r--preact/hooks/test/browser/useState.test.js214
-rw-r--r--preact/jsconfig.json16
-rw-r--r--preact/jsx-runtime/LICENSE21
-rw-r--r--preact/jsx-runtime/mangle.json21
-rw-r--r--preact/jsx-runtime/package.json19
-rw-r--r--preact/jsx-runtime/src/index.d.ts50
-rw-r--r--preact/jsx-runtime/src/index.js77
-rw-r--r--preact/jsx-runtime/test/browser/jsx-runtime.test.js94
-rw-r--r--preact/karma.conf.js338
-rw-r--r--preact/mangle.json80
-rw-r--r--preact/package-lock.json32470
-rw-r--r--preact/package.json270
-rw-r--r--preact/sizereport.config.js5
-rw-r--r--preact/src/cjs.js3
-rw-r--r--preact/src/clone-element.js34
-rw-r--r--preact/src/component.js225
-rw-r--r--preact/src/constants.js3
-rw-r--r--preact/src/create-context.js68
-rw-r--r--preact/src/create-element.js97
-rw-r--r--preact/src/diff/catch-error.js38
-rw-r--r--preact/src/diff/children.js347
-rw-r--r--preact/src/diff/index.js514
-rw-r--r--preact/src/diff/props.js158
-rw-r--r--preact/src/index.d.ts310
-rw-r--r--preact/src/index.js13
-rw-r--r--preact/src/internal.d.ts146
-rw-r--r--preact/src/jsx.d.ts974
-rw-r--r--preact/src/options.js16
-rw-r--r--preact/src/render.js75
-rw-r--r--preact/src/util.js27
-rw-r--r--preact/test-utils/package.json19
-rw-r--r--preact/test-utils/src/index.d.ts3
-rw-r--r--preact/test-utils/src/index.js117
-rw-r--r--preact/test-utils/test/shared/act.test.js479
-rw-r--r--preact/test-utils/test/shared/rerender.test.js59
-rw-r--r--preact/test/TODO.md13
-rw-r--r--preact/test/_util/bench.js46
-rw-r--r--preact/test/_util/dom.js66
-rw-r--r--preact/test/_util/helpers.js292
-rw-r--r--preact/test/_util/logCall.js66
-rw-r--r--preact/test/_util/optionSpies.js39
-rw-r--r--preact/test/benchmarks/performance.test.js470
-rw-r--r--preact/test/benchmarks/text.test.js101
-rw-r--r--preact/test/browser/cloneElement.test.js87
-rw-r--r--preact/test/browser/components.test.js2664
-rw-r--r--preact/test/browser/context.test.js237
-rw-r--r--preact/test/browser/createContext.test.js931
-rw-r--r--preact/test/browser/customBuiltInElements.test.js40
-rw-r--r--preact/test/browser/events.test.js202
-rw-r--r--preact/test/browser/focus.test.js548
-rw-r--r--preact/test/browser/fragments.test.js2805
-rw-r--r--preact/test/browser/getDomSibling.test.js362
-rw-r--r--preact/test/browser/hydrate.test.js454
-rw-r--r--preact/test/browser/isValidElement.test.js4
-rw-r--r--preact/test/browser/keys.test.js627
-rw-r--r--preact/test/browser/lifecycles/componentDidCatch.test.js672
-rw-r--r--preact/test/browser/lifecycles/componentDidMount.test.js36
-rw-r--r--preact/test/browser/lifecycles/componentDidUpdate.test.js385
-rw-r--r--preact/test/browser/lifecycles/componentWillMount.test.js43
-rw-r--r--preact/test/browser/lifecycles/componentWillReceiveProps.test.js296
-rw-r--r--preact/test/browser/lifecycles/componentWillUnmount.test.js72
-rw-r--r--preact/test/browser/lifecycles/componentWillUpdate.test.js95
-rw-r--r--preact/test/browser/lifecycles/getDerivedStateFromError.test.js659
-rw-r--r--preact/test/browser/lifecycles/getDerivedStateFromProps.test.js419
-rw-r--r--preact/test/browser/lifecycles/getSnapshotBeforeUpdate.test.js211
-rw-r--r--preact/test/browser/lifecycles/lifecycle.test.js672
-rw-r--r--preact/test/browser/lifecycles/shouldComponentUpdate.test.js916
-rw-r--r--preact/test/browser/placeholders.test.js308
-rw-r--r--preact/test/browser/refs.test.js481
-rw-r--r--preact/test/browser/render.test.js1164
-rw-r--r--preact/test/browser/replaceNode.test.js239
-rw-r--r--preact/test/browser/select.test.js72
-rw-r--r--preact/test/browser/spec.test.js151
-rw-r--r--preact/test/browser/style.test.js225
-rw-r--r--preact/test/browser/svg.test.js226
-rw-r--r--preact/test/browser/toChildArray.test.js207
-rw-r--r--preact/test/extensions.d.ts5
-rw-r--r--preact/test/fixtures/preact.js626
-rw-r--r--preact/test/node/index.test.js15
-rw-r--r--preact/test/polyfills.js260
-rw-r--r--preact/test/shared/createContext.test.js24
-rw-r--r--preact/test/shared/createElement.test.js299
-rw-r--r--preact/test/shared/exports.test.js32
-rw-r--r--preact/test/shared/isValidElement.test.js5
-rw-r--r--preact/test/shared/isValidElementTests.js37
-rw-r--r--preact/test/ts/Component-test.tsx183
-rw-r--r--preact/test/ts/VNode-test.tsx197
-rw-r--r--preact/test/ts/custom-elements.tsx85
-rw-r--r--preact/test/ts/hoc-test.tsx50
-rw-r--r--preact/test/ts/jsx-namespacce-test.tsx16
-rw-r--r--preact/test/ts/preact-global-test.tsx6
-rw-r--r--preact/test/ts/preact.tsx297
-rw-r--r--preact/test/ts/refs.tsx76
-rw-r--r--preact/test/ts/tsconfig.json15
305 files changed, 78206 insertions, 0 deletions
diff --git a/preact/.codesandbox/ci.json b/preact/.codesandbox/ci.json
new file mode 100644
index 0000000..5f3f859
--- /dev/null
+++ b/preact/.codesandbox/ci.json
@@ -0,0 +1,4 @@
+{
+ "sandboxes": ["preact-x-preact-cli-3-starter-vj285y2rn3"],
+ "silent": true
+}
diff --git a/preact/.editorconfig b/preact/.editorconfig
new file mode 100644
index 0000000..0024e9d
--- /dev/null
+++ b/preact/.editorconfig
@@ -0,0 +1,16 @@
+root = true
+
+[*]
+indent_style = tab
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[{*.json,.*rc,*.yml}]
+indent_style = space
+indent_size = 2
+insert_final_newline = false
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/preact/.github/CODE_OF_CONDUCT.md b/preact/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..9e81e67
--- /dev/null
+++ b/preact/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@preactjs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/preact/.github/FUNDING.yml b/preact/.github/FUNDING.yml
new file mode 100644
index 0000000..bbe0c7d
--- /dev/null
+++ b/preact/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: [preactjs]
+open_collective: preact
diff --git a/preact/.github/ISSUE_TEMPLATE/bug_report.md b/preact/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..b0dd055
--- /dev/null
+++ b/preact/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,25 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+- [ ] Check if updating to the latest Preact version resolves the issue
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+
+If possible, please provide a CodeSandbox/Codepen that demonstrates the issue. You can use the following template: https://codesandbox.io/s/preact-x-preact-cli-3-starter-vj285y2rn3
+
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. See error
+
+**Expected behavior**
+What should have happened when following the steps above?
diff --git a/preact/.github/ISSUE_TEMPLATE/feature_request.md b/preact/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..b289625
--- /dev/null
+++ b/preact/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,14 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: feature request
+assignees: ''
+
+---
+
+**Describe the feature you'd love to see**
+A clear and concise description of what you'd love to see added to Preact.
+
+**Additional context (optional)**
+Add any other context or screenshots about the feature request here.
diff --git a/preact/.github/workflows/benchmarks.yml b/preact/.github/workflows/benchmarks.yml
new file mode 100644
index 0000000..0cb6685
--- /dev/null
+++ b/preact/.github/workflows/benchmarks.yml
@@ -0,0 +1,256 @@
+name: Benchmarks
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches:
+ - '**'
+ paths:
+ - 'src/**.js'
+ push:
+ branches:
+ - master
+ - restructure
+ paths:
+ - 'src/**.js'
+
+jobs:
+ prepare:
+ name: Prepare benchmarks
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - name: Cache node modules
+ uses: actions/cache@v1
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ # This uses the same name as the build-action so we can share the caches.
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+ - run: npm ci
+ - name: Package
+ # Use --ignore-scripts here to avoid re-building again before pack
+ run: |
+ npm pack --ignore-scripts
+ mv preact-*.tgz preact.tgz
+ tar -xzf preact.tgz
+ rm preact.tgz
+ - name: Upload build output
+ uses: actions/upload-artifact@v2
+ with:
+ name: build-output
+ path: package/
+ - uses: andrewiggins/download-base-artifact@v1
+ with:
+ artifact: npm-package
+ workflow: ci.yml
+ required: false
+ - name: Upload base preact package
+ uses: actions/upload-artifact@v2
+ with:
+ name: build-output
+ path: preact.tgz
+
+ bench_text_update:
+ name: Bench text_update
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench text_update.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/text_update.json
+
+ bench_many_updates:
+ name: Bench many_updates
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench many_updates.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/many_updates.json
+
+ bench_02_replace1k:
+ name: Bench 02_replace1k
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench 02_replace1k.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/02_replace1k.json
+
+ bench_03_update10th1k_x16:
+ name: Bench 03_update10th1k_x16
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench 03_update10th1k_x16.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/03_update10th1k_x16.json
+
+ bench_07_create10k:
+ name: Bench 07_create10k
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 20
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench 07_create10k.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/07_create10k.json
+
+ bench_hydrate1k:
+ name: Bench hydrate1k
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 20
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench hydrate1k.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/hydrate1k.json
+
+ bench_filter_list:
+ name: Bench filter_list
+ runs-on: ubuntu-latest
+ needs: prepare
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - uses: actions/download-artifact@v2
+ with:
+ name: build-output
+ - name: install & build
+ run: |
+ cd benches
+ npm ci
+ - name: bench
+ run: |
+ export CHROMEDRIVER_FILEPATH=$(which chromedriver)
+ cd benches
+ npm run bench filter_list.html
+ - name: Upload results
+ uses: actions/upload-artifact@v2
+ with:
+ name: results
+ path: benches/results/filter_list.json
diff --git a/preact/.github/workflows/ci.yml b/preact/.github/workflows/ci.yml
new file mode 100644
index 0000000..80dcd86
--- /dev/null
+++ b/preact/.github/workflows/ci.yml
@@ -0,0 +1,57 @@
+name: CI
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches:
+ - '**'
+ push:
+ branches:
+ - master
+ - restructure
+
+jobs:
+ build_test:
+ name: Build & Test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - name: Cache node modules
+ uses: actions/cache@v1
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ # This uses the same name as the build-action so we can share the caches.
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+ - run: npm ci
+ - name: test
+ env:
+ CI: true
+ COVERAGE: true
+ FLAKEY: false
+ # Not using `npm test` since it rebuilds source which npm ci has already done
+ run: |
+ npm run lint
+ npm run test:unit
+ - name: Coveralls GitHub Action
+ uses: coverallsapp/github-action@v1.0.1
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Package
+ # Use --ignore-scripts here to avoid re-building again before pack
+ run: |
+ npm pack --ignore-scripts
+ mv preact-*.tgz preact.tgz
+ - name: Upload npm package
+ uses: actions/upload-artifact@v2
+ with:
+ name: npm-package
+ path: preact.tgz
diff --git a/preact/.github/workflows/pr-reporter.yml b/preact/.github/workflows/pr-reporter.yml
new file mode 100644
index 0000000..b5e2f1b
--- /dev/null
+++ b/preact/.github/workflows/pr-reporter.yml
@@ -0,0 +1,51 @@
+name: Report Results to PR
+
+on:
+ # The pull_request event can't write comments for PRs from forks so using this
+ # workflow_run workflow as a workaround
+ workflow_run:
+ workflows: ['Benchmarks']
+ branches: ['**']
+ types:
+ - completed
+ - requested
+
+jobs:
+ report_running:
+ name: Report benchmarks are in-progress
+ runs-on: ubuntu-latest
+ # Only add the "benchmarks are running" text when a workflow_run is
+ # requested (a.k.a starting)
+ if: ${{ github.event.action == 'requested' }}
+ steps:
+ - name: Report Tachometer Running
+ uses: andrewiggins/tachometer-reporter-action@v2
+ with:
+ # Set initialize to true so this action just creates the comment or
+ # adds the "benchmarks are running" text
+ initialize: true
+
+ report_results:
+ name: Report benchmark results
+ runs-on: ubuntu-latest
+ # Only run this job if the event action was "completed" and the triggering
+ # workflow_run was successful
+ if: ${{ github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' }}
+ steps:
+ # Download the artifact from the triggering workflow that contains the
+ # Tachometer results to report
+ - uses: dawidd6/action-download-artifact@v2
+ with:
+ workflow: ${{ github.event.workflow.id }}
+ run_id: ${{ github.event.workflow_run.id }}
+ name: results
+ path: results
+
+ # Create/update the comment with the latest results
+ - name: Report Tachometer Results
+ uses: andrewiggins/tachometer-reporter-action@v2
+ with:
+ path: results/*.json
+ base-bench-name: preact-master
+ pr-bench-name: preact-local
+ summarize: 'duration, usedJSHeapSize'
diff --git a/preact/.github/workflows/saucelabs.yml b/preact/.github/workflows/saucelabs.yml
new file mode 100644
index 0000000..e26ae2b
--- /dev/null
+++ b/preact/.github/workflows/saucelabs.yml
@@ -0,0 +1,42 @@
+name: Saucelabs
+
+on:
+ push:
+ branches:
+ - master
+ - restructure
+
+jobs:
+ build_test:
+ name: Build & Test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 1
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+ - name: Cache node modules
+ uses: actions/cache@v1
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ # This uses the same name as the build-action so we can share the caches.
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
+ - run: npm ci
+ - name: test
+ env:
+ CI: true
+ COVERAGE: true
+ FLAKEY: false
+ RUN_SAUCE_LABS: true
+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
+ # Not using `npm test` since it rebuilds source which npm ci has already done
+ run: npm run test:unit
diff --git a/preact/.github/workflows/size.yml b/preact/.github/workflows/size.yml
new file mode 100644
index 0000000..f886534
--- /dev/null
+++ b/preact/.github/workflows/size.yml
@@ -0,0 +1,17 @@
+name: Compressed Size
+
+on:
+ pull_request:
+ branches:
+ - '**'
+ paths:
+ - '**/src/**.js'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: preactjs/compressed-size-action@v1
+ with:
+ repo-token: '${{ secrets.GITHUB_TOKEN }}'
diff --git a/preact/.gitignore b/preact/.gitignore
new file mode 100644
index 0000000..54e501b
--- /dev/null
+++ b/preact/.gitignore
@@ -0,0 +1,16 @@
+.DS_Store
+node_modules
+npm-debug.log
+dist
+*/package-lock.json
+yarn.lock
+.vscode
+.idea
+test/ts/**/*.js
+coverage
+*.sw[op]
+*.log
+package/
+preact-*.tgz
+preact.tgz
+jsx-csstype.d.ts
diff --git a/preact/CODE_OF_CONDUCT.md b/preact/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..9e81e67
--- /dev/null
+++ b/preact/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@preactjs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/preact/CONTRIBUTING.md b/preact/CONTRIBUTING.md
new file mode 100644
index 0000000..465acad
--- /dev/null
+++ b/preact/CONTRIBUTING.md
@@ -0,0 +1,237 @@
+# Contributing
+
+This document is intended for developers interest in making contributions to Preact and document our internal processes like releasing a new version.
+
+## Getting Started
+
+This steps will help you to set up your development environment. That includes all dependencies we use to build Preact and developer tooling like git commit hooks.
+
+1. Clone the git repository: `git clone git@github.com:preactjs/preact.git`
+2. Go into the cloned folder: `cd preact/`
+3. Install all dependencies: `npm install`
+
+## The Repo Structure
+
+This repository contains Preact itself, as well as several addons like the debugging package for example. This is reflected in the directory structure of this repository. Each package has a `src/` folder where the source code can be found, a `test` folder for all sorts of tests that check if the code in `src/` is correct, and a `dist/` folder where you can find the bundled artifacts. Note that the `dist/` folder may not be present initially. It will be created as soon as you run any of the build scripts inside `package.json`. More on that later ;)
+
+A quick overview of our repository:
+
+```bash
+# The repo root (folder where you cloned the repo into)
+/
+ src/ # Source code of our core
+ test/ # Unit tests for core
+ dist/ # Build artifacts for publishing on npm (may not be present)
+
+ # Sub-package, can be imported via `preact/compat` by users.
+ # Compat stands for react-compatibility layer which tries to mirror the
+ # react API as close as possible (mostly legacy APIs)
+ compat/
+ src/ # Source code of the compat addon
+ test/ # Tests related to the compat addon
+ dist/ # Build artifacts for publishing on npm (may not be present)
+
+ # Sub-package, can be imported via `preact/hooks` by users.
+ # The hooks API is an effect based API to deal with component lifcycles.
+ # It's similar to hooks in React
+ hooks/
+ src/ # Source code of the hooks addon
+ test/ # Tests related to the hooks addon
+ dist/ # Build artifacts for publishing on npm (may not be present)
+
+ # Sub-package, can be imported via `preact/debug` by users.
+ # Includes debugging warnings and error messages for common mistakes found
+ # in Preact application. Also hosts the devtools bridge
+ debug/
+ src/ # Source code of the debug addon
+ test/ # Tests related to the debug addon
+ dist/ # Build artifacts for publishing on npm (may not be present)
+
+ # Sub-package, can be imported via `preact/test-utils` by users.
+ # Provides helpers to make testing Preact applications easier
+ test-utils/
+ src/ # Source code of the test-utils addon
+ test/ # Tests related to the test-utils addon
+ dist/ # Build artifacts for publishing on npm (may not be present)
+
+ # A demo application that we use to debug tricky errors and play with new
+ # features.
+ demo/
+
+ # Contains build scripts and dependencies for development
+ package.json
+```
+
+_Note: The code for rendering Preact on the server lives in another repo and is a completely separate npm package. It can be found here: [https://github.com/preactjs/preact-render-to-string](https://github.com/preactjs/preact-render-to-string)_
+
+### What does `mangle.json` do?
+
+It's a special file that can be used to specify how `terser` (previously known as `uglify`) will minify variable names. Because each sub-package has it's own distribution files we need to ensure that the variable names stay consistent across bundles.
+
+## What does `options.js` do?
+
+Unique to Preact we do support several ways to hook into our renderer. All our addons use that to inject code at different stages of a render process. They are documented in our typings in `internal.d.ts`. The core itself doesn't make use of them, which is why the file only contains an empty `object`.
+
+## Important Branches
+
+We merge every PR into the `master` branch which is the one that we'll use to publish code to npm. For the previous Preact release line we have a branch called `8` which is in maintenance mode. As a new contributor you won't have to deal with that ;)
+
+## Creating your first Pull-Request
+
+We try to make it as easy as possible to contribute to Preact and make heavy use of GitHub's "Draft PR" feature which tags Pull-Requests (short = PR) as work in progress. PRs tend to be published as soon as there is an idea that the developer deems worthwhile to include into Preact and has written some rough code. The PR doesn't have to be perfect or anything really ;)
+
+Once a PR or a Draft PR has been created our community typically joins the discussion about the proposed change. Sometimes that includes ideas for test cases or even different ways to go about implementing a feature. Often this also includes ideas on how to make the code smaller. We usually refer to the latter as "code-golfing" or just "golfing".
+
+When everything is good to go someone will approve the PR and the changes will be merged into the `master` branch and we usually cut a release a few days/ a week later.
+
+_The big takeaway for you here is, that we will guide you along the way. We're here to help to make a PR ready for approval!_
+
+The short summary is:
+
+1. Make changes and submit a PR
+2. Modify change according to feedback (if there is any)
+3. PR will be merged into `master`
+4. A new release will be cut (every 2-3 weeks).
+
+## Commonly used scripts for contributions
+
+Scripts can be executed via `npm run [script]` or `yarn [script]` respectively.
+
+- `build` - compiles all packages ready for publishing to npm
+- `build:core` - builds just Preact itself
+- `build:debug` - builds the debug addon only
+- `build:hooks` - builds the hook addon only
+- `build:test-utils` - builds the test-utils addon only
+- `test:ts` - Run all tests for TypeScript definitions
+- `test:karma` - Run all unit/integration tests.
+- `test:karma:watch` - Same as above, but it will automatically re-run the test suite if a code change was detected.
+
+But to be fair, the only ones we use ourselves are `build` and `test:karma:watch`. The other ones are mainly used on our CI pipeline and we rarely use them.
+
+_Note: Both `test:karma` and `test:karma:watch` listen to the environment variable `COVERAGE=true`. Disabling code coverage can significantly speed up the time it takes to complete the test suite._
+
+_Note2: The test suite is based on `karma` and `mocha`. Individual tests can be executed by appending `.only`:_
+
+```jsx
+it.only('should test something', () => {
+ expect(1).to.equal(1);
+});
+```
+
+## Common terminology and variable names
+
+- `vnode` -> shorthand for `virtual-node` which is an object that specifies how a Component or DOM-node looks like
+- `commit` -> A commit is the moment in time when you flush all changes to the DOM
+- `c` -> The variable `c` always refers to a `component` instance throughout our code base.
+- `diff/diffing` -> Diffing describes the process of comparing two "things". In our case we compare the previous `vnode` tree with the new one and apply the delta to the DOM.
+- `root` -> The topmost node of a `vnode` tree
+
+## Tips for getting to know the code base
+
+- Check the JSDoc block right above the function definition to understand what it does. It contains a short description of each function argument and what it does.
+- Check the callsites of a function to understand how it's used. Modern editors/IDEs allow you to quickly find those, or use the plain old search feature instead.
+
+## FAQ
+
+### Why does the JSDoc use TypeScript syntax to specify types?
+
+Several members of the team are very fond of TypeScript and we wanted to leverage as many of its advantages, like improved autocompletion, for Preact. We even attempted to port Preact to TypeScript a few times, but we ran into many issues with the DOM typings. Those would force us to fill our codebase with many `any` castings, making our code very noisy.
+
+Luckily TypeScript has a mode where it can somewhat reliably typecheck JavaScript code by reusing the types defined in JSDoc blocks. It's not perfect and it often has trouble inferring the correct types the further one strays away from the function arguments, but it's good enough that it helps us a lot with autocompletion. Another plus is that we can make sure that our TypeScript definitons are correct at the same time.
+
+Check out the [official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html) for more information.
+
+_Note that we have separate tests for our TypeScript definition files. We only use `ts-check` for local development and don't check it anywhere else like on the CI._
+
+### Why does the code base often use `let` instead of `const`?
+
+There is no real reason for that other a historical one. Back before auto-formatting via prettier was a thing and minifiers weren't as advanced as they are today we used a pretty terse code-style. The code-style deliberately was aimed at making code look as concise and short as possible. The `let` keyword is a bit shorter than `const` to write, so we only used that. This was done only for stylistic reasons.
+
+This helped our minds to not lose sight of focusing on size, but made it difficult for newcomers to start contributing to Preact. For that reason alone we switched to `prettier` and loosened our rule regarding usage of `let` or `const`. Today we use both, but you can still find many existing places where `let` is still in use.
+
+In the end there is no effect on size regardless if you use `const`, `let` or use both. Our code is downtranspiled to `ES5` for npm so both will be replaced with `var` anyways. Therefore it doesn't really matter at all which one is used in our codebase.
+
+This will only become important once shipping modern JavaScript code on npm becomes a thing and bundlers follow suit.
+
+## How to create a good bug report
+
+To be able to fix issues we need to see them on our machine. This is only possible when we can reproduce the error. The easiest way to do that is narrow down the problem to specific components or combination of them. This can be done by removing as much unrelated code as possible.
+
+The perfect way to do that is to make a [codesandbox](https://codesandbox.io/). That way you can easily share the problematic code and ensure that others can see the same issue you are seeing.
+
+For us a [codesandbox](https://codesandbox.io/) says more than a 1000 words :tada:
+
+## I have more questions on how to contribute to Preact. How can I reach you?
+
+We closely watch our issues and have a pretty active [Slack workspace](https://chat.preactjs.com/). Nearly all our communication happens via these two forms of communication.
+
+## Releasing Preact (Maintainers only)
+
+This guide is intended for core team members that have the necessary
+rights to publish new releases on npm.
+
+1. [Write the release notes](#writing-release-notes) and keep them as a draft in GitHub
+ 1. I'd recommend writing them in an offline editor because each edit to a draft will change the URL in GitHub.
+2. Make a PR where **only** the version number is incremented in `package.json` (note: We follow `SemVer` conventions)
+3. Wait until the PR is approved and merged.
+4. Switch back to the `master` branch and pull the merged PR
+5. Run `npm run build && npm publish`
+ 1. Make sure you have 2FA enabled in npm, otherwise the above command will fail.
+ 2. If you're doing a pre-release add `--tag next` to the `npm publish` command to publish it under a different tag (default is `latest`)
+6. Publish the release notes and create the correct git tag.
+7. Tweet it out
+
+## Legacy Releases (8.x)
+
+> **ATTENTION:** Make sure that you've cleared the project correctly
+> when switching from a 10.x branch.
+
+0. Run `rm -rf dist node_modules && npm i` to make sure to have the correct dependencies.
+
+Apart from that it's the same as above.
+
+## Writing release notes
+
+The release notes have become a sort of tiny blog post about what's
+happening in preact-land. The title usually has this format:
+
+```txt
+Version Name
+```
+
+Example:
+
+```txt
+10.0.0-beta.1 Los Compresseros
+```
+
+The name is optional, we just have fun finding creative names :wink:
+
+To keep them interesting we try to be as
+concise as possible and to just reflect where we are. There are some
+rules we follow while writing them:
+
+- Be nice, use a positive tone. Avoid negative words
+- Show, don't just tell.
+- Be honest.
+- Don't write too much, keep it simple and short.
+- Avoid making promises and don't overpromise. That leads to unhappy users
+- Avoid framework comparisons if possible
+- Highlight awesome community contributions (or great issue reports)
+- If in doubt, praise the users.
+
+After this section we typically follow with a changelog part that's
+divided into 4 groups in order of importance for the user:
+
+- Features
+- Bug Fixes
+- Typings
+- Maintenance
+
+We generate it via this handy cli program: [changelogged](https://github.com/marvinhagemeister/changelogged). It will collect and format
+the descriptions of all PRs that have been merged between two tags.
+The usual command is `changelogged 10.0.0-rc.2..HEAD` similar to how
+you'd diff two points in time with git. This will get you 90% there,
+but you still need to divide it into groups. It's also a good idea
+to unify the formatting of the descriptions, so that they're easier
+to read and don't look like a mess.
diff --git a/preact/LICENSE b/preact/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/README.md b/preact/README.md
new file mode 100644
index 0000000..458cdae
--- /dev/null
+++ b/preact/README.md
@@ -0,0 +1,187 @@
+<p align="center">
+<a href="https://preactjs.com" target="_blank">
+
+![Preact](https://raw.githubusercontent.com/preactjs/preact/8b0bcc927995c188eca83cba30fbc83491cc0b2f/logo.svg?sanitize=true "Preact")
+
+</a>
+</p>
+<p align="center">Fast <b>3kB</b> alternative to React with the same modern API.</p>
+
+**All the power of Virtual DOM components, without the overhead:**
+
+- Familiar React API & patterns: ES6 Class, hooks, and Functional Components
+- Extensive React compatibility via a simple [preact/compat] alias
+- Everything you need: JSX, <abbr title="Virtual DOM">VDOM</abbr>, [DevTools], <abbr title="Hot Module Replacement">HMR</abbr>, <abbr title="Server-Side Rendering">SSR</abbr>.
+- Highly optimized diff algorithm and seamless hydration from Server Side Rendering
+- Supports all modern browsers and IE11
+- Transparent asynchronous rendering with a pluggable scheduler
+- **Instant production-grade app setup with [Preact CLI](https://github.com/preactjs/preact-cli)**
+
+### 💁 More information at the [Preact Website ➞](https://preactjs.com)
+
+
+<table border="0">
+<tbody>
+<tr>
+<td>
+
+[![npm](https://img.shields.io/npm/v/preact.svg)](http://npm.im/preact)
+[![Preact Slack Community](https://preact-slack.now.sh/badge.svg)](https://chat.preactjs.com)
+[![OpenCollective Backers](https://opencollective.com/preact/backers/badge.svg)](#backers)
+[![OpenCollective Sponsors](https://opencollective.com/preact/sponsors/badge.svg)](#sponsors)
+
+[![coveralls](https://img.shields.io/coveralls/preactjs/preact/master.svg)](https://coveralls.io/github/preactjs/preact)
+[![gzip size](http://img.badgesize.io/https://unpkg.com/preact/dist/preact.min.js?compression=gzip&label=gzip)](https://unpkg.com/preact/dist/preact.min.js)
+[![brotli size](http://img.badgesize.io/https://unpkg.com/preact/dist/preact.min.js?compression=brotli&label=brotli)](https://unpkg.com/preact/dist/preact.min.js)
+</td>
+<td>
+
+<img src="https://saucelabs.com/browser-matrix/preact.svg" title="Browser support matrix">
+
+</td>
+</tr>
+</tbody>
+</table>
+
+
+You can find some awesome libraries in the [awesome-preact list](https://github.com/preactjs/awesome-preact) :sunglasses:
+
+---
+
+## Getting Started
+
+> 💁 _**Note:** You [don't need ES2015 to use Preact](https://github.com/developit/preact-in-es3)... but give it a try!_
+
+The easiest way to get started with Preact is to use [Preact CLI](https://github.com/preactjs/preact-cli). This simple command-line tool wraps up the best possible tooling for you, and even keeps things like Webpack and Babel up-to-date as they change. Best of all, it's easy to understand! Start a project or compile for production in a single command (`preact build`), with no configuration needed and best practices baked in! 🙌
+
+#### Tutorial: Building UI with Preact
+
+With Preact, you create user interfaces by assembling trees of components and elements. Components are functions or classes that return a description of what their tree should output. These descriptions are typically written in [JSX](https://facebook.github.io/jsx/) (shown underneath), or [HTM](https://github.com/developit/htm) which leverages standard JavaScript Tagged Templates. Both syntaxes can express trees of elements with "props" (similar to HTML attributes) and children.
+
+To get started using Preact, first look at the render() function. This function accepts a tree description and creates the structure described. Next, it appends this structure to a parent DOM element provided as the second argument. Future calls to render() will reuse the existing tree and update it in-place in the DOM. Internally, render() will calculate the difference from previous outputted structures in an attempt to perform as few DOM operations as possible.
+
+```js
+import { h, render } from 'preact';
+// Tells babel to use h for JSX. It's better to configure this globally.
+// See https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#usage
+// In tsconfig you can specify this with the jsxFactory
+/** @jsx h */
+
+// create our tree and append it to document.body:
+render(<main><h1>Hello</h1></main>, document.body);
+
+// update the tree in-place:
+render(<main><h1>Hello World!</h1></main>, document.body);
+// ^ this second invocation of render(...) will use a single DOM call to update the text of the <h1>
+```
+
+Hooray! render() has taken our structure and output a User Interface! This approach demonstrates a simple case, but would be difficult to use as an application grows in complexity. Each change would be forced to calculate the difference between the current and updated structure for the entire application. Components can help here – by dividing the User Interface into nested Components each can calculate their difference from their mounted point. Here's an example:
+
+```js
+import { render, h } from 'preact';
+import { useState } from 'preact/hooks';
+
+/** @jsx h */
+
+const App = () => {
+ const [input, setInput] = useState('');
+
+ return (
+ <div>
+ <p>Do you agree to the statement: "Preact is awesome"?</p>
+ <input value={input} onChange={e => setInput(e.target.value)} />
+ </div>
+ )
+}
+
+render(<App />, document.body);
+```
+
+---
+
+## Backers
+
+Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/preact#backer)]
+
+<a href="https://opencollective.com/preact/backer/0/website" target="_blank"><img src="https://opencollective.com/preact/backer/0/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/1/website" target="_blank"><img src="https://opencollective.com/preact/backer/1/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/2/website" target="_blank"><img src="https://opencollective.com/preact/backer/2/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/3/website" target="_blank"><img src="https://opencollective.com/preact/backer/3/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/4/website" target="_blank"><img src="https://opencollective.com/preact/backer/4/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/5/website" target="_blank"><img src="https://opencollective.com/preact/backer/5/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/6/website" target="_blank"><img src="https://opencollective.com/preact/backer/6/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/7/website" target="_blank"><img src="https://opencollective.com/preact/backer/7/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/8/website" target="_blank"><img src="https://opencollective.com/preact/backer/8/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/9/website" target="_blank"><img src="https://opencollective.com/preact/backer/9/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/10/website" target="_blank"><img src="https://opencollective.com/preact/backer/10/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/11/website" target="_blank"><img src="https://opencollective.com/preact/backer/11/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/12/website" target="_blank"><img src="https://opencollective.com/preact/backer/12/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/13/website" target="_blank"><img src="https://opencollective.com/preact/backer/13/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/14/website" target="_blank"><img src="https://opencollective.com/preact/backer/14/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/15/website" target="_blank"><img src="https://opencollective.com/preact/backer/15/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/16/website" target="_blank"><img src="https://opencollective.com/preact/backer/16/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/17/website" target="_blank"><img src="https://opencollective.com/preact/backer/17/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/18/website" target="_blank"><img src="https://opencollective.com/preact/backer/18/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/19/website" target="_blank"><img src="https://opencollective.com/preact/backer/19/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/20/website" target="_blank"><img src="https://opencollective.com/preact/backer/20/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/21/website" target="_blank"><img src="https://opencollective.com/preact/backer/21/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/22/website" target="_blank"><img src="https://opencollective.com/preact/backer/22/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/23/website" target="_blank"><img src="https://opencollective.com/preact/backer/23/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/24/website" target="_blank"><img src="https://opencollective.com/preact/backer/24/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/25/website" target="_blank"><img src="https://opencollective.com/preact/backer/25/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/26/website" target="_blank"><img src="https://opencollective.com/preact/backer/26/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/27/website" target="_blank"><img src="https://opencollective.com/preact/backer/27/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/28/website" target="_blank"><img src="https://opencollective.com/preact/backer/28/avatar.svg"></a>
+<a href="https://opencollective.com/preact/backer/29/website" target="_blank"><img src="https://opencollective.com/preact/backer/29/avatar.svg"></a>
+<a href="https://github.com/guardian" target="_blank"><img src="https://github.com/guardian.png?size=64"></a>
+
+
+
+## Sponsors
+Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/preact#sponsor)]
+
+<a href="https://opencollective.com/preact/sponsor/0/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/0/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/1/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/1/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/2/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/2/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/3/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/3/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/4/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/4/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/5/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/5/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/6/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/6/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/7/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/7/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/8/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/8/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/9/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/9/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/10/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/10/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/11/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/11/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/12/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/12/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/13/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/13/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/14/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/14/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/15/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/15/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/16/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/16/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/17/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/17/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/18/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/18/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/19/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/19/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/20/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/20/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/21/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/21/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/22/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/22/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/23/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/23/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/24/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/24/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/25/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/25/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/26/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/26/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/27/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/27/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/28/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/28/avatar.svg"></a>
+<a href="https://opencollective.com/preact/sponsor/29/website" target="_blank"><img src="https://opencollective.com/preact/sponsor/29/avatar.svg"></a>
+
+---
+
+## License
+
+MIT
+
+
+
+[![Preact](https://i.imgur.com/YqCHvEW.gif)](https://preactjs.com)
+
+
+[preact/compat]: https://github.com/preactjs/preact/tree/master/compat
+[hyperscript]: https://github.com/dominictarr/hyperscript
+[DevTools]: https://github.com/preactjs/preact-devtools
diff --git a/preact/babel.config.js b/preact/babel.config.js
new file mode 100644
index 0000000..2a701eb
--- /dev/null
+++ b/preact/babel.config.js
@@ -0,0 +1,47 @@
+module.exports = function(api) {
+ api.cache(true);
+
+ const minify = String(process.env.MINIFY) === 'true';
+ const noModules = String(process.env.BABEL_NO_MODULES) === 'true';
+
+ const rename = {};
+ const mangle = require('./mangle.json');
+ for (let prop in mangle.props.props) {
+ let name = prop;
+ if (name[0] === '$') {
+ name = name.slice(1);
+ }
+
+ rename[name] = mangle.props.props[prop];
+ }
+
+ return {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ loose: true,
+ // Don't transform modules when using esbuild
+ modules: noModules ? false : 'auto',
+ exclude: ['@babel/plugin-transform-typeof-symbol'],
+ targets: {
+ browsers: ['last 2 versions', 'IE >= 9']
+ }
+ }
+ ]
+ ],
+ plugins: [
+ '@babel/plugin-proposal-object-rest-spread',
+ '@babel/plugin-transform-react-jsx',
+ 'babel-plugin-transform-async-to-promises',
+ ['babel-plugin-transform-rename-properties', { rename }]
+ ],
+ include: ['**/src/**/*.js', '**/test/**/*.js'],
+ overrides: [
+ {
+ test: /(component-stack|debug)\.test\.js$/,
+ plugins: ['@babel/plugin-transform-react-jsx-source']
+ }
+ ]
+ };
+};
diff --git a/preact/benches/.gitignore b/preact/benches/.gitignore
new file mode 100644
index 0000000..507e011
--- /dev/null
+++ b/preact/benches/.gitignore
@@ -0,0 +1,6 @@
+dist/
+results/
+logs/
+logs-saved/
+node_modules/
+proxy-packages/*/package-lock.json
diff --git a/preact/benches/LICENSE b/preact/benches/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/benches/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/benches/README.md b/preact/benches/README.md
new file mode 100644
index 0000000..066b5fa
--- /dev/null
+++ b/preact/benches/README.md
@@ -0,0 +1,72 @@
+# Preact Benchmarks
+
+This directory contains benchmarks for Preact, run using the [`polymer/tachometer`](https://github.com/polymer/tachometer) project.
+
+## Getting Started
+
+To run benchmark suite, use `npm bench`.
+
+To debug benches locally, use `npm start`.
+
+### bench
+
+Use the `npm bench` command to run some (or all, the default) benchmarks locally.
+
+```text
+> node ./scripts bench "--help"
+
+ Description
+ Run the benchmarks matching the given globs.
+ The root for the globs is the "src" directory.
+ Specify "all" to run all benchmarks.
+ To get more help on options, see polymer/tachometer help.
+ Result table is printed to stdout and written to a csv and json file in the results directory.
+
+ Usage
+ $ ./scripts bench [globs] [options]
+
+ Options
+ -n, --sample-size Minimum number of times to run each benchmark (default 50)
+ --horizon The degrees of difference to try and resolve when auto-sampling ("N%" or "Nms", comma-delimited) (default 10%)
+ --timeout The maximum number of minutes to spend auto-sampling (default 3)
+ -h, --help Displays this message
+
+ Examples
+ $ ./scripts bench text*
+ $ ./scripts bench **/*.html
+ $ ./scripts bench all
+
+```
+
+The `bench` command generates a tachometer config file for each benchmark matching the given globs. It then runs tachometer on each config file. If you would create one config file containing all the benchmarks, then Tachometer would produce one table comparing all package versions to each other across benchmarks which wouldn't be as useful. By generating a config per benchmark, Tachometer will output a table per benchmark comparing how each package version performed on just that benchmark.
+
+### start
+
+Use the `npm start` command to start the benchmark server but not run the benchmarks. This command is useful to debug or profile how a benchmark is doing. Tachometer starts a web server for each package version we run (note the port difference per package version in the sample output below). It provides a sample URL at which to point your browser to run a benchmark. You can run any benchmark in the `src` directory, not just the one in the sample URL.
+
+```bash
+> npm start
+
+...snipped some debug output...
+
+Visit these URLs in any browser:
+
+text_update [@preact8]
+http://127.0.0.1:8080/src/text_update.html
+
+text_update [@preact10]
+http://127.0.0.1:8081/src/text_update.html
+
+text_update [@preactLocal]
+http://127.0.0.1:8082/src/text_update.html
+```
+
+## Contributing
+
+To contribute a new benchmark, look at the existing benchmarks (the HTML files in `src`) to get an idea of what a benchmark can look like. Then read up on how [`polymer/tachometer`](https://github.com/polymer/tachometer) works to understand some of the options available to you.
+
+Add an HTML file containing the benchmark you'd like to run. Use `npm start` (documented above) to test and debug your benchmark. Then run `npm bench YOUR_BENCH.html` to run it. Note while initialling developing it may be easier to limit the amount of samples taken while benching. Use the options documented for the `npm bench` command to customize the sample size and auto-sample timeout.
+
+Currently this infra is only setup to run benchmarks against different preact versions and requires that your benchmark use the `bench.start()` and `bench.stop()` methods.
+
+The `src/util.js` file contains some utility functions for running your benchmark. For, example the `afterFrame/afterFrameAsync` functions can be used to run `bench.stop()` after the browser as painted the next frame. The `testElement/testElementText` functions can be used to verify that the benchmark implementation rendered the expected result properly.
diff --git a/preact/benches/TODO.md b/preact/benches/TODO.md
new file mode 100644
index 0000000..ec9430f
--- /dev/null
+++ b/preact/benches/TODO.md
@@ -0,0 +1,10 @@
+* Add `preact-release` proxy
+ - to capture slowdowns overtime
+* Report `initial-run` metric to PR
+ - to capture unoptimized runtime which would be an important metric to understand perf characteristic before optimizations kick in
+* Add warmup reporting to all benchmarks
+* Add `preact-compat` proxy
+* Add UIBench
+* Add bench mimicking speedometer
+* Add a realworld-like bench?
+* Add a specialized bench that hits certain code paths other's miss (e.g. style attribute handling?)
diff --git a/preact/benches/jsconfig.json b/preact/benches/jsconfig.json
new file mode 100644
index 0000000..28c8242
--- /dev/null
+++ b/preact/benches/jsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "target": "es2020",
+ "checkJs": true,
+ "moduleResolution": "node"
+ },
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/preact/benches/package.json b/preact/benches/package.json
new file mode 100644
index 0000000..e3bdd07
--- /dev/null
+++ b/preact/benches/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "preact-benchmarks",
+ "private": true,
+ "version": "1.0.0",
+ "type": "module",
+ "description": "Benchmarks for Preact",
+ "scripts": {
+ "start": "node ./scripts config many_updates.html && tach --force-clean-npm-install --config dist/many_updates.config.json --manual",
+ "analyze": "node ./scripts analyze",
+ "bench": "node ./scripts bench",
+ "deopts": "node ./scripts deopts",
+ "help": "node ./scripts --help"
+ },
+ "license": "MIT",
+ "dependencies": {
+ "afterframe": "^1.0.1"
+ },
+ "devDependencies": {
+ "@kristoferbaxter/async": "^1.0.0",
+ "del": "^6.0.0",
+ "escalade": "^3.0.2",
+ "escape-string-regexp": "^4.0.0",
+ "globby": "^11.0.0",
+ "prompts": "^2.4.0",
+ "sade": "^1.7.3",
+ "strip-ansi": "^6.0.0",
+ "tachometer": "^0.5.7",
+ "v8-deopt-viewer": "^0.2.1"
+ }
+}
diff --git a/preact/benches/proxy-packages/preact-local-proxy/index.js b/preact/benches/proxy-packages/preact-local-proxy/index.js
new file mode 100644
index 0000000..1b3d7b2
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-local-proxy/index.js
@@ -0,0 +1,18 @@
+import { render, hydrate } from 'preact';
+
+export * from 'preact';
+
+/**
+ * @param {HTMLElement} rootDom
+ * @returns {{ render(vnode: JSX.Element): void; hydrate(vnode: JSX.Element): void; }}
+ */
+export function createRoot(rootDom) {
+ return {
+ render(vnode) {
+ render(vnode, rootDom);
+ },
+ hydrate(vnode) {
+ hydrate(vnode, rootDom);
+ }
+ };
+}
diff --git a/preact/benches/proxy-packages/preact-local-proxy/package.json b/preact/benches/proxy-packages/preact-local-proxy/package.json
new file mode 100644
index 0000000..344d845
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-local-proxy/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "preact-local-proxy",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "main": "index.js",
+ "dependencies": {
+ "preact": "file:../../../"
+ }
+}
diff --git a/preact/benches/proxy-packages/preact-master-proxy/index.js b/preact/benches/proxy-packages/preact-master-proxy/index.js
new file mode 100644
index 0000000..1b3d7b2
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-master-proxy/index.js
@@ -0,0 +1,18 @@
+import { render, hydrate } from 'preact';
+
+export * from 'preact';
+
+/**
+ * @param {HTMLElement} rootDom
+ * @returns {{ render(vnode: JSX.Element): void; hydrate(vnode: JSX.Element): void; }}
+ */
+export function createRoot(rootDom) {
+ return {
+ render(vnode) {
+ render(vnode, rootDom);
+ },
+ hydrate(vnode) {
+ hydrate(vnode, rootDom);
+ }
+ };
+}
diff --git a/preact/benches/proxy-packages/preact-master-proxy/package.json b/preact/benches/proxy-packages/preact-master-proxy/package.json
new file mode 100644
index 0000000..a73c202
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-master-proxy/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "preact-proxy",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "main": "index.js",
+ "dependencies": {
+ "preact": "file:../../../preact.tgz"
+ }
+}
diff --git a/preact/benches/proxy-packages/preact-v8-proxy/index.js b/preact/benches/proxy-packages/preact-v8-proxy/index.js
new file mode 100644
index 0000000..8c75330
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-v8-proxy/index.js
@@ -0,0 +1,23 @@
+import { render } from 'preact';
+
+export * from 'preact';
+
+/**
+ * @param {HTMLElement} rootDom
+ * @returns {{ render(vnode: JSX.Element): void; hydrate(vnode: JSX.Element): void; }}
+ */
+export function createRoot(rootDom) {
+ let result;
+ return {
+ render(vnode) {
+ if (result) {
+ result = render(vnode, rootDom, result);
+ } else {
+ result = render(vnode, rootDom);
+ }
+ },
+ hydrate(vnode) {
+ render(vnode, rootDom, rootDom.firstElementChild);
+ }
+ };
+}
diff --git a/preact/benches/proxy-packages/preact-v8-proxy/package.json b/preact/benches/proxy-packages/preact-v8-proxy/package.json
new file mode 100644
index 0000000..1ac098d
--- /dev/null
+++ b/preact/benches/proxy-packages/preact-v8-proxy/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "preact-v8-proxy",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "main": "index.js",
+ "dependencies": {
+ "preact": "^8.5.3"
+ }
+}
diff --git a/preact/benches/scripts/analyze.js b/preact/benches/scripts/analyze.js
new file mode 100644
index 0000000..b57f9d4
--- /dev/null
+++ b/preact/benches/scripts/analyze.js
@@ -0,0 +1,363 @@
+import { existsSync } from 'fs';
+import { readFile, readdir } from 'fs/promises';
+import prompts from 'prompts';
+import { baseTraceLogDir, frameworks } from './config.js';
+
+// @ts-ignore
+import tachometerStats from 'tachometer/lib/stats.js';
+// @ts-ignore
+import tachometerFormat from 'tachometer/lib/format.js';
+
+/**
+ * @typedef {import('./tracing').TraceEvent} TraceEvent
+ * @typedef {import('tachometer/lib/stats').SummaryStats} SummaryStats
+ * @typedef {import('tachometer/lib/stats').ResultStats} ResultStats
+ * @typedef {import('tachometer/lib/stats').ResultStatsWithDifferences} ResultStatsWithDifferences
+ * @type {import('tachometer/lib/stats')}
+ */
+const statsLib = tachometerStats;
+const { summaryStats, computeDifferences } = statsLib;
+/** @type {import('tachometer/lib/format')} */
+const formatLib = tachometerFormat;
+const { automaticResultTable, verticalTermResultTable } = formatLib;
+
+const toTrack = new Set([
+ // 'V8.CompileCode', // Might be tachometer code?? But maybe not?
+ 'V8.MarkCandidatesForOptimization',
+ 'V8.OptimizeCode',
+ 'V8.OptimizeConcurrentPrepare',
+ 'V8.OptimizeNonConcurrent',
+ // 'V8.OptimizeBackground', // Runs on background thread
+ 'V8.InstallOptimizedFunctions',
+ 'V8.DeoptimizeCode',
+ 'MinorGC',
+ 'V8.GCDeoptMarkedAllocationSites'
+]);
+
+/**
+ * @template T
+ * @param {Map<string, T[]>} grouping
+ * @param {Map<string, T | T[]>} results
+ */
+function addToGrouping(grouping, results) {
+ for (let [group, data] of results.entries()) {
+ if (grouping.has(group)) {
+ if (Array.isArray(data)) {
+ grouping.get(group).push(...data);
+ } else {
+ grouping.get(group).push(data);
+ }
+ } else {
+ if (Array.isArray(data)) {
+ grouping.set(group, data);
+ } else {
+ grouping.set(group, [data]);
+ }
+ }
+ }
+}
+
+/**
+ * @template K
+ * @template V
+ * @param {Map<K, V[]>} map
+ * @param {K} key
+ * @param {...V} values
+ */
+function addToMapArray(map, key, ...values) {
+ if (map.has(key)) {
+ map.get(key).push(...values);
+ } else {
+ map.set(key, values);
+ }
+}
+
+/**
+ * @template K
+ * @template V
+ * @param {Map<K, V[]>} map
+ * @param {K} key
+ * @param {number} index
+ * @param {V} value
+ */
+function setInMapArray(map, key, index, value) {
+ if (map.has(key)) {
+ map.get(key)[index] = value;
+ } else {
+ map.set(key, [value]);
+ }
+}
+
+/**
+ * @param {ResultStats[]} results
+ */
+function logDifferences(key, results) {
+ let withDifferences = computeDifferences(results);
+ console.log();
+ let { fixed, unfixed } = automaticResultTable(withDifferences);
+ // console.log(horizontalTermResultTable(fixed));
+ console.log(key);
+ console.log(verticalTermResultTable(unfixed));
+}
+
+/**
+ * @param {string} version
+ * @param {string[]} logPaths
+ * @param {(logs: TraceEvent[], logFilePath: string) => number} [getThreadId]
+ * @param {(log: TraceEvent) => boolean} [trackEventsIn]
+ * @returns {Promise<Map<string, ResultStats>>}
+ */
+async function getStatsFromLogs(version, logPaths, getThreadId, trackEventsIn) {
+ /** @type {Map<string, number[]>} Sums for each function for each file */
+ const data = new Map();
+ for (let logPath of logPaths) {
+ /** @type {TraceEvent[]} */
+ const logs = JSON.parse(await readFile(logPath, 'utf8'));
+
+ let tid = getThreadId ? getThreadId(logs, logPath) : null;
+
+ /** @type {Array<{ id: string; start: number; end: number; }>} Determine what durations to track events under */
+ const parentLogs = [];
+ for (let log of logs) {
+ if (trackEventsIn && trackEventsIn(log)) {
+ if (log.ph == 'X') {
+ parentLogs.push({
+ id: log.name,
+ start: log.ts,
+ end: log.ts + log.dur
+ });
+ } else if (log.ph == 'b') {
+ parentLogs.push({
+ id: log.name,
+ start: log.ts,
+ end: log.ts
+ });
+ } else if (log.ph == 'e') {
+ parentLogs.find(l => l.id == log.name).end = log.ts;
+ } else {
+ throw new Error(`Unsupported parent log type: ${log.ph}`);
+ }
+ }
+ }
+
+ /** @type {Map<string, import('./tracing').AsyncEvent>} */
+ const durationBeginEvents = new Map();
+
+ /** @type {Map<string, number[]>} Sum of time spent in each function for this log file */
+ const sumsForFile = new Map();
+ for (let log of logs) {
+ if (tid != null && log.tid !== tid) {
+ // if (toTrack.has(log.name)) {
+ // console.log(
+ // `Skipping ${log.name} on tid ${log.tid} (expected ${tid}) in ${logPath}`
+ // );
+ // }
+
+ continue;
+ }
+
+ if (log.ph == 'X') {
+ // Track duration event
+ if (toTrack.has(log.name)) {
+ let key = `Sum of ${log.name} time`;
+ let sum = sumsForFile.get(key)?.[0] ?? 0;
+ // sumsForFile.set(log.name, sum + log.dur / 1000);
+ setInMapArray(sumsForFile, key, 0, sum + log.dur / 1000);
+
+ key = `Count of ${log.name}`;
+ sum = sumsForFile.get(key)?.[0] ?? 0;
+ // sumsForFile.set(key, sum + 1);
+ setInMapArray(sumsForFile, key, 0, sum + 1);
+
+ key = `Sum of V8 runtime`;
+ sum = sumsForFile.get(key)?.[0] ?? 0;
+ // sumsForFile.set(key, sum + log.dur / 1000);
+ setInMapArray(sumsForFile, key, 0, sum + log.dur / 1000);
+
+ for (let parentLog of parentLogs) {
+ if (
+ parentLog.start <= log.ts &&
+ log.ts + log.dur <= parentLog.end
+ ) {
+ key = `In ${parentLog.id}, Sum of V8 runtime`;
+ sum = sumsForFile.get(key)?.[0] ?? 0;
+ setInMapArray(sumsForFile, key, 0, sum + log.dur / 1000);
+ }
+ }
+ }
+
+ if (log.name == 'MinorGC' || log.name == 'MajorGC') {
+ let key = `${log.name} usedHeapSizeBefore`;
+ addToMapArray(sumsForFile, key, log.args.usedHeapSizeBefore / 1e6);
+
+ key = `${log.name} usedHeapSizeAfter`;
+ addToMapArray(sumsForFile, key, log.args.usedHeapSizeAfter / 1e6);
+ }
+ } else if (
+ (log.ph == 'b' || log.ph == 'e') &&
+ log.cat == 'blink.user_timing' &&
+ log.scope == 'blink.user_timing'
+ ) {
+ // TODO: Doesn't handle nested events of same name. Oh well.
+ if (log.ph == 'b') {
+ durationBeginEvents.set(log.name, log);
+ } else {
+ const beginEvent = durationBeginEvents.get(log.name);
+ const endEvent = log;
+ durationBeginEvents.delete(log.name);
+
+ let key = beginEvent.name;
+ let duration = (endEvent.ts - beginEvent.ts) / 1000;
+ addToMapArray(sumsForFile, key, duration);
+
+ if (key.startsWith('run-') && key !== 'run-warmup-0') {
+ // Skip run-warmup-0 since it doesn't do unmounting
+ addToMapArray(sumsForFile, 'average run duration', duration);
+ }
+ }
+ }
+ }
+
+ addToGrouping(data, sumsForFile);
+ }
+
+ const stats = new Map();
+ for (let [key, sums] of data) {
+ stats.set(key, {
+ result: {
+ name: '02_replace1k',
+ version: version,
+ measurement: {
+ name: key,
+ mode: 'expression',
+ expression: key,
+ unit: key.startsWith('Count')
+ ? ''
+ : key.includes('usedHeapSize')
+ ? 'MB'
+ : null
+ },
+ browser: {
+ name: 'chrome'
+ },
+ millis: sums
+ },
+ stats: summaryStats(sums)
+ });
+ }
+
+ return stats;
+}
+
+/**
+ * @param {import('./tracing').TraceEvent[]} logs
+ * @param {string} logFilePath
+ * @returns {number}
+ */
+function getDurationThread(logs, logFilePath) {
+ let log = logs.find(isDurationLog);
+
+ if (log == null) {
+ throw new Error(
+ `Could not find blink.user_timing log for "run-final" or "duration" in ${logFilePath}.`
+ );
+ } else {
+ return log.tid;
+ }
+}
+
+/**
+ * @param {TraceEvent} log
+ */
+function isDurationLog(log) {
+ return (
+ (log.ph == 'b' || log.ph == 'e') &&
+ log.cat == 'blink.user_timing' &&
+ log.scope == 'blink.user_timing' &&
+ // Tachometer may kill the tab after seeing the duration measure before
+ // the tab can log it to the trace file
+ (log.name == 'run-final' || log.name == 'duration')
+ );
+}
+
+export async function analyze() {
+ // const frameworkNames = await readdir(p('logs'));
+ const frameworkNames = frameworks.map(f => f.label);
+ const listAtEnd = [
+ 'average run duration',
+ 'Sum of V8 runtime',
+ 'In run-final, Sum of V8 runtime',
+ 'In duration, Sum of V8 runtime',
+ 'duration'
+ ];
+
+ if (!existsSync(baseTraceLogDir())) {
+ console.log(
+ `Could not find log directory: "${baseTraceLogDir()}". Did you run the benchmarks?`
+ );
+ return;
+ }
+
+ const benchmarkNames = await readdir(baseTraceLogDir());
+ let selectedBench;
+ if (benchmarkNames.length == 0) {
+ console.log(`No benchmarks or results found in "${baseTraceLogDir()}".`);
+ return;
+ } else if (benchmarkNames.length == 1) {
+ selectedBench = benchmarkNames[0];
+ } else {
+ selectedBench = (
+ await prompts({
+ type: 'select',
+ name: 'value',
+ message: "Which benchmark's results would you like to analyze?",
+ choices: benchmarkNames.map(name => ({
+ title: name,
+ value: name
+ }))
+ })
+ ).value;
+ }
+
+ /** @type {Map<string, ResultStats[]>} */
+ const resultStatsMap = new Map();
+ for (let framework of frameworkNames) {
+ const logDir = baseTraceLogDir(selectedBench, framework);
+
+ let logFilePaths;
+ try {
+ logFilePaths = (await readdir(logDir)).map(fn =>
+ baseTraceLogDir(selectedBench, framework, fn)
+ );
+ } catch (e) {
+ // If directory doesn't exist or we fail to read it, just skip
+ continue;
+ }
+
+ const resultStats = await getStatsFromLogs(
+ framework,
+ logFilePaths,
+ getDurationThread,
+ isDurationLog
+ );
+ addToGrouping(resultStatsMap, resultStats);
+
+ // console.log(`${framework}:`);
+ // console.log(resultStats);
+ }
+
+ // Compute differences and print table
+ for (let [key, results] of resultStatsMap.entries()) {
+ if (listAtEnd.includes(key)) {
+ continue;
+ }
+
+ logDifferences(key, results);
+ }
+
+ for (let key of listAtEnd) {
+ if (resultStatsMap.has(key)) {
+ logDifferences(key, resultStatsMap.get(key));
+ }
+ }
+}
diff --git a/preact/benches/scripts/bench.js b/preact/benches/scripts/bench.js
new file mode 100644
index 0000000..eb7d464
--- /dev/null
+++ b/preact/benches/scripts/bench.js
@@ -0,0 +1,70 @@
+import { spawnSync } from 'child_process';
+import { mkdir } from 'fs/promises';
+import {
+ globSrc,
+ benchesRoot,
+ allBenches,
+ resultsPath,
+ IS_CI
+} from './utils.js';
+import { generateConfig } from './config.js';
+
+export const defaultBenchOptions = {
+ browser: 'chrome-headless',
+ // Tachometer default is 50, but locally let's only do 10
+ 'sample-size': !IS_CI ? 10 : 50,
+ // Tachometer default is 10% but let's do 5% to save some GitHub action
+ // minutes by reducing the likelihood of needing auto-sampling. See
+ // https://github.com/Polymer/tachometer#auto-sampling
+ horizon: '5%',
+ // Tachometer default is 3 minutes, but let's shrink it to 1 here to save some
+ // GitHub Action minutes
+ timeout: 1,
+ 'window-size': '1024,768',
+ framework: IS_CI ? ['preact-master', 'preact-local'] : null,
+ trace: false
+};
+
+/**
+ * @param {string} bench1
+ * @param {{ _: string[]; } & TachometerOptions} opts
+ */
+export async function runBenches(bench1 = 'all', opts) {
+ const globs = bench1 === 'all' ? allBenches : [bench1].concat(opts._);
+ const benchesToRun = await globSrc(globs);
+
+ if (benchesToRun.length == 0) {
+ console.log('No benchmarks found matching patterns:', globs);
+ } else {
+ console.log('Running benchmarks:', benchesToRun.join(', '));
+ console.log();
+ }
+
+ const configFileTasks = benchesToRun.map(async (benchPath, i) => {
+ return generateConfig(benchesRoot('src', benchPath), {
+ ...opts,
+ prepare: i === 0 // Only run prepare script for first config
+ });
+ });
+
+ await mkdir(resultsPath(), { recursive: true });
+
+ const configFiles = await Promise.all(configFileTasks);
+ for (const { name, configPath } of configFiles) {
+ const args = [
+ benchesRoot('node_modules/tachometer/bin/tach.js'),
+ '--force-clean-npm-install',
+ '--config',
+ configPath,
+ '--json-file',
+ benchesRoot('results', name + '.json')
+ ];
+
+ console.log('\n$', process.execPath, ...args);
+
+ spawnSync(process.execPath, args, {
+ cwd: benchesRoot(),
+ stdio: 'inherit'
+ });
+ }
+}
diff --git a/preact/benches/scripts/config.js b/preact/benches/scripts/config.js
new file mode 100644
index 0000000..cb8f582
--- /dev/null
+++ b/preact/benches/scripts/config.js
@@ -0,0 +1,317 @@
+import * as path from 'path';
+import del from 'del';
+import { writeFile, stat, mkdir } from 'fs/promises';
+import { repoRoot, benchesRoot, toUrl } from './utils.js';
+import { defaultBenchOptions } from './bench.js';
+import { prepare } from './prepare.js';
+
+const measureName = 'duration'; // Must match measureName in '../src/util.js'
+const warnings = new Set([]);
+const TACH_SCHEMA =
+ 'https://raw.githubusercontent.com/Polymer/tachometer/master/config.schema.json';
+
+export const baseTraceLogDir = (...args) =>
+ path.join(benchesRoot('logs'), ...args);
+
+/**
+ * @param {ConfigFileBenchmark["packageVersions"]["dependencies"]["framework"]} framework
+ * @returns {Promise<boolean>}
+ */
+async function validateFileDep(framework) {
+ try {
+ if (typeof framework === 'string') {
+ await stat(framework.replace(/^file:/, ''));
+ return true;
+ } else {
+ return false;
+ }
+ } catch (e) {
+ console.log('Stat error:', e);
+ return false;
+ }
+}
+
+/**
+ * @typedef {ConfigFileBenchmark["packageVersions"]} ConfigFilePackageVersion
+ * @typedef {ConfigFilePackageVersion & { isValid(): Promise<boolean>; }} BenchConfig
+ * @type {BenchConfig[]}
+ */
+export const frameworks = [
+ {
+ label: 'preact-v8',
+ dependencies: {
+ framework: 'file:' + repoRoot('benches/proxy-packages/preact-v8-proxy')
+ },
+ isValid() {
+ return validateFileDep(this.dependencies.framework);
+ }
+ },
+ {
+ label: 'preact-master',
+ dependencies: {
+ framework:
+ 'file:' + repoRoot('benches/proxy-packages/preact-master-proxy')
+ },
+ async isValid() {
+ try {
+ await stat(repoRoot('preact.tgz'));
+ return validateFileDep(this.dependencies.framework);
+ } catch (e) {
+ return false;
+ }
+ }
+ },
+ {
+ label: 'preact-local',
+ dependencies: {
+ framework: 'file:' + repoRoot('benches/proxy-packages/preact-local-proxy')
+ },
+ isValid() {
+ return validateFileDep(this.dependencies.framework);
+ }
+ }
+];
+
+/**
+ * @param {string} benchPath
+ * @returns {Pick<ConfigFileBenchmark, "name" | "url" | "measurement">}
+ */
+function getBaseBenchmarkConfig(benchPath) {
+ let name = path.basename(benchPath).replace('.html', '');
+ let url = path.posix.relative(toUrl(benchesRoot()), toUrl(benchPath));
+
+ /** @type {ConfigFileBenchmark["measurement"]} */
+ let measurement;
+ if (name == '02_replace1k') {
+ // MUST BE KEPT IN SYNC WITH WARMUP COUNT IN 02_replace1k.html
+ const WARMUP_COUNT = 5;
+
+ // For 02_replace1k, collect additional measurements focusing on the JS
+ // clock time for each warmup and the final duration.
+ measurement = [
+ {
+ name: 'duration',
+ mode: 'performance',
+ entryName: measureName
+ },
+ {
+ name: 'usedJSHeapSize',
+ mode: 'expression',
+ expression: 'window.usedJSHeapSize'
+ }
+ ];
+
+ for (let i = 0; i < WARMUP_COUNT; i++) {
+ const entryName = `run-warmup-${i}`;
+ measurement.push({
+ name: entryName,
+ mode: 'performance',
+ entryName
+ });
+ }
+
+ measurement.push({
+ name: 'run-final',
+ mode: 'performance',
+ entryName: 'run-final'
+ });
+ } else {
+ // Default measurements
+ measurement = [
+ {
+ name: 'duration',
+ mode: 'performance',
+ entryName: measureName
+ },
+ {
+ name: 'usedJSHeapSize',
+ mode: 'expression',
+ expression: 'window.usedJSHeapSize'
+ }
+ ];
+ }
+
+ return { name, url, measurement };
+}
+
+export async function generateSingleConfig(benchFile, opts) {
+ const benchPath = await benchesRoot('src', benchFile);
+ const results = await stat(benchPath);
+ if (!results.isFile) {
+ throw new Error(`Given path is not a file: ${benchPath}`);
+ }
+
+ await generateConfig(benchPath, { ...defaultBenchOptions, ...opts });
+}
+
+/**
+ * @typedef {import('tachometer/lib/configfile').ConfigFile} ConfigFile Expected
+ * format of a top-level tachometer JSON config file.
+ * @typedef {ConfigFile["benchmarks"][0]} ConfigFileBenchmark
+ * @typedef {{ name: string; configPath: string; config: ConfigFile; }} ConfigData
+ * @param {string} benchPath
+ * @param {TachometerOptions & { prepare?: boolean }} options
+ * @returns {Promise<ConfigData>}
+ */
+export async function generateConfig(benchPath, options) {
+ /** @type {ConfigFileBenchmark["expand"]} */
+ let expand;
+ /** @type {BrowserConfigs} */
+ let browser;
+
+ const baseBenchConfig = getBaseBenchmarkConfig(benchPath);
+
+ // See https://www.npmjs.com/package/tachometer#browsers
+ // and https://www.npmjs.com/package/tachometer#config-file
+ if (Array.isArray(options.browser)) {
+ expand = options.browser.map(browserOpt => ({
+ browser: parseBrowserOption(browserOpt)
+ }));
+ } else {
+ browser = parseBrowserOption(options.browser);
+ }
+
+ if (browser.name == 'chrome' && options.trace) {
+ const traceLogDir = baseTraceLogDir(baseBenchConfig.name);
+ await del('**/*', { cwd: traceLogDir });
+ await mkdir(traceLogDir, { recursive: true });
+
+ browser.trace = {
+ logDir: traceLogDir
+ };
+ }
+
+ /** @type {BenchConfig[]} */
+ let frameworksToRun;
+ if (!options.framework) {
+ frameworksToRun = frameworks;
+ } else if (typeof options.framework === 'string') {
+ const match = frameworks.find(f => f.label == options.framework);
+ frameworksToRun = match ? [match] : [];
+ } else if (Array.isArray(options.framework)) {
+ frameworksToRun = frameworks.filter(f =>
+ options.framework.includes(f.label)
+ );
+ } else {
+ throw new Error(`Unrecognized framework option: ${options.framework}`);
+ }
+
+ if (frameworksToRun.length == 0) {
+ console.error(
+ `Framework options did not match any configured frameworks:\n` +
+ `\tProvided option: ${options.framework}\n` +
+ `\tAvailable frameworks: [${frameworks
+ .map(f => JSON.stringify(f.label))
+ .join(', ')}]\n`
+ );
+
+ throw new Error(
+ `Framework option did not match any configured frameworks: ${options.framework}`
+ );
+ }
+
+ /** @type {ConfigFile["benchmarks"]} */
+ const benchmarks = [];
+ for (let framework of frameworksToRun) {
+ let frameworkPath = framework.dependencies.framework;
+ if (typeof frameworkPath !== 'string') {
+ throw new Error(
+ 'Only string/npm dependencies are supported at this time'
+ );
+ }
+
+ if (!(await framework.isValid())) {
+ const warnMsg = `Could not locate path for ${framework.label}: ${framework.dependencies.framework}. \nSkipping...`;
+ if (!warnings.has(warnMsg)) {
+ console.warn(warnMsg);
+ warnings.add(warnMsg);
+ }
+
+ continue;
+ }
+
+ benchmarks.push({
+ ...baseBenchConfig,
+ packageVersions: framework,
+ browser,
+ expand
+ });
+ }
+
+ if (options.prepare !== false) {
+ await prepare(benchmarks.map(b => b.packageVersions.label));
+ }
+
+ /** @type {ConfigFile} */
+ const config = {
+ $schema: TACH_SCHEMA,
+ sampleSize: options['sample-size'],
+ timeout: options.timeout,
+ horizons: options.horizon.split(','),
+ benchmarks
+ };
+
+ if (config.benchmarks.length == 0) {
+ if (options.framework) {
+ const configuredFrameworks = frameworks.map(f => f.label).join(', ');
+ throw new Error(
+ `No benchmarks created. Does the specified framework match one of the configured frameworks? ${configuredFrameworks}`
+ );
+ } else {
+ throw new Error(
+ `Unknown failure: no benchmarks created. frameworksToRun: ${frameworksToRun}`
+ );
+ }
+ }
+
+ const configPath = await writeConfig(baseBenchConfig.name, config);
+
+ return { name: baseBenchConfig.name, configPath, config };
+}
+
+async function writeConfig(name, config) {
+ const configPath = benchesRoot('dist', name + '.config.json');
+ await mkdir(path.dirname(configPath), { recursive: true });
+ await writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
+
+ return configPath;
+}
+
+/**
+ * @typedef {Exclude<ConfigFileBenchmark["browser"], string>} BrowserConfigs
+ * @param {string} str
+ * @returns {BrowserConfigs}
+ */
+function parseBrowserOption(str) {
+ // Source: https://github.com/Polymer/tachometer/blob/d4d5116acb2d7df18035ddc36f0a3a1730841a23/src/browser.ts#L100
+ let remoteUrl;
+ const at = str.indexOf('@');
+ if (at !== -1) {
+ remoteUrl = str.substring(at + 1);
+ str = str.substring(0, at);
+ }
+ const headless = str.endsWith('-headless');
+ if (headless === true) {
+ str = str.replace(/-headless$/, '');
+ }
+
+ /** @type {import('tachometer/lib/browser').BrowserName} */
+ // @ts-ignore
+ const name = str;
+
+ /** @type {BrowserConfigs} */
+ const config = { name, headless };
+ if (remoteUrl !== undefined) {
+ config.remoteUrl = remoteUrl;
+ }
+
+ // Custom browser options
+ if (config.name == 'chrome') {
+ config.addArguments = [
+ '--js-flags=--expose-gc',
+ '--enable-precise-memory-info'
+ ];
+ }
+
+ return config;
+}
diff --git a/preact/benches/scripts/deopts.js b/preact/benches/scripts/deopts.js
new file mode 100644
index 0000000..990a6cc
--- /dev/null
+++ b/preact/benches/scripts/deopts.js
@@ -0,0 +1,253 @@
+import * as path from 'path';
+import { mkdir } from 'fs/promises';
+import { spawn } from 'child_process';
+import { Transform } from 'stream';
+import escapeRe from 'escape-string-regexp';
+import stripAnsi from 'strip-ansi';
+import { pool } from '@kristoferbaxter/async';
+import {
+ globSrc,
+ benchesRoot,
+ getPkgBinPath,
+ resultsPath,
+ IS_CI
+} from './utils.js';
+import { generateConfig } from './config.js';
+import { defaultBenchOptions } from './bench.js';
+
+export const defaultDeoptsOptions = {
+ framework: 'preact-local',
+ timeout: 5,
+ open: IS_CI ? false : true
+};
+
+const getResultDir = (benchmark, framework) =>
+ resultsPath('v8-deopt-viewer', benchmark, framework);
+
+/**
+ * @param {string} pkgName
+ * @param {string[]} args
+ * @param {"pipe" | "inherit"} [stdio]
+ * @returns {Promise<import('child_process').ChildProcess>}
+ */
+async function runPackage(pkgName, args, stdio) {
+ const binPath = await getPkgBinPath(pkgName);
+ args.unshift(binPath);
+
+ return spawn(process.execPath, args, { stdio });
+}
+
+/**
+ * @param {import('child_process').ChildProcess} childProcess
+ */
+async function onExit(childProcess) {
+ return new Promise((resolve, reject) => {
+ childProcess.once('exit', (code, signal) => {
+ if (code === 0 || signal == 'SIGINT') {
+ resolve();
+ } else {
+ reject(new Error('Exit with error code: ' + code));
+ }
+ });
+
+ childProcess.once('error', err => {
+ reject(err);
+ });
+ });
+}
+
+/**
+ * @typedef {{ benchName: string; framework: string; url: string; }} TachURL
+ * @param {import('child_process').ChildProcess} tachProcess
+ * @param {import('./config').ConfigData} tachConfig
+ * @param {number} timeoutMs
+ * @returns {Promise<TachURL[]>}
+ */
+async function getTachometerURLs(tachProcess, tachConfig, timeoutMs = 60e3) {
+ return new Promise(async (resolve, reject) => {
+ let timeout;
+ if (timeoutMs > 0) {
+ timeout = setTimeout(() => {
+ reject(
+ new Error(
+ 'Timed out waiting for Tachometer to get set up. Did it output a URL?'
+ )
+ );
+ }, timeoutMs);
+ }
+
+ // Look for lines like:
+ // many_updates [@preact]
+ // http://127.0.0.1:56536/src/many_updates.html
+ const benchesToSearch = tachConfig.config.benchmarks.map(bench => ({
+ benchName: bench.name,
+ framework: bench.packageVersions.label,
+ regex: new RegExp(
+ escapeRe(`${bench.name} [@${bench.packageVersions.label}]`) +
+ `\\s+(http:\\/\\/.*)`,
+ 'im'
+ ),
+ url: null
+ }));
+
+ /** @type {TachURL[]} */
+ const results = [];
+ let output = '';
+ tachProcess.stdout.on('data', function onStdOutChunk(chunk) {
+ output += stripAnsi(chunk.toString('utf8'));
+
+ for (let bench of benchesToSearch) {
+ if (bench.url) {
+ continue;
+ }
+
+ let match = output.match(bench.regex);
+ if (match) {
+ bench.url = match[1];
+ results.push(bench);
+ }
+ }
+
+ if (results.length == benchesToSearch.length) {
+ // All URLs found, removeEventListener
+ tachProcess.off('data', onStdOutChunk);
+
+ clearTimeout(timeout);
+ resolve(results);
+ }
+ });
+ });
+}
+
+function createPrefixTransform(prefix) {
+ return new Transform({
+ transform(chunk, encoding, callback) {
+ try {
+ // @ts-ignore
+ chunk = encoding == 'buffer' ? chunk.toString() : chunk;
+ const lines = chunk.split('\n');
+
+ for (let line of lines) {
+ if (line) {
+ line = `[${prefix}] ${line}`;
+ this.push(line + '\n');
+ }
+ }
+
+ callback();
+ } catch (error) {
+ return callback(error);
+ }
+ }
+ });
+}
+
+/**
+ * @param {TachURL} tachURL
+ * @param {DeoptOptions} options
+ */
+async function runV8DeoptViewer(tachURL, options) {
+ const deoptOutputDir = getResultDir(tachURL.benchName, tachURL.framework);
+ await mkdir(deoptOutputDir, { recursive: true });
+
+ const deoptArgs = [
+ tachURL.url,
+ '-o',
+ deoptOutputDir,
+ '-t',
+ (options.timeout * 1000).toString()
+ ];
+
+ if (options.open) {
+ deoptArgs.push('--open');
+ }
+
+ const deoptProcess = await runPackage('v8-deopt-viewer', deoptArgs);
+ deoptProcess.stdout
+ .pipe(createPrefixTransform(tachURL.framework))
+ .pipe(process.stdout);
+ deoptProcess.stderr
+ .pipe(createPrefixTransform(tachURL.framework))
+ .pipe(process.stderr);
+
+ await onExit(deoptProcess);
+}
+
+/**
+ * @param {string} benchGlob
+ * @param {DeoptOptions} options
+ */
+export async function runDeopts(benchGlob, options) {
+ // TODO:
+ // * Handle multiple benchmarks
+
+ const frameworks = options.framework;
+ if (!benchGlob) {
+ benchGlob = 'many_updates.html';
+ }
+
+ const benchesToRun = await globSrc(benchGlob);
+ if (benchesToRun.length > 1) {
+ console.error('Matched multiple benchmarks. Only running the first one.');
+ }
+
+ const benchPath = benchesRoot('src', benchesToRun[0]);
+ const tachConfig = await generateConfig(benchPath, {
+ ...defaultBenchOptions,
+ ...defaultDeoptsOptions,
+ framework: frameworks
+ });
+
+ console.log('Benchmarks running:', benchPath);
+ console.log('Frameworks running:', frameworks);
+
+ /** @type {Promise<void>} */
+ let onTachExit;
+ /** @type {import('child_process').ChildProcess} */
+ let tachProcess;
+ try {
+ // Run tachometer in manual mode with generated config
+ const tachArgs = ['--config', tachConfig.configPath, '--manual'];
+ tachProcess = await runPackage('tachometer', tachArgs);
+ tachProcess.stdout.pipe(process.stdout);
+ tachProcess.stderr.pipe(process.stderr);
+ onTachExit = onExit(tachProcess);
+
+ // Parse URL from tachometer stdout
+ const tachURLs = await getTachometerURLs(tachProcess, tachConfig);
+
+ // Run v8-deopt-viewer against tachometer URL
+ console.log();
+ await pool(tachURLs, tachURL =>
+ runV8DeoptViewer(tachURL, {
+ ...options,
+ open: options.open && tachURLs.length == 1
+ })
+ );
+
+ if (tachURLs.length > 1) {
+ const rootResultDir = getResultDir('', '');
+ console.log(`\nOpen your browser to ${rootResultDir} to view results.`);
+
+ if (options.open) {
+ // TODO: Figure out how to open a directory in the user's default browser
+ }
+ }
+ } finally {
+ if (tachProcess) {
+ tachProcess.kill('SIGINT');
+
+ // Log a message is Tachometer takes a while to close
+ let logMsg = () => console.log('Waiting for Tachometer to exit...');
+ let t = setTimeout(logMsg, 2e3);
+
+ try {
+ await onTachExit;
+ } catch (error) {
+ console.error('Error waiting for Tachometer to exit:', error);
+ } finally {
+ clearTimeout(t);
+ }
+ }
+ }
+}
diff --git a/preact/benches/scripts/global.d.ts b/preact/benches/scripts/global.d.ts
new file mode 100644
index 0000000..0fb67a3
--- /dev/null
+++ b/preact/benches/scripts/global.d.ts
@@ -0,0 +1,15 @@
+interface TachometerOptions {
+ browser: string | string[];
+ framework: string | string[];
+ 'window-size': string;
+ 'sample-size': number;
+ horizon: string;
+ timeout: number;
+ trace: boolean;
+}
+
+interface DeoptOptions {
+ framework: string;
+ timeout: number;
+ open: boolean;
+}
diff --git a/preact/benches/scripts/index.js b/preact/benches/scripts/index.js
new file mode 100644
index 0000000..4eeb21a
--- /dev/null
+++ b/preact/benches/scripts/index.js
@@ -0,0 +1,110 @@
+import sade from 'sade';
+import { generateSingleConfig } from './config.js';
+import { defaultDeoptsOptions, runDeopts } from './deopts.js';
+import { defaultBenchOptions, runBenches } from './bench.js';
+import { analyze } from './analyze.js';
+
+const prog = sade('./scripts');
+
+// Tests:
+// - npm start
+prog
+ .command('config [bench]')
+ .describe('Generate the config for the given benchmark HTML file.')
+ .option(
+ '--trace',
+ 'Enable perf tracing for browsers that support it',
+ defaultBenchOptions.trace
+ )
+ .action(generateSingleConfig);
+
+// Tests:
+// - many* -n 2 -t 0
+// - many* -n 2 -t 0 -f preact-local -f preact-v8
+// - many* -n 2 -t 0 -f preact-local -f preact-v8 -b chrome
+prog
+ .command('bench [globs]')
+ .describe(
+ 'Run the benchmarks matching the given globs. The root for the globs is the "src" directory. Specify "all" to run all benchmarks (default). To get more help on options, see polymer/tachometer help. Result table is printed to stdout and written to a csv and json file in the results directory.'
+ )
+ .example('bench text*')
+ .example('bench *.html')
+ .example('bench all')
+ .example('bench many* -f preact-local -f preact-master')
+ .option(
+ '--browser, -b',
+ 'Which browsers to launch in automatic mode, comma-delimited (chrome, chrome-headless, firefox, firefox-headless, safari, edge, ie)',
+ defaultBenchOptions.browser
+ )
+ // TODO: Consider parsing and adding to configs
+ // .option(
+ // '--window-size',
+ // '"width,height" in pixels of the browser windows that will be created',
+ // defaultOptions['window-size']
+ // )
+ .option(
+ '--sample-size, -n',
+ 'Minimum number of times to run each benchmark',
+ defaultBenchOptions['sample-size']
+ )
+ .option(
+ '--horizon, -h',
+ 'The degrees of difference to try and resolve when auto-sampling ("N%" or "Nms", comma-delimited)',
+ defaultBenchOptions.horizon
+ )
+ .option(
+ '--timeout, -t',
+ 'The maximum number of minutes to spend auto-sampling',
+ defaultBenchOptions.timeout
+ )
+ .option(
+ '--framework, -f',
+ 'Which framework(s) to bench. Specify the flag multiple times to compare specific frameworks. Default is all frameworks',
+ defaultBenchOptions.framework
+ )
+ .option(
+ '--trace',
+ 'Enable perf tracing for browsers that support it',
+ defaultBenchOptions.trace
+ )
+ .action(runBenches);
+
+// Tests:
+// - (no args)
+// - many*
+// - many* -f preact-local -f preact-master
+prog
+ .command('deopts [benchmark]')
+ .describe(
+ 'Run v8-deopt-viewer against the specified benchmark file (defaults to many_updates.html). If a glob is given, only the first matching file will be run'
+ )
+ .example('deopts many_updates.html')
+ .example('deopts many*')
+ .example('deopts many* -f preact-local')
+ .example('deopts many* -f preact-local -f preact-master')
+ .option(
+ '--framework, -f',
+ 'The framework to run the benchmark with.',
+ defaultDeoptsOptions.framework
+ )
+ .option(
+ '--timeout, -t',
+ 'How long in seconds to keep the browser open while the benchmark runs. Passed to v8-deopt-viewer.',
+ defaultDeoptsOptions.timeout
+ )
+ .option(
+ '--open',
+ 'Open the resulting v8-deopt-viewer result in the browser upon completion',
+ defaultDeoptsOptions.open
+ )
+ .action(runDeopts);
+
+prog
+ .command('analyze')
+ .describe(
+ 'Analyze the trace logs created by running benchmarks with the --trace flag'
+ )
+ .example('analyze')
+ .action(analyze);
+
+prog.parse(process.argv);
diff --git a/preact/benches/scripts/prepare.js b/preact/benches/scripts/prepare.js
new file mode 100644
index 0000000..da1b7f3
--- /dev/null
+++ b/preact/benches/scripts/prepare.js
@@ -0,0 +1,44 @@
+import { readdir } from 'fs/promises';
+import path from 'path';
+import { execFileSync } from 'child_process';
+import del from 'del';
+import { repoRoot } from './utils.js';
+
+const npmCmd = process.platform == 'win32' ? 'npm.cmd' : 'npm';
+
+/**
+ * @param {string[]} frameworks
+ */
+export async function prepare(frameworks) {
+ const proxyRoot = repoRoot('benches/proxy-packages');
+ const proxyDirs = (await readdir(proxyRoot)).map(dirname =>
+ dirname.replace(/-proxy$/, '')
+ );
+
+ for (let framework of frameworks) {
+ const dirname = proxyDirs.find(dir => dir == framework);
+ if (dirname == null) {
+ continue;
+ }
+
+ const proxyDir = (...args) =>
+ path.join(proxyRoot, dirname + '-proxy', ...args);
+
+ // It appears from ad-hoc testing (npm v6.14.9 on Windows), npm will cache
+ // any locally referenced tarball files (e.g. "file:../../../preact.tgz") in
+ // its global cache.
+ //
+ // If a package-lock is present and the `npm ci` or `npm i` command is used,
+ // then npm will pull the tarball from the cache and not use the local
+ // tarball file even if the local reference has changed or is deleted.
+ //
+ // Because of the above behavior, we'll always delete the package-lock file
+ // and node_modules folder and use `npm i` to ensure we always get the
+ // latest packages
+ console.log(`Preparing ${dirname}: Cleaning ${proxyDir()}...`);
+ await del(['package-lock.json', 'node_modules'], { cwd: proxyDir() });
+
+ console.log(`Preparing ${dirname}: Running "npm i" in ${proxyDir()}...`);
+ execFileSync(npmCmd, ['i'], { cwd: proxyDir(), stdio: 'inherit' });
+ }
+}
diff --git a/preact/benches/scripts/tracing.d.ts b/preact/benches/scripts/tracing.d.ts
new file mode 100644
index 0000000..cc3f271
--- /dev/null
+++ b/preact/benches/scripts/tracing.d.ts
@@ -0,0 +1,224 @@
+// From: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+
+export type TraceEvent =
+ | DurationEvent
+ | CompleteEvent
+ | InstantEvent
+ | AsyncEvent
+ | FlowEvent
+ | SampleEvent
+ | ProcessNameEvent
+ | ProcessLabelsEvent
+ | ProcessSortIndexEvent
+ | ThreadNameEvent
+ | ThreadSortIndexEvent
+ | MarkEvent
+ | ContextEvent
+ | ObjectCreatedEvent
+ | ObjectSnapshotEvent
+ | ObjectDestroyedEvent;
+
+interface BaseEvent {
+ /** The name of the event */
+ name: string;
+ /**
+ * The event categories. This is a comma separated list of categories for the
+ * event.
+ */
+ cat: string;
+ /** The event type (phase?) */
+ ph: string;
+ /** The tracing clock timestamp (microseconds) */
+ ts: number;
+ /** The thread clock timestamp of the event (microseconds) */
+ tts?: number;
+ /** Process ID */
+ pid: number;
+ /** Thread ID */
+ tid: number;
+ /** Any args provided for the event */
+ args: Record<string, any>;
+}
+
+interface StackData {
+ /**
+ * Stack frame at the start of the event. ID pointing the corresponding stack
+ * in the stackFrames map
+ */
+ sf?: number;
+ /**
+ * Stack at the start of the event. Usually contains program counter addresses
+ * as hex strings
+ */
+ stack?: string[];
+}
+
+/** Mark the beginning or end of a duration of work on a given thread */
+interface DurationEvent extends BaseEvent, StackData {
+ ph: 'B' | 'E';
+}
+
+/** Represents a duration of work on a given thread */
+interface CompleteEvent extends BaseEvent, StackData {
+ ph: 'X';
+ /** Tracing clock duration (microseconds) */
+ dur: number;
+ /** Thread clock duration? (microseconds) */
+ tdur?: number;
+ /** Stack frame at the end of this event */
+ esf?: number;
+ /** Stack at the end of this event */
+ estack?: string[];
+}
+
+/**
+ * Mark something happened but has no duration associated with it. Only threaded
+ * scoped events can have stack data associated with them.
+ */
+interface InstantEvent extends BaseEvent, StackData {
+ ph: 'i' | 'I';
+ /** Scope of the event. g = global, p = process, t = thread (default) */
+ s?: 'g' | 'p' | 't';
+}
+
+/**
+ * Async operations (e.g. frames in a game, network I/O). b = start, n =
+ * instant, e = end. Events with the same category, id, and scope (if provided)
+ * are considered events from the same event tree. Nested async events should
+ * have the same category and id as its parent (but perhaps a different name).
+ */
+interface AsyncEvent extends BaseEvent {
+ ph: 'b' | 'n' | 'e';
+ id: string;
+ scope?: string;
+}
+
+/**
+ * Similar to Async events but allows a duration to be associated with each
+ * other across threads/processes. Visually, think of a flow event as an arrow
+ * between two duration events. With flow events, each event will be drawn in
+ * the thread it is emitted from. The events will be linked together visually
+ * using lines and arrows.
+ *
+ * TODO: Finish filling out
+ */
+interface FlowEvent extends BaseEvent {
+ ph: 's' | 't' | 'f';
+}
+
+interface SampleEvent extends BaseEvent, StackData {
+ ph: 'P';
+}
+
+interface ProcessNameEvent extends BaseEvent {
+ ph: 'M';
+ name: 'process_name';
+ args: {
+ name: string;
+ };
+}
+
+interface ProcessLabelsEvent extends BaseEvent {
+ ph: 'M';
+ name: 'process_labels';
+ args: {
+ labels: string;
+ };
+}
+
+interface ProcessSortIndexEvent extends BaseEvent {
+ ph: 'M';
+ name: 'process_sort_index';
+ args: {
+ sort_index: number;
+ };
+}
+
+interface ProcessUptimeEvent extends BaseEvent {
+ ph: 'M';
+ name: 'process_uptime_seconds';
+ args: {
+ uptime: number;
+ };
+}
+
+interface ThreadNameEvent extends BaseEvent {
+ ph: 'M';
+ name: 'thread_name';
+ args: {
+ name: string;
+ };
+}
+
+interface ThreadSortIndexEvent extends BaseEvent {
+ ph: 'M';
+ name: 'thread_sort_index';
+ args: {
+ sort_index: number;
+ };
+}
+
+interface NumCPUsEvent extends BaseEvent {
+ ph: 'M';
+ name: 'num_cpus';
+ args: {
+ number: number;
+ };
+}
+
+/**
+ * Mark events are created whenever a corresponding navigation timing API mark
+ * is created
+ */
+interface MarkEvent extends BaseEvent {
+ ph: 'R';
+}
+
+/**
+ * Context events are used to mark sequences of trace events as belonging to a
+ * particular context (or a tree of contexts). "(" = enter context, ")" = exit
+ * context. The enter event adds a context to all following trace events on the
+ * same thread until a corresponding leave event exits that context. Context ids
+ * refer to context object snapshots.
+ */
+interface ContextEvent extends BaseEvent {
+ ph: '(' | ')';
+ id?: string;
+}
+
+/** Object was created. Time is inclusive */
+interface ObjectCreatedEvent extends BaseEvent {
+ ph: 'N';
+ id: string;
+ scope?: string;
+ args: undefined;
+}
+
+interface ObjectSnapshotEvent extends BaseEvent {
+ ph: 'O';
+ id: string;
+ scope?: string;
+ args: {
+ /**
+ * By default, an object snapshot inherits the category of its containing
+ * trace event. However, sometimes the object being snapshotted needs its
+ * own category. This happens because the place that creates an object
+ * snapshot's values is often separate form where the objects' constructor
+ * and destructor is called. Categories for the object creation and deletion
+ * commands must match the snapshot commands. Thus, the category of any
+ * object snapshot may be provided with the snapshot itself
+ */
+ cat?: string;
+ /** Name of base type object */
+ base_type?: string;
+ snapshot: any;
+ };
+}
+
+/** Object was destroyed. Time is exclusive */
+interface ObjectDestroyedEvent extends BaseEvent {
+ ph: 'D';
+ id: string;
+ scope?: string;
+ args: undefined;
+}
diff --git a/preact/benches/scripts/utils.js b/preact/benches/scripts/utils.js
new file mode 100644
index 0000000..f8404c0
--- /dev/null
+++ b/preact/benches/scripts/utils.js
@@ -0,0 +1,65 @@
+import { fileURLToPath } from 'url';
+import { stat, readFile } from 'fs/promises';
+import * as path from 'path';
+import escalade from 'escalade';
+import globby from 'globby';
+
+// TODO: Replace with import.meta.resolve when stable
+import { createRequire } from 'module';
+// @ts-ignore
+const require = createRequire(import.meta.url);
+
+export const IS_CI = process.env.CI === 'true';
+
+// @ts-ignore
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+export const repoRoot = (...args) => path.join(__dirname, '..', '..', ...args);
+export const benchesRoot = (...args) => repoRoot('benches', ...args);
+export const resultsPath = (...args) => benchesRoot('results', ...args);
+
+export const toUrl = str => str.replace(/^[A-Za-z]+:/, '/').replace(/\\/g, '/');
+
+export const allBenches = '**/*.html';
+export function globSrc(patterns) {
+ return globby(patterns, { cwd: benchesRoot('src') });
+}
+
+export async function getPkgBinPath(pkgName) {
+ /** @type {string | void} */
+ let packageJsonPath;
+ try {
+ // TODO: Replace with import.meta.resolve when stable
+ const pkgMainPath = require.resolve(pkgName);
+ packageJsonPath = await escalade(pkgMainPath, (dir, names) => {
+ if (names.includes('package.json')) {
+ return 'package.json';
+ }
+ });
+ } catch (e) {
+ // Tachometer doesn't have a valid 'main' entry
+ packageJsonPath = benchesRoot('node_modules', pkgName, 'package.json');
+ }
+
+ if (!packageJsonPath || !(await stat(packageJsonPath)).isFile()) {
+ throw new Error(
+ `Could not locate "${pkgName}" package.json at "${packageJsonPath}".`
+ );
+ }
+
+ const pkg = JSON.parse(await readFile(packageJsonPath, 'utf8'));
+ if (!pkg.bin) {
+ throw new Error(`${pkgName} package.json does not contain a "bin" entry.`);
+ }
+
+ let binSubPath = pkg.bin;
+ if (typeof pkg.bin == 'object') {
+ binSubPath = pkg.bin[pkgName];
+ }
+
+ const binPath = path.join(path.dirname(packageJsonPath), binSubPath);
+ if (!(await stat(binPath)).isFile()) {
+ throw new Error(`Bin path for ${pkgName} is not a file: ${binPath}`);
+ }
+
+ return binPath;
+}
diff --git a/preact/benches/src/02_replace1k.html b/preact/benches/src/02_replace1k.html
new file mode 100644
index 0000000..e6b6270
--- /dev/null
+++ b/preact/benches/src/02_replace1k.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>replace all rows</title>
+ <meta name="description" content="updating all 1,000 rows" />
+ <style>
+ .preloadicon {
+ display: none;
+ }
+ .glyphicon-remove:before {
+ content: '⨯';
+ }
+ </style>
+ </head>
+ <body>
+ <div id="main"></div>
+ <script type="module">
+ import {
+ measureName,
+ measureMemory,
+ testElementText,
+ afterFrame,
+ afterFrameAsync,
+ markRunStart,
+ markRunEnd
+ } from './util.js';
+ import * as framework from 'framework';
+ import { render } from '../src/keyed-children/index.js';
+
+ const { run } = render(framework, document.getElementById('main'));
+
+ async function main() {
+ const elementSelector = 'tr:first-child > td:first-child';
+
+ // MUST BE KEPT IN SYNC WITH WARMUP COUNT IN benches/scripts/config.js
+ const WARMUP_COUNT = 5;
+ for (let i = 0; i < WARMUP_COUNT; i++) {
+ markRunStart(`warmup-${i}`);
+ run();
+ await markRunEnd(`warmup-${i}`);
+
+ await afterFrameAsync();
+ testElementText(elementSelector, (i * 1000 + 1).toFixed());
+ }
+
+ await afterFrameAsync();
+
+ afterFrame(function () {
+ testElementText(elementSelector, WARMUP_COUNT + '001');
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ });
+
+ markRunStart('final');
+ performance.mark('start');
+ run();
+ await markRunEnd('final');
+ }
+
+ afterFrame(main);
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/03_update10th1k_x16.html b/preact/benches/src/03_update10th1k_x16.html
new file mode 100644
index 0000000..9de8fdb
--- /dev/null
+++ b/preact/benches/src/03_update10th1k_x16.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>partial update</title>
+ <meta
+ name="description"
+ content="updating every 10th row for 1,000 rows (3 warmup runs). 16x CPU slowdown."
+ />
+ <style>
+ .preloadicon {
+ display: none;
+ }
+ .glyphicon-remove:before {
+ content: "⨯";
+ }
+ </style>
+ </head>
+ <body>
+ <div id="main"></div>
+ <script type="module">
+ import {
+ measureName,
+ measureMemory,
+ afterFrame,
+ afterFrameAsync,
+ getRowLinkSel,
+ testElement,
+ testElementTextContains
+ } from './util.js';
+ import * as framework from 'framework';
+ import { render } from '../src/keyed-children/index.js';
+
+ const { run: mount, update } = render(
+ framework,
+ document.getElementById('main')
+ );
+
+ function repeat(pattern, repeats) {
+ let result = '';
+ for (let i = 0; i < repeats; i++) {
+ result += pattern;
+ }
+
+ return result;
+ }
+
+ async function init() {
+ mount();
+
+ await afterFrameAsync();
+ testElement(getRowLinkSel(1000));
+
+ for (let i = 0; i < 3; i++) {
+ update();
+
+ await afterFrameAsync();
+ testElementTextContains(getRowLinkSel(991), repeat(' !!!', i + 1));
+ }
+ }
+
+ async function run() {
+ performance.mark('start');
+ update();
+
+ await afterFrameAsync();
+ testElementTextContains(getRowLinkSel(991), repeat(' !!!', 3 + 1));
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ }
+
+ init().then(run);
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/07_create10k.html b/preact/benches/src/07_create10k.html
new file mode 100644
index 0000000..728d472
--- /dev/null
+++ b/preact/benches/src/07_create10k.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>create many rows</title>
+ <meta name="description" content="creating 10,000 rows" />
+ <style>
+ .preloadicon {
+ display: none;
+ }
+ .glyphicon-remove:before {
+ content: '⨯';
+ }
+ </style>
+ </head>
+ <body>
+ <div id="main"></div>
+ <script type="module">
+ import {
+ measureName,
+ measureMemory,
+ testElementText,
+ afterFrame
+ } from './util.js';
+ import * as framework from 'framework';
+ import { render } from '../src/keyed-children/index.js';
+
+ const { runLots } = render(framework, document.getElementById('main'));
+
+ async function main() {
+ const elementSelector = 'tr:last-child > td:first-child';
+
+ performance.mark('start');
+ runLots();
+
+ afterFrame(() => {
+ testElementText(elementSelector, '10000');
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ });
+ }
+
+ main();
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/filter_list.html b/preact/benches/src/filter_list.html
new file mode 100644
index 0000000..d31e1af
--- /dev/null
+++ b/preact/benches/src/filter_list.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Patching HTML</title>
+ <style>
+ .items {
+ margin: 1em 0;
+ padding: 0;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 2px;
+ }
+
+ .items > * {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 3em;
+ height: 2em;
+ margin: 0;
+ padding: 0;
+ background: #eee;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="app"></div>
+ <script type="module">
+ import { measureName, measureMemory } from './util.js';
+ import { createRoot, createElement as h, Component } from 'framework';
+
+ function Row(props) {
+ return h('article', null, props.children);
+ }
+
+ function App(props) {
+ return h('div', {}, [
+ h(
+ 'div',
+ { class: 'items' },
+ props.items.map(id => h(Row, { key: id }, id))
+ )
+ ]);
+ }
+
+ const count = 1000;
+ const start = 20;
+ const end = 600;
+
+ const newItems = () =>
+ Array(count)
+ .fill(0)
+ .map((item, i) => i);
+ let items = newItems();
+ let currentItems = items;
+
+ const root = createRoot(document.getElementById('app'));
+ root.render(h(App, { items }));
+
+ function runPatch() {
+ items = newItems().filter(id => {
+ const isVisible = currentItems.includes(id);
+ return id >= start && id <= end ? !isVisible : isVisible;
+ });
+ currentItems = items;
+
+ root.render(h(App, { items }));
+ }
+
+ async function warmup() {
+ const count = 25;
+
+ for (let i = 0; i < count; i++) {
+ runPatch();
+ await new Promise(r => requestAnimationFrame(r));
+ }
+ }
+
+ warmup().then(async () => {
+ performance.mark('start');
+ runPatch();
+ await new Promise(r => requestAnimationFrame(r));
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ });
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/hydrate1k.html b/preact/benches/src/hydrate1k.html
new file mode 100644
index 0000000..bf43448
--- /dev/null
+++ b/preact/benches/src/hydrate1k.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>hydrate 1k table rows</title>
+ <meta name="description" content="hydrating 1,000 rows" />
+ <style>
+ .preloadicon {
+ display: none;
+ }
+ .glyphicon-remove:before {
+ content: '⨯';
+ }
+ </style>
+ </head>
+ <body>
+ <template id="template"></template>
+ <script type="module">
+ import {
+ measureName,
+ measureMemory,
+ testElementText,
+ afterFrame,
+ afterFrameAsync
+ } from './util.js';
+ import * as framework from 'framework';
+ import { getComponents } from '../src/keyed-children/components.js';
+ import { Store } from '../src/keyed-children/store.js';
+
+ /** @type {HTMLTemplateElement} */
+ const template = document.getElementById('template');
+ const { Main } = getComponents(framework);
+ const { createRoot, createElement } = framework;
+
+ const firstRowSel = 'tr:first-child > td:first-child';
+ const lastRowSel = 'tr:last-child > td:first-child';
+
+ const baseStore = new Store();
+ baseStore.run();
+
+ /**
+ * Delete the old hydrate root and create a new one with a clone of the
+ * template's content
+ */
+ function setupHydrateRoot() {
+ const hydrateRootId = 'hydrate-root';
+ let hydrateRoot = document.getElementById(hydrateRootId);
+ if (hydrateRoot) {
+ hydrateRoot.remove();
+ }
+
+ hydrateRoot = document.createElement('div');
+ hydrateRoot.id = hydrateRootId;
+ hydrateRoot.appendChild(template.content.cloneNode(true));
+ document.body.appendChild(hydrateRoot);
+ return hydrateRoot;
+ }
+
+ /** Render the app inside the template tag */
+ async function initializeTemplate() {
+ // Initialize template
+ createRoot(template.content).render(
+ createElement(Main, { store: baseStore })
+ );
+ await afterFrameAsync();
+ }
+
+ /**
+ * Click the second row's remove link and ensure the number of rows before
+ * and after the click are as expected
+ */
+ async function clickRemove(root, label, expectedBefore, expectedAfter) {
+ let rowCount = root.querySelectorAll('tr').length;
+ if (rowCount !== expectedBefore) {
+ throw new Error(
+ `${label}: Incorrect number of rows before remove click. Expected ${expectedBefore} but got ${rowCount}`
+ );
+ }
+
+ const removeLink = root.querySelector(
+ 'tr:nth-child(2) td:nth-child(3) a'
+ );
+ removeLink.click();
+ await afterFrameAsync();
+
+ rowCount = root.querySelectorAll('tr').length;
+ if (rowCount !== expectedAfter) {
+ throw new Error(
+ `${label}: Incorrect number of rows after after remove click. Expected ${expectedAfter} but got ${rowCount}`
+ );
+ }
+ }
+
+ async function warmupRun(i) {
+ // Test out hydrate and ensure it works
+ const hydrateRoot = setupHydrateRoot();
+
+ // Verify initial hydrate root isn't already hydrated and is static
+ testElementText(firstRowSel, '1');
+ testElementText(lastRowSel, '1000');
+ await clickRemove(hydrateRoot, `WARMUP ${i} - prehydrate`, 1000, 1000);
+
+ const store = new Store();
+ store.data = baseStore.data.slice();
+ createRoot(hydrateRoot).hydrate(createElement(Main, { store }));
+
+ // Verify hydrate has correct markup and is properly hydrated
+ testElementText(firstRowSel, '1');
+ testElementText(lastRowSel, '1000');
+ await clickRemove(hydrateRoot, `WARMUP ${i} - posthydrate`, 1000, 999);
+ }
+
+ function timedRun() {
+ afterFrame(function () {
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ });
+
+ const hydrateRoot = setupHydrateRoot();
+ const store = new Store();
+ store.data = baseStore.data.slice();
+
+ performance.mark('start');
+ createRoot(hydrateRoot).hydrate(createElement(Main, { store }));
+ }
+
+ async function main() {
+ // const WARMUP_COUNT = 5;
+ const WARMUP_COUNT = 5;
+ for (let i = 0; i < WARMUP_COUNT; i++) {
+ await warmupRun(i);
+ }
+
+ await afterFrameAsync();
+
+ timedRun();
+ }
+
+ initializeTemplate().then(main);
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/keyed-children/components.js b/preact/benches/src/keyed-children/components.js
new file mode 100644
index 0000000..0960b89
--- /dev/null
+++ b/preact/benches/src/keyed-children/components.js
@@ -0,0 +1,152 @@
+import { Store } from './store.js';
+
+/**
+ * @param {import('./index').Framework} framework
+ */
+export function getComponents({ createElement, Component }) {
+ class Row extends Component {
+ constructor(props) {
+ super(props);
+ this.onDelete = this.onDelete.bind(this);
+ this.onClick = this.onClick.bind(this);
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return (
+ nextProps.data !== this.props.data ||
+ nextProps.styleClass !== this.props.styleClass
+ );
+ }
+
+ onDelete() {
+ this.props.onDelete(this.props.data.id);
+ }
+
+ onClick() {
+ this.props.onClick(this.props.data.id);
+ }
+
+ render() {
+ let { styleClass, onClick, onDelete, data } = this.props;
+ return createElement(
+ 'tr',
+ {
+ className: styleClass
+ },
+ createElement(
+ 'td',
+ {
+ className: 'col-md-1'
+ },
+ data.id
+ ),
+ createElement(
+ 'td',
+ {
+ className: 'col-md-4'
+ },
+ createElement(
+ 'a',
+ {
+ onClick: this.onClick
+ },
+ data.label
+ )
+ ),
+ createElement(
+ 'td',
+ {
+ className: 'col-md-1'
+ },
+ createElement(
+ 'a',
+ {
+ onClick: this.onDelete
+ },
+ createElement('span', {
+ className: 'glyphicon glyphicon-remove',
+ 'aria-hidden': 'true'
+ })
+ )
+ ),
+ createElement('td', {
+ className: 'col-md-6'
+ })
+ );
+ }
+ }
+
+ class Main extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { store: props.store ?? new Store() };
+ this.select = this.select.bind(this);
+ this.delete = this.delete.bind(this);
+
+ // @ts-ignore
+ window.app = this;
+ }
+ run() {
+ this.state.store.run();
+ this.setState({ store: this.state.store });
+ }
+ add() {
+ this.state.store.add();
+ this.setState({ store: this.state.store });
+ }
+ update() {
+ this.state.store.update();
+ this.setState({ store: this.state.store });
+ }
+ select(id) {
+ this.state.store.select(id);
+ this.setState({ store: this.state.store });
+ }
+ delete(id) {
+ this.state.store.delete(id);
+ this.setState({ store: this.state.store });
+ }
+ runLots() {
+ this.state.store.runLots();
+ this.setState({ store: this.state.store });
+ }
+ clear() {
+ this.state.store.clear();
+ this.setState({ store: this.state.store });
+ }
+ swapRows() {
+ this.state.store.swapRows();
+ this.setState({ store: this.state.store });
+ }
+ render() {
+ let rows = this.state.store.data.map((d, i) => {
+ return createElement(Row, {
+ key: d.id,
+ data: d,
+ onClick: this.select,
+ onDelete: this.delete,
+ styleClass: d.id === this.state.store.selected ? 'danger' : ''
+ });
+ });
+ return createElement(
+ 'div',
+ {
+ className: 'container'
+ },
+ createElement(
+ 'table',
+ {
+ className: 'table table-hover table-striped test-data'
+ },
+ createElement('tbody', {}, rows)
+ ),
+ createElement('span', {
+ className: 'preloadicon glyphicon glyphicon-remove',
+ 'aria-hidden': 'true'
+ })
+ );
+ }
+ }
+
+ return { Main, Row };
+}
diff --git a/preact/benches/src/keyed-children/index.js b/preact/benches/src/keyed-children/index.js
new file mode 100644
index 0000000..ece1265
--- /dev/null
+++ b/preact/benches/src/keyed-children/index.js
@@ -0,0 +1,29 @@
+import { getComponents } from './components.js';
+
+/**
+ * @typedef Framework
+ * @property {(type: any, props?: any, ...children: any) => JSX.Element} createElement
+ * @property {(root: HTMLElement) => ({ render(vnode: JSX.Element): void; hydrate(vnode: JSX.Element): void; })} createRoot
+ * @property {any} Component
+ *
+ * @param {Framework} framework
+ * @param {HTMLElement} rootDom
+ */
+export function render(framework, rootDom) {
+ const { Main } = getComponents(framework);
+ framework.createRoot(rootDom).render(framework.createElement(Main));
+
+ /** @type {Main} */
+ // @ts-ignore
+ const app = window.app;
+ return {
+ run: app.run.bind(app),
+ add: app.add.bind(app),
+ update: app.update.bind(app),
+ select: app.select.bind(app),
+ delete: app.delete.bind(app),
+ runLots: app.runLots.bind(app),
+ clear: app.clear.bind(app),
+ swapRows: app.swapRows.bind(app)
+ };
+}
diff --git a/preact/benches/src/keyed-children/store.js b/preact/benches/src/keyed-children/store.js
new file mode 100644
index 0000000..413208d
--- /dev/null
+++ b/preact/benches/src/keyed-children/store.js
@@ -0,0 +1,119 @@
+function _random(max) {
+ return Math.round(Math.random() * 1000) % max;
+}
+
+export class Store {
+ constructor() {
+ this.data = [];
+ this.selected = undefined;
+ this.id = 1;
+ }
+ buildData(count = 1000) {
+ var adjectives = [
+ 'pretty',
+ 'large',
+ 'big',
+ 'small',
+ 'tall',
+ 'short',
+ 'long',
+ 'handsome',
+ 'plain',
+ 'quaint',
+ 'clean',
+ 'elegant',
+ 'easy',
+ 'angry',
+ 'crazy',
+ 'helpful',
+ 'mushy',
+ 'odd',
+ 'unsightly',
+ 'adorable',
+ 'important',
+ 'inexpensive',
+ 'cheap',
+ 'expensive',
+ 'fancy'
+ ];
+ var colours = [
+ 'red',
+ 'yellow',
+ 'blue',
+ 'green',
+ 'pink',
+ 'brown',
+ 'purple',
+ 'brown',
+ 'white',
+ 'black',
+ 'orange'
+ ];
+ var nouns = [
+ 'table',
+ 'chair',
+ 'house',
+ 'bbq',
+ 'desk',
+ 'car',
+ 'pony',
+ 'cookie',
+ 'sandwich',
+ 'burger',
+ 'pizza',
+ 'mouse',
+ 'keyboard'
+ ];
+ var data = [];
+ for (var i = 0; i < count; i++)
+ data.push({
+ id: this.id++,
+ label:
+ adjectives[_random(adjectives.length)] +
+ ' ' +
+ colours[_random(colours.length)] +
+ ' ' +
+ nouns[_random(nouns.length)]
+ });
+ return data;
+ }
+ updateData(mod = 10) {
+ for (let i = 0; i < this.data.length; i += 10) {
+ this.data[i] = Object.assign({}, this.data[i], {
+ label: this.data[i].label + ' !!!'
+ });
+ }
+ }
+ delete(id) {
+ var idx = this.data.findIndex(d => d.id === id);
+ this.data.splice(idx, 1);
+ }
+ run() {
+ this.data = this.buildData();
+ this.selected = undefined;
+ }
+ add() {
+ this.data = this.data.concat(this.buildData(1000));
+ }
+ update() {
+ this.updateData();
+ }
+ select(id) {
+ this.selected = id;
+ }
+ runLots() {
+ this.data = this.buildData(10000);
+ this.selected = undefined;
+ }
+ clear() {
+ this.data = [];
+ this.selected = undefined;
+ }
+ swapRows() {
+ if (this.data.length > 998) {
+ var a = this.data[1];
+ this.data[1] = this.data[998];
+ this.data[998] = a;
+ }
+ }
+}
diff --git a/preact/benches/src/many_updates.html b/preact/benches/src/many_updates.html
new file mode 100644
index 0000000..e59b304
--- /dev/null
+++ b/preact/benches/src/many_updates.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Patching HTML</title>
+ <style>
+ .hello {
+ color: red;
+ }
+
+ .bye {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="root"></div>
+ <script type="module">
+ import { measureName, measureMemory } from './util.js';
+ import { createRoot, createElement as h } from 'framework';
+
+ const state = {
+ msg: 'hello',
+ list: new Array(1000).fill(0).map((_, i) => ({
+ i,
+ text: 'foobar' + i
+ }))
+ };
+
+ let counter = 0;
+ function App() {
+ return h(
+ 'div',
+ { id: 'app' },
+ h('p', null, '> ', ++counter, ' <'),
+ h('p', null, state.msg),
+ ...state.list.map((obj, i) =>
+ h(
+ 'div',
+ { key: i, title: state.msg + i },
+ h('span', { className: state.msg }, obj.text),
+ h('span', { className: 'baz' }, 'one'),
+ h('span', { className: 'qux' }, 'two'),
+ h(
+ 'div',
+ null,
+ h('span', { className: 'qux' }, 'three'),
+ h('span', { className: 'qux' }, 'four'),
+ h('span', { className: 'baz' }, 'five'),
+ h(
+ 'div',
+ null,
+ h('span', { className: 'qux' }, 'six'),
+ h('span', { className: 'baz' }, 'seven'),
+ h('span', { className: state.msg }, 'eight')
+ )
+ )
+ )
+ )
+ );
+ }
+
+ const root = createRoot(document.getElementById('root'));
+
+ // const p = performance.now();
+ root.render(h(App));
+ // console.log(`mount: ${(performance.now() - p).toFixed(2)}ms`);
+
+ // const patchResults = [];
+
+ function runPatch() {
+ // const s = performance.now();
+ state.msg = state.msg === 'hello' ? 'bye' : 'hello';
+ state.list[0].text = state.msg;
+ root.render(h(App));
+ // patchResults.push(performance.now() - s);
+ }
+
+ async function warmup() {
+ // const count = 100;
+ const count = 25;
+
+ for (let i = 0; i < count; i++) {
+ runPatch();
+ await new Promise(r => requestAnimationFrame(r));
+ }
+
+ // let fastest = Infinity;
+ // const total = patchResults.reduce((all, cur) => {
+ // if (cur < fastest) {
+ // fastest = cur;
+ // }
+ // return all + cur;
+ // }, 0);
+
+ // console.log(`${count} runs average: ${(total / count).toFixed(2)}ms`);
+ // console.log(`fastest run: ${fastest.toFixed(2)}ms`);
+ }
+
+ warmup().then(async () => {
+ performance.mark('start');
+ runPatch();
+ await new Promise(r => requestAnimationFrame(r));
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+
+ measureMemory();
+ });
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/text_update.html b/preact/benches/src/text_update.html
new file mode 100644
index 0000000..6874558
--- /dev/null
+++ b/preact/benches/src/text_update.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Text Updates</title>
+ </head>
+ <body>
+ <div id="root"></div>
+ <script type="module">
+ import { measureName, measureMemory } from './util.js';
+ import { createRoot, createElement } from 'framework';
+
+ const root = createRoot(document.getElementById('root'));
+
+ function component({ randomValue }) {
+ return createElement('div', {}, [
+ createElement('h2', {}, 'Test ' + randomValue),
+ createElement('h1', {}, `===${randomValue}===`)
+ ]);
+ }
+
+ let result;
+
+ performance.mark('start');
+ for (let i = 0; i < 100; i++) {
+ root.render(createElement(component, { randomValue: i }));
+ }
+ performance.mark('stop');
+ performance.measure(measureName, 'start', 'stop');
+ measureMemory();
+ </script>
+ </body>
+</html>
diff --git a/preact/benches/src/util.js b/preact/benches/src/util.js
new file mode 100644
index 0000000..64c4765
--- /dev/null
+++ b/preact/benches/src/util.js
@@ -0,0 +1,98 @@
+// import afterFrame from "../node_modules/afterframe/dist/afterframe.module.js";
+import afterFrame from 'afterframe';
+
+export { afterFrame };
+
+export const measureName = 'duration';
+
+let promise = null;
+export function afterFrameAsync() {
+ if (promise === null) {
+ promise = new Promise(resolve =>
+ afterFrame(time => {
+ promise = null;
+ resolve(time);
+ })
+ );
+ }
+
+ return promise;
+}
+
+export function measureMemory() {
+ if ('gc' in window && 'memory' in performance) {
+ // Report results in MBs
+ window.gc();
+ window.usedJSHeapSize = performance.memory.usedJSHeapSize / 1e6;
+ } else {
+ window.usedJSHeapSize = 0;
+ }
+}
+
+export function markRunStart(runId) {
+ performance.mark(`run-${runId}-start`);
+}
+
+let staticPromise = Promise.resolve();
+export function markRunEnd(runId) {
+ return staticPromise.then(() => {
+ performance.mark(`run-${runId}-end`);
+ performance.measure(
+ `run-${runId}`,
+ `run-${runId}-start`,
+ `run-${runId}-end`
+ );
+ });
+}
+
+export function getRowIdSel(index) {
+ return `tbody > tr:nth-child(${index}) > td:first-child`;
+}
+
+export function getRowLinkSel(index) {
+ return `tbody > tr:nth-child(${index}) > td:nth-child(2) > a`;
+}
+
+/**
+ * @param {string} selector
+ * @returns {Element}
+ */
+export function getBySelector(selector) {
+ const element = document.querySelector(selector);
+ if (element == null) {
+ throw new Error(`Could not find element matching selector: ${selector}`);
+ }
+
+ return element;
+}
+
+export function testElement(selector) {
+ const testElement = document.querySelector(selector);
+ if (testElement == null) {
+ throw new Error(
+ 'Test failed. Rendering after one paint was not successful'
+ );
+ }
+}
+
+export function testElementText(selector, expectedText) {
+ const elm = document.querySelector(selector);
+ if (elm == null) {
+ throw new Error('Could not find element matching selector: ' + selector);
+ }
+
+ if (elm.textContent != expectedText) {
+ throw new Error(
+ `Element did not have expected text. Expected: '${expectedText}' Actual: '${elm.textContent}'`
+ );
+ }
+}
+
+export function testElementTextContains(selector, expectedText) {
+ const elm = getBySelector(selector);
+ if (!elm.textContent.includes(expectedText)) {
+ throw new Error(
+ `Element did not include expected text. Expected to include: '${expectedText}' Actual: '${elm.textContent}'`
+ );
+ }
+}
diff --git a/preact/compat/LICENSE b/preact/compat/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/compat/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/compat/jsx-dev-runtime.js b/preact/compat/jsx-dev-runtime.js
new file mode 100644
index 0000000..355f008
--- /dev/null
+++ b/preact/compat/jsx-dev-runtime.js
@@ -0,0 +1 @@
+module.exports = require('preact/jsx-runtime');
diff --git a/preact/compat/jsx-dev-runtime.mjs b/preact/compat/jsx-dev-runtime.mjs
new file mode 100644
index 0000000..5e28f44
--- /dev/null
+++ b/preact/compat/jsx-dev-runtime.mjs
@@ -0,0 +1 @@
+export * from 'preact/jsx-runtime';
diff --git a/preact/compat/jsx-runtime.js b/preact/compat/jsx-runtime.js
new file mode 100644
index 0000000..355f008
--- /dev/null
+++ b/preact/compat/jsx-runtime.js
@@ -0,0 +1 @@
+module.exports = require('preact/jsx-runtime');
diff --git a/preact/compat/jsx-runtime.mjs b/preact/compat/jsx-runtime.mjs
new file mode 100644
index 0000000..5e28f44
--- /dev/null
+++ b/preact/compat/jsx-runtime.mjs
@@ -0,0 +1 @@
+export * from 'preact/jsx-runtime';
diff --git a/preact/compat/mangle.json b/preact/compat/mangle.json
new file mode 100644
index 0000000..506a6a4
--- /dev/null
+++ b/preact/compat/mangle.json
@@ -0,0 +1,21 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/preact/compat/package.json b/preact/compat/package.json
new file mode 100644
index 0000000..c39ef14
--- /dev/null
+++ b/preact/compat/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "preact-compat",
+ "amdName": "preactCompat",
+ "version": "4.0.0",
+ "private": true,
+ "description": "A React compatibility layer for Preact",
+ "main": "dist/compat.js",
+ "module": "dist/compat.module.js",
+ "umd:main": "dist/compat.umd.js",
+ "source": "src/index.js",
+ "types": "src/index.d.ts",
+ "license": "MIT",
+ "mangle": {
+ "regex": "^_"
+ },
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ }
+}
diff --git a/preact/compat/scheduler.js b/preact/compat/scheduler.js
new file mode 100644
index 0000000..01c4ceb
--- /dev/null
+++ b/preact/compat/scheduler.js
@@ -0,0 +1,15 @@
+// see scheduler.mjs
+
+function unstable_runWithPriority(priority, callback) {
+ return callback();
+}
+
+module.exports = {
+ unstable_ImmediatePriority: 1,
+ unstable_UserBlockingPriority: 2,
+ unstable_NormalPriority: 3,
+ unstable_LowPriority: 4,
+ unstable_IdlePriority: 5,
+ unstable_runWithPriority,
+ unstable_now: performance.now.bind(performance)
+};
diff --git a/preact/compat/scheduler.mjs b/preact/compat/scheduler.mjs
new file mode 100644
index 0000000..c51bd4b
--- /dev/null
+++ b/preact/compat/scheduler.mjs
@@ -0,0 +1,23 @@
+/* eslint-disable */
+
+// This file includes experimental React APIs exported from the "scheduler"
+// npm package. Despite being explicitely marked as unstable some libraries
+// already make use of them. This file is not a full replacement for the
+// scheduler package, but includes the necessary shims to make those libraries
+// work with Preact.
+
+export var unstable_ImmediatePriority = 1;
+export var unstable_UserBlockingPriority = 2;
+export var unstable_NormalPriority = 3;
+export var unstable_LowPriority = 4;
+export var unstable_IdlePriority = 5;
+
+/**
+ * @param {number} priority
+ * @param {() => void} callback
+ */
+export function unstable_runWithPriority(priority, callback) {
+ return callback();
+}
+
+export var unstable_now = performance.now.bind(performance);
diff --git a/preact/compat/server.js b/preact/compat/server.js
new file mode 100644
index 0000000..7156872
--- /dev/null
+++ b/preact/compat/server.js
@@ -0,0 +1,15 @@
+/* eslint-disable */
+var renderToString;
+try {
+ const mod = require('preact-render-to-string');
+ renderToString = mod.default || mod.renderToString || mod;
+} catch (e) {
+ throw Error(
+ 'renderToString() error: missing "preact-render-to-string" dependency.'
+ );
+}
+
+module.exports = {
+ renderToString: renderToString,
+ renderToStaticMarkup: renderToString
+};
diff --git a/preact/compat/server.mjs b/preact/compat/server.mjs
new file mode 100644
index 0000000..9e8858e
--- /dev/null
+++ b/preact/compat/server.mjs
@@ -0,0 +1,4 @@
+export {
+ renderToString,
+ renderToString as renderToStaticMarkup
+} from 'preact-render-to-string';
diff --git a/preact/compat/src/Children.js b/preact/compat/src/Children.js
new file mode 100644
index 0000000..0295d93
--- /dev/null
+++ b/preact/compat/src/Children.js
@@ -0,0 +1,21 @@
+import { toChildArray } from 'preact';
+
+const mapFn = (children, fn) => {
+ if (children == null) return null;
+ return toChildArray(toChildArray(children).map(fn));
+};
+
+// This API is completely unnecessary for Preact, so it's basically passthrough.
+export const Children = {
+ map: mapFn,
+ forEach: mapFn,
+ count(children) {
+ return children ? toChildArray(children).length : 0;
+ },
+ only(children) {
+ const normalized = toChildArray(children);
+ if (normalized.length !== 1) throw 'Children.only';
+ return normalized[0];
+ },
+ toArray: toChildArray
+};
diff --git a/preact/compat/src/PureComponent.js b/preact/compat/src/PureComponent.js
new file mode 100644
index 0000000..6396ce4
--- /dev/null
+++ b/preact/compat/src/PureComponent.js
@@ -0,0 +1,15 @@
+import { Component } from 'preact';
+import { shallowDiffers } from './util';
+
+/**
+ * Component class with a predefined `shouldComponentUpdate` implementation
+ */
+export function PureComponent(p) {
+ this.props = p;
+}
+PureComponent.prototype = new Component();
+// Some third-party libraries check if this property is present
+PureComponent.prototype.isPureReactComponent = true;
+PureComponent.prototype.shouldComponentUpdate = function(props, state) {
+ return shallowDiffers(this.props, props) || shallowDiffers(this.state, state);
+};
diff --git a/preact/compat/src/forwardRef.js b/preact/compat/src/forwardRef.js
new file mode 100644
index 0000000..39585cb
--- /dev/null
+++ b/preact/compat/src/forwardRef.js
@@ -0,0 +1,51 @@
+import { options } from 'preact';
+import { assign } from './util';
+
+let oldDiffHook = options._diff;
+options._diff = vnode => {
+ if (vnode.type && vnode.type._forwarded && vnode.ref) {
+ vnode.props.ref = vnode.ref;
+ vnode.ref = null;
+ }
+ if (oldDiffHook) oldDiffHook(vnode);
+};
+
+export const REACT_FORWARD_SYMBOL =
+ (typeof Symbol != 'undefined' &&
+ Symbol.for &&
+ Symbol.for('react.forward_ref')) ||
+ 0xf47;
+
+/**
+ * Pass ref down to a child. This is mainly used in libraries with HOCs that
+ * wrap components. Using `forwardRef` there is an easy way to get a reference
+ * of the wrapped component instead of one of the wrapper itself.
+ * @param {import('./index').ForwardFn} fn
+ * @returns {import('./internal').FunctionComponent}
+ */
+export function forwardRef(fn) {
+ // We always have ref in props.ref, except for
+ // mobx-react. It will call this function directly
+ // and always pass ref as the second argument.
+ function Forwarded(props, ref) {
+ let clone = assign({}, props);
+ delete clone.ref;
+ ref = props.ref || ref;
+ return fn(
+ clone,
+ !ref || (typeof ref === 'object' && !('current' in ref)) ? null : ref
+ );
+ }
+
+ // mobx-react checks for this being present
+ Forwarded.$$typeof = REACT_FORWARD_SYMBOL;
+ // mobx-react heavily relies on implementation details.
+ // It expects an object here with a `render` property,
+ // and prototype.render will fail. Without this
+ // mobx-react throws.
+ Forwarded.render = Forwarded;
+
+ Forwarded.prototype.isReactComponent = Forwarded._forwarded = true;
+ Forwarded.displayName = 'ForwardRef(' + (fn.displayName || fn.name) + ')';
+ return Forwarded;
+}
diff --git a/preact/compat/src/index.d.ts b/preact/compat/src/index.d.ts
new file mode 100644
index 0000000..82c1a4f
--- /dev/null
+++ b/preact/compat/src/index.d.ts
@@ -0,0 +1,140 @@
+import * as _hooks from '../../hooks';
+import * as preact from '../../src';
+import { JSXInternal } from '../../src/jsx';
+import * as _Suspense from './suspense';
+import * as _SuspenseList from './suspense-list';
+
+// export default React;
+export = React;
+export as namespace React;
+declare namespace React {
+ // Export JSX
+ export import JSX = JSXInternal;
+
+ // Hooks
+ export import CreateHandle = _hooks.CreateHandle;
+ export import EffectCallback = _hooks.EffectCallback;
+ export import Inputs = _hooks.Inputs;
+ export import PropRef = _hooks.PropRef;
+ export import Reducer = _hooks.Reducer;
+ export import Ref = _hooks.Ref;
+ export import StateUpdater = _hooks.StateUpdater;
+ export import useCallback = _hooks.useCallback;
+ export import useContext = _hooks.useContext;
+ export import useDebugValue = _hooks.useDebugValue;
+ export import useEffect = _hooks.useEffect;
+ export import useImperativeHandle = _hooks.useImperativeHandle;
+ export import useLayoutEffect = _hooks.useLayoutEffect;
+ export import useMemo = _hooks.useMemo;
+ export import useReducer = _hooks.useReducer;
+ export import useRef = _hooks.useRef;
+ export import useState = _hooks.useState;
+
+ // Preact Defaults
+ export import Component = preact.Component;
+ export import FunctionComponent = preact.FunctionComponent;
+ export import FC = preact.FunctionComponent;
+ export import createContext = preact.createContext;
+ export import createRef = preact.createRef;
+ export import Fragment = preact.Fragment;
+ export import createElement = preact.createElement;
+ export import cloneElement = preact.cloneElement;
+
+ // Suspense
+ export import Suspense = _Suspense.Suspense;
+ export import lazy = _Suspense.lazy;
+ export import SuspenseList = _SuspenseList.SuspenseList;
+
+ // Compat
+ export import StrictMode = preact.Fragment;
+ export const version: string;
+
+ export function createPortal(
+ vnode: preact.VNode,
+ container: Element
+ ): preact.VNode<any>;
+
+ export function render(
+ vnode: preact.VNode<any>,
+ parent: Element,
+ callback?: () => void
+ ): Component | null;
+
+ export function hydrate(
+ vnode: preact.VNode<any>,
+ parent: Element,
+ callback?: () => void
+ ): Component | null;
+
+ export function unmountComponentAtNode(
+ container: Element | Document | ShadowRoot | DocumentFragment
+ ): boolean;
+
+ export function createFactory(
+ type: preact.VNode<any>['type']
+ ): (
+ props?: any,
+ ...children: preact.ComponentChildren[]
+ ) => preact.VNode<any>;
+ export function isValidElement(element: any): boolean;
+ export function findDOMNode(component: preact.Component): Element | null;
+
+ export abstract class PureComponent<P = {}, S = {}> extends preact.Component<
+ P,
+ S
+ > {
+ isPureReactComponent: boolean;
+ }
+
+ export function memo<P = {}>(
+ component: preact.FunctionalComponent<P>,
+ comparer?: (prev: P, next: P) => boolean
+ ): preact.FunctionComponent<P>;
+ export function memo<C extends preact.FunctionalComponent<any>>(
+ component: C,
+ comparer?: (
+ prev: preact.ComponentProps<C>,
+ next: preact.ComponentProps<C>
+ ) => boolean
+ ): C;
+
+ export interface ForwardFn<P = {}, T = any> {
+ (props: P, ref: Ref<T>): preact.ComponentChild;
+ displayName?: string;
+ }
+
+ export function forwardRef<R, P = {}>(
+ fn: ForwardFn<P, R>
+ ): preact.FunctionalComponent<Omit<P, 'ref'> & { ref?: preact.RefObject<R> }>;
+
+ export function unstable_batchedUpdates(
+ callback: (arg?: any) => void,
+ arg?: any
+ ): void;
+
+ export const Children: {
+ map<T extends preact.ComponentChild, R>(
+ children: T | T[],
+ fn: (child: T, i: number) => R
+ ): R[];
+ forEach<T extends preact.ComponentChild>(
+ children: T | T[],
+ fn: (child: T, i: number) => void
+ ): void;
+ count: (children: preact.ComponentChildren) => number;
+ only: (children: preact.ComponentChildren) => preact.ComponentChild;
+ toArray: (children: preact.ComponentChildren) => preact.VNode<{}>[];
+ };
+
+ // scheduler
+ export const unstable_ImmediatePriority: number;
+ export const unstable_UserBlockingPriority: number;
+ export const unstable_NormalPriority: number;
+ export const unstable_LowPriority: number;
+ export const unstable_IdlePriority: number;
+ export function unstable_runWithPriority(
+ priority: number,
+ callback: () => void
+ ): void;
+ export const unstable_now: () => number;
+}
diff --git a/preact/compat/src/index.js b/preact/compat/src/index.js
new file mode 100644
index 0000000..c8f9a6c
--- /dev/null
+++ b/preact/compat/src/index.js
@@ -0,0 +1,187 @@
+import {
+ createElement,
+ render as preactRender,
+ cloneElement as preactCloneElement,
+ createRef,
+ Component,
+ createContext,
+ Fragment
+} from 'preact';
+import {
+ useState,
+ useReducer,
+ useEffect,
+ useLayoutEffect,
+ useRef,
+ useImperativeHandle,
+ useMemo,
+ useCallback,
+ useContext,
+ useDebugValue
+} from 'preact/hooks';
+import { PureComponent } from './PureComponent';
+import { memo } from './memo';
+import { forwardRef } from './forwardRef';
+import { Children } from './Children';
+import { Suspense, lazy } from './suspense';
+import { SuspenseList } from './suspense-list';
+import { createPortal } from './portals';
+import {
+ hydrate,
+ render,
+ REACT_ELEMENT_TYPE,
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+} from './render';
+
+const version = '17.0.2'; // trick libraries to think we are react
+
+/**
+ * Legacy version of createElement.
+ * @param {import('./internal').VNode["type"]} type The node name or Component constructor
+ */
+function createFactory(type) {
+ return createElement.bind(null, type);
+}
+
+/**
+ * Check if the passed element is a valid (p)react node.
+ * @param {*} element The element to check
+ * @returns {boolean}
+ */
+function isValidElement(element) {
+ return !!element && element.$$typeof === REACT_ELEMENT_TYPE;
+}
+
+/**
+ * Wrap `cloneElement` to abort if the passed element is not a valid element and apply
+ * all vnode normalizations.
+ * @param {import('./internal').VNode} element The vnode to clone
+ * @param {object} props Props to add when cloning
+ * @param {Array<import('./internal').ComponentChildren>} rest Optional component children
+ */
+function cloneElement(element) {
+ if (!isValidElement(element)) return element;
+ return preactCloneElement.apply(null, arguments);
+}
+
+/**
+ * Remove a component tree from the DOM, including state and event handlers.
+ * @param {import('./internal').PreactElement} container
+ * @returns {boolean}
+ */
+function unmountComponentAtNode(container) {
+ if (container._children) {
+ preactRender(null, container);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Get the matching DOM node for a component
+ * @param {import('./internal').Component} component
+ * @returns {import('./internal').PreactElement | null}
+ */
+function findDOMNode(component) {
+ return (
+ (component &&
+ (component.base || (component.nodeType === 1 && component))) ||
+ null
+ );
+}
+
+/**
+ * Deprecated way to control batched rendering inside the reconciler, but we
+ * already schedule in batches inside our rendering code
+ * @template Arg
+ * @param {(arg: Arg) => void} callback function that triggers the updated
+ * @param {Arg} [arg] Optional argument that can be passed to the callback
+ */
+// eslint-disable-next-line camelcase
+const unstable_batchedUpdates = (callback, arg) => callback(arg);
+
+/**
+ * In React, `flushSync` flushes the entire tree and forces a rerender. It's
+ * implmented here as a no-op.
+ * @template Arg
+ * @template Result
+ * @param {(arg: Arg) => Result} callback function that runs before the flush
+ * @param {Arg} [arg] Optional arugment that can be passed to the callback
+ * @returns
+ */
+const flushSync = (callback, arg) => callback(arg);
+
+/**
+ * Strict Mode is not implemented in Preact, so we provide a stand-in for it
+ * that just renders its children without imposing any restrictions.
+ */
+const StrictMode = Fragment;
+
+export * from 'preact/hooks';
+export {
+ version,
+ Children,
+ render,
+ hydrate,
+ unmountComponentAtNode,
+ createPortal,
+ createElement,
+ createContext,
+ createFactory,
+ cloneElement,
+ createRef,
+ Fragment,
+ isValidElement,
+ findDOMNode,
+ Component,
+ PureComponent,
+ memo,
+ forwardRef,
+ flushSync,
+ // eslint-disable-next-line camelcase
+ unstable_batchedUpdates,
+ StrictMode,
+ Suspense,
+ SuspenseList,
+ lazy,
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+};
+
+// React copies the named exports to the default one.
+export default {
+ useState,
+ useReducer,
+ useEffect,
+ useLayoutEffect,
+ useRef,
+ useImperativeHandle,
+ useMemo,
+ useCallback,
+ useContext,
+ useDebugValue,
+ version,
+ Children,
+ render,
+ hydrate,
+ unmountComponentAtNode,
+ createPortal,
+ createElement,
+ createContext,
+ createFactory,
+ cloneElement,
+ createRef,
+ Fragment,
+ isValidElement,
+ findDOMNode,
+ Component,
+ PureComponent,
+ memo,
+ forwardRef,
+ flushSync,
+ unstable_batchedUpdates,
+ StrictMode,
+ Suspense,
+ SuspenseList,
+ lazy,
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+};
diff --git a/preact/compat/src/internal.d.ts b/preact/compat/src/internal.d.ts
new file mode 100644
index 0000000..cb68ffa
--- /dev/null
+++ b/preact/compat/src/internal.d.ts
@@ -0,0 +1,47 @@
+import {
+ Component as PreactComponent,
+ VNode as PreactVNode,
+ FunctionComponent as PreactFunctionComponent
+} from '../../src/internal';
+import { SuspenseProps } from './suspense';
+
+export { ComponentChildren } from '../..';
+
+export { PreactElement } from '../../src/internal';
+
+export interface Component<P = {}, S = {}> extends PreactComponent<P, S> {
+ isReactComponent?: object;
+ isPureReactComponent?: true;
+ _patchedLifecycles?: true;
+
+ // Suspense internal properties
+ _childDidSuspend?(error: Promise<void>, suspendingVNode: VNode): void;
+ _suspended: (vnode: VNode) => (unsuspend: () => void) => void;
+ _onResolve?(): void;
+
+ // Portal internal properties
+ _temp: any;
+ _container: PreactElement;
+}
+
+export interface FunctionComponent<P = {}> extends PreactFunctionComponent<P> {
+ shouldComponentUpdate?(nextProps: Readonly<P>): boolean;
+ _forwarded?: boolean;
+ _patchedLifecycles?: true;
+}
+
+export interface VNode<T = any> extends PreactVNode<T> {
+ $$typeof?: symbol | string;
+ preactCompatNormalized?: boolean;
+}
+
+export interface SuspenseState {
+ _suspended?: null | VNode<any>;
+}
+
+export interface SuspenseComponent
+ extends PreactComponent<SuspenseProps, SuspenseState> {
+ _pendingSuspensionCount: number;
+ _suspenders: Component[];
+ _detachOnNextRender: null | VNode<any>;
+}
diff --git a/preact/compat/src/memo.js b/preact/compat/src/memo.js
new file mode 100644
index 0000000..e743199
--- /dev/null
+++ b/preact/compat/src/memo.js
@@ -0,0 +1,34 @@
+import { createElement } from 'preact';
+import { shallowDiffers } from './util';
+
+/**
+ * Memoize a component, so that it only updates when the props actually have
+ * changed. This was previously known as `React.pure`.
+ * @param {import('./internal').FunctionComponent} c functional component
+ * @param {(prev: object, next: object) => boolean} [comparer] Custom equality function
+ * @returns {import('./internal').FunctionComponent}
+ */
+export function memo(c, comparer) {
+ function shouldUpdate(nextProps) {
+ let ref = this.props.ref;
+ let updateRef = ref == nextProps.ref;
+ if (!updateRef && ref) {
+ ref.call ? ref(null) : (ref.current = null);
+ }
+
+ if (!comparer) {
+ return shallowDiffers(this.props, nextProps);
+ }
+
+ return !comparer(this.props, nextProps) || !updateRef;
+ }
+
+ function Memoed(props) {
+ this.shouldComponentUpdate = shouldUpdate;
+ return createElement(c, props);
+ }
+ Memoed.displayName = 'Memo(' + (c.displayName || c.name) + ')';
+ Memoed.prototype.isReactComponent = true;
+ Memoed._forwarded = true;
+ return Memoed;
+}
diff --git a/preact/compat/src/portals.js b/preact/compat/src/portals.js
new file mode 100644
index 0000000..cf9f8f7
--- /dev/null
+++ b/preact/compat/src/portals.js
@@ -0,0 +1,80 @@
+import { createElement, render } from 'preact';
+
+/**
+ * @param {import('../../src/index').RenderableProps<{ context: any }>} props
+ */
+function ContextProvider(props) {
+ this.getChildContext = () => props.context;
+ return props.children;
+}
+
+/**
+ * Portal component
+ * @this {import('./internal').Component}
+ * @param {object | null | undefined} props
+ *
+ * TODO: use createRoot() instead of fake root
+ */
+function Portal(props) {
+ const _this = this;
+ let container = props._container;
+
+ _this.componentWillUnmount = function() {
+ render(null, _this._temp);
+ _this._temp = null;
+ _this._container = null;
+ };
+
+ // When we change container we should clear our old container and
+ // indicate a new mount.
+ if (_this._container && _this._container !== container) {
+ _this.componentWillUnmount();
+ }
+
+ // When props.vnode is undefined/false/null we are dealing with some kind of
+ // conditional vnode. This should not trigger a render.
+ if (props._vnode) {
+ if (!_this._temp) {
+ _this._container = container;
+
+ // Create a fake DOM parent node that manages a subset of `container`'s children:
+ _this._temp = {
+ nodeType: 1,
+ parentNode: container,
+ childNodes: [],
+ appendChild(child) {
+ this.childNodes.push(child);
+ _this._container.appendChild(child);
+ },
+ insertBefore(child, before) {
+ this.childNodes.push(child);
+ _this._container.appendChild(child);
+ },
+ removeChild(child) {
+ this.childNodes.splice(this.childNodes.indexOf(child) >>> 1, 1);
+ _this._container.removeChild(child);
+ }
+ };
+ }
+
+ // Render our wrapping element into temp.
+ render(
+ createElement(ContextProvider, { context: _this.context }, props._vnode),
+ _this._temp
+ );
+ }
+ // When we come from a conditional render, on a mounted
+ // portal we should clear the DOM.
+ else if (_this._temp) {
+ _this.componentWillUnmount();
+ }
+}
+
+/**
+ * Create a `Portal` to continue rendering the vnode tree at a different DOM node
+ * @param {import('./internal').VNode} vnode The vnode to render
+ * @param {import('./internal').PreactElement} container The DOM node to continue rendering in to.
+ */
+export function createPortal(vnode, container) {
+ return createElement(Portal, { _vnode: vnode, _container: container });
+}
diff --git a/preact/compat/src/render.js b/preact/compat/src/render.js
new file mode 100644
index 0000000..2448d2d
--- /dev/null
+++ b/preact/compat/src/render.js
@@ -0,0 +1,219 @@
+import {
+ render as preactRender,
+ hydrate as preactHydrate,
+ options,
+ toChildArray,
+ Component
+} from 'preact';
+
+export const REACT_ELEMENT_TYPE =
+ (typeof Symbol != 'undefined' && Symbol.for && Symbol.for('react.element')) ||
+ 0xeac7;
+
+const CAMEL_PROPS = /^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/;
+
+// Input types for which onchange should not be converted to oninput.
+// type="file|checkbox|radio", plus "range" in IE11.
+// (IE11 doesn't support Symbol, which we use here to turn `rad` into `ra` which matches "range")
+const onChangeInputType = type =>
+ (typeof Symbol != 'undefined' && typeof Symbol() == 'symbol'
+ ? /fil|che|rad/i
+ : /fil|che|ra/i
+ ).test(type);
+
+// Some libraries like `react-virtualized` explicitly check for this.
+Component.prototype.isReactComponent = {};
+
+// `UNSAFE_*` lifecycle hooks
+// Preact only ever invokes the unprefixed methods.
+// Here we provide a base "fallback" implementation that calls any defined UNSAFE_ prefixed method.
+// - If a component defines its own `componentDidMount()` (including via defineProperty), use that.
+// - If a component defines `UNSAFE_componentDidMount()`, `componentDidMount` is the alias getter/setter.
+// - If anything assigns to an `UNSAFE_*` property, the assignment is forwarded to the unprefixed property.
+// See https://github.com/preactjs/preact/issues/1941
+[
+ 'componentWillMount',
+ 'componentWillReceiveProps',
+ 'componentWillUpdate'
+].forEach(key => {
+ Object.defineProperty(Component.prototype, key, {
+ configurable: true,
+ get() {
+ return this['UNSAFE_' + key];
+ },
+ set(v) {
+ Object.defineProperty(this, key, {
+ configurable: true,
+ writable: true,
+ value: v
+ });
+ }
+ });
+});
+
+/**
+ * Proxy render() since React returns a Component reference.
+ * @param {import('./internal').VNode} vnode VNode tree to render
+ * @param {import('./internal').PreactElement} parent DOM node to render vnode tree into
+ * @param {() => void} [callback] Optional callback that will be called after rendering
+ * @returns {import('./internal').Component | null} The root component reference or null
+ */
+export function render(vnode, parent, callback) {
+ // React destroys any existing DOM nodes, see #1727
+ // ...but only on the first render, see #1828
+ if (parent._children == null) {
+ parent.textContent = '';
+ }
+
+ preactRender(vnode, parent);
+ if (typeof callback == 'function') callback();
+
+ return vnode ? vnode._component : null;
+}
+
+export function hydrate(vnode, parent, callback) {
+ preactHydrate(vnode, parent);
+ if (typeof callback == 'function') callback();
+
+ return vnode ? vnode._component : null;
+}
+
+let oldEventHook = options.event;
+options.event = e => {
+ if (oldEventHook) e = oldEventHook(e);
+ e.persist = empty;
+ e.isPropagationStopped = isPropagationStopped;
+ e.isDefaultPrevented = isDefaultPrevented;
+ return (e.nativeEvent = e);
+};
+
+function empty() {}
+
+function isPropagationStopped() {
+ return this.cancelBubble;
+}
+
+function isDefaultPrevented() {
+ return this.defaultPrevented;
+}
+
+let classNameDescriptor = {
+ configurable: true,
+ get() {
+ return this.class;
+ }
+};
+
+let oldVNodeHook = options.vnode;
+options.vnode = vnode => {
+ let type = vnode.type;
+ let props = vnode.props;
+ let normalizedProps = props;
+
+ // only normalize props on Element nodes
+ if (typeof type === 'string') {
+ normalizedProps = {};
+
+ for (let i in props) {
+ let value = props[i];
+
+ if (i === 'value' && 'defaultValue' in props && value == null) {
+ // Skip applying value if it is null/undefined and we already set
+ // a default value
+ continue;
+ } else if (
+ i === 'defaultValue' &&
+ 'value' in props &&
+ props.value == null
+ ) {
+ // `defaultValue` is treated as a fallback `value` when a value prop is present but null/undefined.
+ // `defaultValue` for Elements with no value prop is the same as the DOM defaultValue property.
+ i = 'value';
+ } else if (i === 'download' && value === true) {
+ // Calling `setAttribute` with a truthy value will lead to it being
+ // passed as a stringified value, e.g. `download="true"`. React
+ // converts it to an empty string instead, otherwise the attribute
+ // value will be used as the file name and the file will be called
+ // "true" upon downloading it.
+ value = '';
+ } else if (/ondoubleclick/i.test(i)) {
+ i = 'ondblclick';
+ } else if (
+ /^onchange(textarea|input)/i.test(i + type) &&
+ !onChangeInputType(props.type)
+ ) {
+ i = 'oninput';
+ } else if (/^on(Ani|Tra|Tou|BeforeInp)/.test(i)) {
+ i = i.toLowerCase();
+ } else if (CAMEL_PROPS.test(i)) {
+ i = i.replace(/[A-Z0-9]/, '-$&').toLowerCase();
+ } else if (value === null) {
+ value = undefined;
+ }
+
+ normalizedProps[i] = value;
+ }
+
+ // Add support for array select values: <select multiple value={[]} />
+ if (
+ type == 'select' &&
+ normalizedProps.multiple &&
+ Array.isArray(normalizedProps.value)
+ ) {
+ // forEach() always returns undefined, which we abuse here to unset the value prop.
+ normalizedProps.value = toChildArray(props.children).forEach(child => {
+ child.props.selected =
+ normalizedProps.value.indexOf(child.props.value) != -1;
+ });
+ }
+
+ // Adding support for defaultValue in select tag
+ if (type == 'select' && normalizedProps.defaultValue != null) {
+ normalizedProps.value = toChildArray(props.children).forEach(child => {
+ if (normalizedProps.multiple) {
+ child.props.selected =
+ normalizedProps.defaultValue.indexOf(child.props.value) != -1;
+ } else {
+ child.props.selected =
+ normalizedProps.defaultValue == child.props.value;
+ }
+ });
+ }
+
+ vnode.props = normalizedProps;
+ }
+
+ if (type && props.class != props.className) {
+ classNameDescriptor.enumerable = 'className' in props;
+ if (props.className != null) normalizedProps.class = props.className;
+ Object.defineProperty(normalizedProps, 'className', classNameDescriptor);
+ }
+
+ vnode.$$typeof = REACT_ELEMENT_TYPE;
+
+ if (oldVNodeHook) oldVNodeHook(vnode);
+};
+
+// Only needed for react-relay
+let currentComponent;
+const oldBeforeRender = options._render;
+options._render = function(vnode) {
+ if (oldBeforeRender) {
+ oldBeforeRender(vnode);
+ }
+ currentComponent = vnode._component;
+};
+
+// This is a very very private internal function for React it
+// is used to sort-of do runtime dependency injection. So far
+// only `react-relay` makes use of it. It uses it to read the
+// context value.
+export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
+ ReactCurrentDispatcher: {
+ current: {
+ readContext(context) {
+ return currentComponent._globalContext[context._id].props.value;
+ }
+ }
+ }
+};
diff --git a/preact/compat/src/suspense-list.d.ts b/preact/compat/src/suspense-list.d.ts
new file mode 100644
index 0000000..caa1eb6
--- /dev/null
+++ b/preact/compat/src/suspense-list.d.ts
@@ -0,0 +1,14 @@
+import { Component, ComponentChild, ComponentChildren } from '../../src';
+
+//
+// SuspenseList
+// -----------------------------------
+
+export interface SuspenseListProps {
+ children?: ComponentChildren;
+ revealOrder?: 'forwards' | 'backwards' | 'together';
+}
+
+export class SuspenseList extends Component<SuspenseListProps> {
+ render(): ComponentChild;
+}
diff --git a/preact/compat/src/suspense-list.js b/preact/compat/src/suspense-list.js
new file mode 100644
index 0000000..cf162cb
--- /dev/null
+++ b/preact/compat/src/suspense-list.js
@@ -0,0 +1,126 @@
+import { Component, toChildArray } from 'preact';
+import { suspended } from './suspense.js';
+
+// Indexes to linked list nodes (nodes are stored as arrays to save bytes).
+const SUSPENDED_COUNT = 0;
+const RESOLVED_COUNT = 1;
+const NEXT_NODE = 2;
+
+// Having custom inheritance instead of a class here saves a lot of bytes.
+export function SuspenseList() {
+ this._next = null;
+ this._map = null;
+}
+
+// Mark one of child's earlier suspensions as resolved.
+// Some pending callbacks may become callable due to this
+// (e.g. the last suspended descendant gets resolved when
+// revealOrder === 'together'). Process those callbacks as well.
+const resolve = (list, child, node) => {
+ if (++node[RESOLVED_COUNT] === node[SUSPENDED_COUNT]) {
+ // The number a child (or any of its descendants) has been suspended
+ // matches the number of times it's been resolved. Therefore we
+ // mark the child as completely resolved by deleting it from ._map.
+ // This is used to figure out when *all* children have been completely
+ // resolved when revealOrder is 'together'.
+ list._map.delete(child);
+ }
+
+ // If revealOrder is falsy then we can do an early exit, as the
+ // callbacks won't get queued in the node anyway.
+ // If revealOrder is 'together' then also do an early exit
+ // if all suspended descendants have not yet been resolved.
+ if (
+ !list.props.revealOrder ||
+ (list.props.revealOrder[0] === 't' && list._map.size)
+ ) {
+ return;
+ }
+
+ // Walk the currently suspended children in order, calling their
+ // stored callbacks on the way. Stop if we encounter a child that
+ // has not been completely resolved yet.
+ node = list._next;
+ while (node) {
+ while (node.length > 3) {
+ node.pop()();
+ }
+ if (node[RESOLVED_COUNT] < node[SUSPENDED_COUNT]) {
+ break;
+ }
+ list._next = node = node[NEXT_NODE];
+ }
+};
+
+// Things we do here to save some bytes but are not proper JS inheritance:
+// - call `new Component()` as the prototype
+// - do not set `Suspense.prototype.constructor` to `Suspense`
+SuspenseList.prototype = new Component();
+
+SuspenseList.prototype._suspended = function(child) {
+ const list = this;
+ const delegated = suspended(list._vnode);
+
+ let node = list._map.get(child);
+ node[SUSPENDED_COUNT]++;
+
+ return unsuspend => {
+ const wrappedUnsuspend = () => {
+ if (!list.props.revealOrder) {
+ // Special case the undefined (falsy) revealOrder, as there
+ // is no need to coordinate a specific order or unsuspends.
+ unsuspend();
+ } else {
+ node.push(unsuspend);
+ resolve(list, child, node);
+ }
+ };
+ if (delegated) {
+ delegated(wrappedUnsuspend);
+ } else {
+ wrappedUnsuspend();
+ }
+ };
+};
+
+SuspenseList.prototype.render = function(props) {
+ this._next = null;
+ this._map = new Map();
+
+ const children = toChildArray(props.children);
+ if (props.revealOrder && props.revealOrder[0] === 'b') {
+ // If order === 'backwards' (or, well, anything starting with a 'b')
+ // then flip the child list around so that the last child will be
+ // the first in the linked list.
+ children.reverse();
+ }
+ // Build the linked list. Iterate through the children in reverse order
+ // so that `_next` points to the first linked list node to be resolved.
+ for (let i = children.length; i--; ) {
+ // Create a new linked list node as an array of form:
+ // [suspended_count, resolved_count, next_node]
+ // where suspended_count and resolved_count are numeric counters for
+ // keeping track how many times a node has been suspended and resolved.
+ //
+ // Note that suspended_count starts from 1 instead of 0, so we can block
+ // processing callbacks until componentDidMount has been called. In a sense
+ // node is suspended at least until componentDidMount gets called!
+ //
+ // Pending callbacks are added to the end of the node:
+ // [suspended_count, resolved_count, next_node, callback_0, callback_1, ...]
+ this._map.set(children[i], (this._next = [1, 0, this._next]));
+ }
+ return props.children;
+};
+
+SuspenseList.prototype.componentDidUpdate = SuspenseList.prototype.componentDidMount = function() {
+ // Iterate through all children after mounting for two reasons:
+ // 1. As each node[SUSPENDED_COUNT] starts from 1, this iteration increases
+ // each node[RELEASED_COUNT] by 1, therefore balancing the counters.
+ // The nodes can now be completely consumed from the linked list.
+ // 2. Handle nodes that might have gotten resolved between render and
+ // componentDidMount.
+ this._map.forEach((node, child) => {
+ resolve(this, child, node);
+ });
+};
diff --git a/preact/compat/src/suspense.d.ts b/preact/compat/src/suspense.d.ts
new file mode 100644
index 0000000..9bd0e74
--- /dev/null
+++ b/preact/compat/src/suspense.d.ts
@@ -0,0 +1,15 @@
+import { Component, ComponentChild, ComponentChildren } from '../../src';
+
+//
+// Suspense/lazy
+// -----------------------------------
+export function lazy<T>(loader: () => Promise<{ default: T } | T>): T;
+
+export interface SuspenseProps {
+ children?: ComponentChildren;
+ fallback: ComponentChildren;
+}
+
+export class Suspense extends Component<SuspenseProps> {
+ render(): ComponentChild;
+}
diff --git a/preact/compat/src/suspense.js b/preact/compat/src/suspense.js
new file mode 100644
index 0000000..6244eaf
--- /dev/null
+++ b/preact/compat/src/suspense.js
@@ -0,0 +1,270 @@
+import { Component, createElement, options, Fragment } from 'preact';
+import { assign } from './util';
+
+const oldCatchError = options._catchError;
+options._catchError = function(error, newVNode, oldVNode) {
+ if (error.then) {
+ /** @type {import('./internal').Component} */
+ let component;
+ let vnode = newVNode;
+
+ for (; (vnode = vnode._parent); ) {
+ if ((component = vnode._component) && component._childDidSuspend) {
+ if (newVNode._dom == null) {
+ newVNode._dom = oldVNode._dom;
+ newVNode._children = oldVNode._children;
+ }
+ // Don't call oldCatchError if we found a Suspense
+ return component._childDidSuspend(error, newVNode);
+ }
+ }
+ }
+ oldCatchError(error, newVNode, oldVNode);
+};
+
+const oldUnmount = options.unmount;
+options.unmount = function(vnode) {
+ /** @type {import('./internal').Component} */
+ const component = vnode._component;
+ if (component && component._onResolve) {
+ component._onResolve();
+ }
+
+ // if the component is still hydrating
+ // most likely it is because the component is suspended
+ // we set the vnode.type as `null` so that it is not a typeof function
+ // so the unmount will remove the vnode._dom
+ if (component && vnode._hydrating === true) {
+ vnode.type = null;
+ }
+
+ if (oldUnmount) oldUnmount(vnode);
+};
+
+function detachedClone(vnode, detachedParent, parentDom) {
+ if (vnode) {
+ if (vnode._component && vnode._component.__hooks) {
+ vnode._component.__hooks._list.forEach(effect => {
+ if (typeof effect._cleanup == 'function') effect._cleanup();
+ });
+
+ vnode._component.__hooks = null;
+ }
+
+ vnode = assign({}, vnode);
+ if (vnode._component != null) {
+ if (vnode._component._parentDom === parentDom) {
+ vnode._component._parentDom = detachedParent;
+ }
+ vnode._component = null;
+ }
+
+ vnode._children =
+ vnode._children &&
+ vnode._children.map(child =>
+ detachedClone(child, detachedParent, parentDom)
+ );
+ }
+
+ return vnode;
+}
+
+function removeOriginal(vnode, detachedParent, originalParent) {
+ if (vnode) {
+ vnode._original = null;
+ vnode._children =
+ vnode._children &&
+ vnode._children.map(child =>
+ removeOriginal(child, detachedParent, originalParent)
+ );
+
+ if (vnode._component) {
+ if (vnode._component._parentDom === detachedParent) {
+ if (vnode._dom) {
+ originalParent.insertBefore(vnode._dom, vnode._nextDom);
+ }
+ vnode._component._force = true;
+ vnode._component._parentDom = originalParent;
+ }
+ }
+ }
+
+ return vnode;
+}
+
+// having custom inheritance instead of a class here saves a lot of bytes
+export function Suspense() {
+ // we do not call super here to golf some bytes...
+ this._pendingSuspensionCount = 0;
+ this._suspenders = null;
+ this._detachOnNextRender = null;
+}
+
+// Things we do here to save some bytes but are not proper JS inheritance:
+// - call `new Component()` as the prototype
+// - do not set `Suspense.prototype.constructor` to `Suspense`
+Suspense.prototype = new Component();
+
+/**
+ * @this {import('./internal').SuspenseComponent}
+ * @param {Promise} promise The thrown promise
+ * @param {import('./internal').VNode<any, any>} suspendingVNode The suspending component
+ */
+Suspense.prototype._childDidSuspend = function(promise, suspendingVNode) {
+ const suspendingComponent = suspendingVNode._component;
+
+ /** @type {import('./internal').SuspenseComponent} */
+ const c = this;
+
+ if (c._suspenders == null) {
+ c._suspenders = [];
+ }
+ c._suspenders.push(suspendingComponent);
+
+ const resolve = suspended(c._vnode);
+
+ let resolved = false;
+ const onResolved = () => {
+ if (resolved) return;
+
+ resolved = true;
+ suspendingComponent._onResolve = null;
+
+ if (resolve) {
+ resolve(onSuspensionComplete);
+ } else {
+ onSuspensionComplete();
+ }
+ };
+
+ suspendingComponent._onResolve = onResolved;
+
+ const onSuspensionComplete = () => {
+ if (!--c._pendingSuspensionCount) {
+ // If the suspension was during hydration we don't need to restore the
+ // suspended children into the _children array
+ if (c.state._suspended) {
+ const suspendedVNode = c.state._suspended;
+ c._vnode._children[0] = removeOriginal(
+ suspendedVNode,
+ suspendedVNode._component._parentDom,
+ suspendedVNode._component._originalParentDom
+ );
+ }
+
+ c.setState({ _suspended: (c._detachOnNextRender = null) });
+
+ let suspended;
+ while ((suspended = c._suspenders.pop())) {
+ suspended.forceUpdate();
+ }
+ }
+ };
+
+ /**
+ * We do not set `suspended: true` during hydration because we want the actual markup
+ * to remain on screen and hydrate it when the suspense actually gets resolved.
+ * While in non-hydration cases the usual fallback -> component flow would occour.
+ */
+ const wasHydrating = suspendingVNode._hydrating === true;
+ if (!c._pendingSuspensionCount++ && !wasHydrating) {
+ c.setState({ _suspended: (c._detachOnNextRender = c._vnode._children[0]) });
+ }
+ promise.then(onResolved, onResolved);
+};
+
+Suspense.prototype.componentWillUnmount = function() {
+ this._suspenders = [];
+};
+
+/**
+ * @this {import('./internal').SuspenseComponent}
+ * @param {import('./internal').SuspenseComponent["props"]} props
+ * @param {import('./internal').SuspenseState} state
+ */
+Suspense.prototype.render = function(props, state) {
+ if (this._detachOnNextRender) {
+ // When the Suspense's _vnode was created by a call to createVNode
+ // (i.e. due to a setState further up in the tree)
+ // it's _children prop is null, in this case we "forget" about the parked vnodes to detach
+ if (this._vnode._children) {
+ const detachedParent = document.createElement('div');
+ const detachedComponent = this._vnode._children[0]._component;
+ this._vnode._children[0] = detachedClone(
+ this._detachOnNextRender,
+ detachedParent,
+ (detachedComponent._originalParentDom = detachedComponent._parentDom)
+ );
+ }
+
+ this._detachOnNextRender = null;
+ }
+
+ // Wrap fallback tree in a VNode that prevents itself from being marked as aborting mid-hydration:
+ /** @type {import('./internal').VNode} */
+ const fallback =
+ state._suspended && createElement(Fragment, null, props.fallback);
+ if (fallback) fallback._hydrating = null;
+
+ return [
+ createElement(Fragment, null, state._suspended ? null : props.children),
+ fallback
+ ];
+};
+
+/**
+ * Checks and calls the parent component's _suspended method, passing in the
+ * suspended vnode. This is a way for a parent (e.g. SuspenseList) to get notified
+ * that one of its children/descendants suspended.
+ *
+ * The parent MAY return a callback. The callback will get called when the
+ * suspension resolves, notifying the parent of the fact.
+ * Moreover, the callback gets function `unsuspend` as a parameter. The resolved
+ * child descendant will not actually get unsuspended until `unsuspend` gets called.
+ * This is a way for the parent to delay unsuspending.
+ *
+ * If the parent does not return a callback then the resolved vnode
+ * gets unsuspended immediately when it resolves.
+ *
+ * @param {import('./internal').VNode} vnode
+ * @returns {((unsuspend: () => void) => void)?}
+ */
+export function suspended(vnode) {
+ /** @type {import('./internal').Component} */
+ let component = vnode._parent._component;
+ return component && component._suspended && component._suspended(vnode);
+}
+
+export function lazy(loader) {
+ let prom;
+ let component;
+ let error;
+
+ function Lazy(props) {
+ if (!prom) {
+ prom = loader();
+ prom.then(
+ exports => {
+ component = exports.default || exports;
+ },
+ e => {
+ error = e;
+ }
+ );
+ }
+
+ if (error) {
+ throw error;
+ }
+
+ if (!component) {
+ throw prom;
+ }
+
+ return createElement(component, props);
+ }
+
+ Lazy.displayName = 'Lazy';
+ Lazy._forwarded = true;
+ return Lazy;
+}
diff --git a/preact/compat/src/util.js b/preact/compat/src/util.js
new file mode 100644
index 0000000..fa12b09
--- /dev/null
+++ b/preact/compat/src/util.js
@@ -0,0 +1,28 @@
+/**
+ * Assign properties from `props` to `obj`
+ * @template O, P The obj and props types
+ * @param {O} obj The object to copy properties to
+ * @param {P} props The object to copy properties from
+ * @returns {O & P}
+ */
+export function assign(obj, props) {
+ for (let i in props) obj[i] = props[i];
+ return /** @type {O & P} */ (obj);
+}
+
+/**
+ * Check if two objects have a different shape
+ * @param {object} a
+ * @param {object} b
+ * @returns {boolean}
+ */
+export function shallowDiffers(a, b) {
+ for (let i in a) if (i !== '__source' && !(i in b)) return true;
+ for (let i in b) if (i !== '__source' && a[i] !== b[i]) return true;
+ return false;
+}
+
+export function removeNode(node) {
+ let parentNode = node.parentNode;
+ if (parentNode) parentNode.removeChild(node);
+}
diff --git a/preact/compat/test-utils.js b/preact/compat/test-utils.js
new file mode 100644
index 0000000..2dac062
--- /dev/null
+++ b/preact/compat/test-utils.js
@@ -0,0 +1 @@
+module.exports = require('preact/test-utils');
diff --git a/preact/compat/test/browser/Children.test.js b/preact/compat/test/browser/Children.test.js
new file mode 100644
index 0000000..4e0c32d
--- /dev/null
+++ b/preact/compat/test/browser/Children.test.js
@@ -0,0 +1,185 @@
+import {
+ setupScratch,
+ teardown,
+ serializeHtml
+} from '../../../test/_util/helpers';
+import { div, span } from '../../../test/_util/dom';
+import React, { createElement, Children, render } from 'preact/compat';
+
+describe('Children', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('.count', () => {
+ let count;
+ function Foo(props) {
+ count = Children.count(props.children);
+ return <div>{count}</div>;
+ }
+
+ it('should return 0 for no children', () => {
+ render(<Foo />, scratch);
+ expect(count).to.equal(0);
+ });
+
+ it('should return number of children', () => {
+ render(
+ <Foo>
+ <div />
+ foo
+ </Foo>,
+ scratch
+ );
+ expect(count).to.equal(2);
+ });
+ });
+
+ describe('.only', () => {
+ let actual;
+ function Foo(props) {
+ actual = Children.only(props.children);
+ return <div>{actual}</div>;
+ }
+
+ it('should only allow 1 child', () => {
+ render(<Foo>foo</Foo>, scratch);
+ expect(actual).to.equal('foo');
+ });
+
+ it('should throw if no children are passed', () => {
+ // eslint-disable-next-line prefer-arrow-callback
+ expect(function() {
+ render(<Foo />, scratch);
+ }).to.throw();
+ });
+
+ it('should throw if more children are passed', () => {
+ // eslint-disable-next-line prefer-arrow-callback
+ expect(function() {
+ render(
+ <Foo>
+ foo
+ <span />
+ </Foo>,
+ scratch
+ );
+ }).to.throw();
+ });
+ });
+
+ describe('.map', () => {
+ function Foo(props) {
+ let children = Children.map(props.children, child => (
+ <span>{child}</span>
+ ));
+ return <div>{children}</div>;
+ }
+
+ it('should iterate over children', () => {
+ render(
+ <Foo>
+ foo<div>bar</div>
+ </Foo>,
+ scratch
+ );
+ let expected = div([span('foo'), span(div('bar'))]);
+ expect(serializeHtml(scratch)).to.equal(expected);
+ });
+
+ it('should work with no children', () => {
+ render(<Foo />, scratch);
+ expect(serializeHtml(scratch)).to.equal('<div></div>');
+ });
+
+ it('should work with children as zero number', () => {
+ const testNumber = 0;
+
+ render(<Foo>{testNumber}</Foo>, scratch);
+ expect(serializeHtml(scratch)).to.equal('<div><span>0</span></div>');
+ });
+
+ it('should flatten result', () => {
+ const ProblemChild = ({ children }) => {
+ return React.Children.map(children, child => {
+ return React.Children.map(child.props.children, x => x);
+ }).filter(React.isValidElement);
+ };
+
+ const App = () => {
+ return (
+ <ProblemChild>
+ <div>
+ <div>1</div>
+ <div>2</div>
+ </div>
+ </ProblemChild>
+ );
+ };
+
+ render(<App />, scratch);
+
+ expect(scratch.textContent).to.equal('12');
+ });
+
+ it('should call with indices', () => {
+ const assertion = [];
+ const ProblemChild = ({ children }) => {
+ return React.Children.map(children, (child, i) => {
+ assertion.push(i);
+ return React.Children.map(child.props.children, (x, j) => {
+ assertion.push(j);
+ return x;
+ });
+ }).filter(React.isValidElement);
+ };
+
+ const App = () => {
+ return (
+ <ProblemChild>
+ <div>
+ <div>1</div>
+ <div>2</div>
+ </div>
+ <div>
+ <div>3</div>
+ <div>4</div>
+ </div>
+ </ProblemChild>
+ );
+ };
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('1234');
+ expect(assertion.length).to.equal(6);
+ });
+ });
+
+ describe('.forEach', () => {
+ function Foo(props) {
+ let children = [];
+ Children.forEach(props.children, child =>
+ children.push(<span>{child}</span>)
+ );
+ return <div>{children}</div>;
+ }
+
+ it('should iterate over children', () => {
+ render(
+ <Foo>
+ foo<div>bar</div>
+ </Foo>,
+ scratch
+ );
+ let expected = div([span('foo'), span(div('bar'))]);
+ expect(serializeHtml(scratch)).to.equal(expected);
+ });
+ });
+});
diff --git a/preact/compat/test/browser/PureComponent.test.js b/preact/compat/test/browser/PureComponent.test.js
new file mode 100644
index 0000000..1e69307
--- /dev/null
+++ b/preact/compat/test/browser/PureComponent.test.js
@@ -0,0 +1,125 @@
+import React, { createElement } from 'preact/compat';
+import { setupRerender } from 'preact/test-utils';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('PureComponent', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should be a class', () => {
+ expect(React)
+ .to.have.property('PureComponent')
+ .that.is.a('function');
+ });
+
+ it('should pass props in constructor', () => {
+ let spy = sinon.spy();
+ class Foo extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ spy(this.props, props);
+ }
+ }
+
+ React.render(<Foo foo="bar" />, scratch);
+
+ let expected = { foo: 'bar' };
+ expect(spy).to.be.calledWithMatch(expected, expected);
+ });
+
+ it('should ignore the __source variable', () => {
+ const pureSpy = sinon.spy();
+ const appSpy = sinon.spy();
+ let set;
+ class Pure extends React.PureComponent {
+ render() {
+ pureSpy();
+ return <div>Static</div>;
+ }
+ }
+
+ const App = () => {
+ const [, setState] = React.useState(0);
+ appSpy();
+ set = setState;
+ return <Pure __source={{}} />;
+ };
+
+ React.render(<App />, scratch);
+ expect(appSpy).to.be.calledOnce;
+ expect(pureSpy).to.be.calledOnce;
+
+ set(1);
+ rerender();
+ expect(appSpy).to.be.calledTwice;
+ expect(pureSpy).to.be.calledOnce;
+ });
+
+ it('should only re-render when props or state change', () => {
+ class C extends React.PureComponent {
+ render() {
+ return <div />;
+ }
+ }
+ let spy = sinon.spy(C.prototype, 'render');
+
+ let inst = React.render(<C />, scratch);
+ expect(spy).to.have.been.calledOnce;
+ spy.resetHistory();
+
+ inst = React.render(<C />, scratch);
+ expect(spy).not.to.have.been.called;
+
+ let b = { foo: 'bar' };
+ inst = React.render(<C a="a" b={b} />, scratch);
+ expect(spy).to.have.been.calledOnce;
+ spy.resetHistory();
+
+ inst = React.render(<C a="a" b={b} />, scratch);
+ expect(spy).not.to.have.been.called;
+
+ inst.setState({});
+ rerender();
+ expect(spy).not.to.have.been.called;
+
+ inst.setState({ a: 'a', b });
+ rerender();
+ expect(spy).to.have.been.calledOnce;
+ spy.resetHistory();
+
+ inst.setState({ a: 'a', b });
+ rerender();
+ expect(spy).not.to.have.been.called;
+ });
+
+ it('should update when props are removed', () => {
+ let spy = sinon.spy();
+ class App extends React.PureComponent {
+ render() {
+ spy();
+ return <div>foo</div>;
+ }
+ }
+
+ React.render(<App a="foo" />, scratch);
+ React.render(<App />, scratch);
+ expect(spy).to.be.calledTwice;
+ });
+
+ it('should have "isPureReactComponent" property', () => {
+ let Pure = new React.PureComponent();
+ expect(Pure.isReactComponent).to.deep.equal({});
+ });
+});
diff --git a/preact/compat/test/browser/cloneElement.test.js b/preact/compat/test/browser/cloneElement.test.js
new file mode 100644
index 0000000..460ef77
--- /dev/null
+++ b/preact/compat/test/browser/cloneElement.test.js
@@ -0,0 +1,96 @@
+import { createElement as preactH } from 'preact';
+import React, { createElement, render, cloneElement } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('compat cloneElement', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should clone elements', () => {
+ let element = (
+ <foo a="b" c="d">
+ a<span>b</span>
+ </foo>
+ );
+ const clone = cloneElement(element);
+ delete clone._original;
+ delete element._original;
+ expect(clone).to.eql(element);
+ });
+
+ it('should support props.children', () => {
+ let element = <foo children={<span>b</span>} />;
+ let clone = cloneElement(element);
+ delete clone._original;
+ delete element._original;
+ expect(clone).to.eql(element);
+ expect(cloneElement(clone).props.children).to.eql(element.props.children);
+ });
+
+ it('children take precedence over props.children', () => {
+ let element = (
+ <foo children={<span>c</span>}>
+ <div>b</div>
+ </foo>
+ );
+ let clone = cloneElement(element);
+ delete clone._original;
+ delete element._original;
+ expect(clone).to.eql(element);
+ expect(clone.props.children.type).to.eql('div');
+ });
+
+ it('should support children in prop argument', () => {
+ let element = <foo />;
+ let children = [<span>b</span>];
+ let clone = cloneElement(element, { children });
+ expect(clone.props.children).to.eql(children);
+ });
+
+ it('single child argument takes precedence over props.children', () => {
+ let element = <foo />;
+ let childrenA = [<span>b</span>];
+ let childrenB = [<div>c</div>];
+ let clone = cloneElement(element, { children: childrenA }, ...childrenB);
+ expect(clone.props.children).to.eql(childrenB[0]);
+ });
+
+ it('multiple children arguments take precedence over props.children', () => {
+ let element = <foo />;
+ let childrenA = [<span>b</span>];
+ let childrenB = [<div>c</div>, 'd'];
+ let clone = cloneElement(element, { children: childrenA }, ...childrenB);
+ expect(clone.props.children).to.eql(childrenB);
+ });
+
+ it('children argument takes precedence over props.children even if falsey', () => {
+ let element = <foo />;
+ let childrenA = [<span>b</span>];
+ let clone = cloneElement(element, { children: childrenA }, undefined);
+ expect(clone.children).to.eql(undefined);
+ });
+
+ it('should skip cloning on invalid element', () => {
+ let element = { foo: 42 };
+ let clone = cloneElement(element);
+ expect(clone).to.eql(element);
+ });
+
+ it('should work with jsx constructor from core', () => {
+ function Foo(props) {
+ return <div>{props.value}</div>;
+ }
+
+ let clone = cloneElement(preactH(Foo), { value: 'foo' });
+ render(clone, scratch);
+ expect(scratch.textContent).to.equal('foo');
+ });
+});
diff --git a/preact/compat/test/browser/compat.options.test.js b/preact/compat/test/browser/compat.options.test.js
new file mode 100644
index 0000000..6c52278
--- /dev/null
+++ b/preact/compat/test/browser/compat.options.test.js
@@ -0,0 +1,85 @@
+import { vnodeSpy, eventSpy } from '../../../test/_util/optionSpies';
+import React, {
+ createElement,
+ render,
+ Component,
+ createRef
+} from 'preact/compat';
+import { setupRerender } from 'preact/test-utils';
+import {
+ setupScratch,
+ teardown,
+ createEvent
+} from '../../../test/_util/helpers';
+
+describe('compat options', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ /** @type {() => void} */
+ let increment;
+
+ /** @type {import('../../src/index').PropRef<HTMLButtonElement | null>} */
+ let buttonRef;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ vnodeSpy.resetHistory();
+ eventSpy.resetHistory();
+
+ buttonRef = createRef();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ class ClassApp extends Component {
+ constructor() {
+ super();
+ this.state = { count: 0 };
+ increment = () =>
+ this.setState(({ count }) => ({
+ count: count + 1
+ }));
+ }
+
+ render() {
+ return (
+ <button ref={buttonRef} onClick={increment}>
+ {this.state.count}
+ </button>
+ );
+ }
+ }
+
+ it('should call old options on mount', () => {
+ render(<ClassApp />, scratch);
+
+ expect(vnodeSpy).to.have.been.called;
+ });
+
+ it('should call old options on event and update', () => {
+ render(<ClassApp />, scratch);
+ expect(scratch.innerHTML).to.equal('<button>0</button>');
+
+ buttonRef.current.dispatchEvent(createEvent('click'));
+ rerender();
+ expect(scratch.innerHTML).to.equal('<button>1</button>');
+
+ expect(vnodeSpy).to.have.been.called;
+ expect(eventSpy).to.have.been.called;
+ });
+
+ it('should call old options on unmount', () => {
+ render(<ClassApp />, scratch);
+ render(null, scratch);
+
+ expect(vnodeSpy).to.have.been.called;
+ });
+});
diff --git a/preact/compat/test/browser/component.test.js b/preact/compat/test/browser/component.test.js
new file mode 100644
index 0000000..de78a1f
--- /dev/null
+++ b/preact/compat/test/browser/component.test.js
@@ -0,0 +1,243 @@
+import { setupRerender } from 'preact/test-utils';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import React, { createElement } from 'preact/compat';
+
+describe('components', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should have "isReactComponent" property', () => {
+ let Comp = new React.Component();
+ expect(Comp.isReactComponent).to.deep.equal({});
+ });
+
+ it('should be sane', () => {
+ let props;
+
+ class Demo extends React.Component {
+ render() {
+ props = this.props;
+ return <div id="demo">{this.props.children}</div>;
+ }
+ }
+
+ React.render(
+ <Demo a="b" c="d">
+ inner
+ </Demo>,
+ scratch
+ );
+
+ expect(props).to.exist.and.deep.equal({
+ a: 'b',
+ c: 'd',
+ children: 'inner'
+ });
+
+ expect(scratch.innerHTML).to.equal('<div id="demo">inner</div>');
+ });
+
+ it('should single out children before componentWillReceiveProps', () => {
+ let props;
+
+ class Child extends React.Component {
+ componentWillReceiveProps(newProps) {
+ props = newProps;
+ }
+ render() {
+ return this.props.children;
+ }
+ }
+
+ class Parent extends React.Component {
+ render() {
+ return <Child>second</Child>;
+ }
+ }
+
+ let a = React.render(<Parent />, scratch);
+ a.forceUpdate();
+ rerender();
+
+ expect(props).to.exist.and.deep.equal({
+ children: 'second'
+ });
+ });
+
+ describe('UNSAFE_* lifecycle methods', () => {
+ it('should support UNSAFE_componentWillMount', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillMount() {
+ spy();
+ }
+
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ React.render(<Foo />, scratch);
+
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support UNSAFE_componentWillMount #2', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ Object.defineProperty(Foo.prototype, 'UNSAFE_componentWillMount', {
+ value: spy
+ });
+
+ React.render(<Foo />, scratch);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support UNSAFE_componentWillReceiveProps', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillReceiveProps() {
+ spy();
+ }
+
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ React.render(<Foo />, scratch);
+ // Trigger an update
+ React.render(<Foo />, scratch);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support UNSAFE_componentWillReceiveProps #2', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ Object.defineProperty(Foo.prototype, 'UNSAFE_componentWillReceiveProps', {
+ value: spy
+ });
+
+ React.render(<Foo />, scratch);
+ // Trigger an update
+ React.render(<Foo />, scratch);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support UNSAFE_componentWillUpdate', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillUpdate() {
+ spy();
+ }
+
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ React.render(<Foo />, scratch);
+ // Trigger an update
+ React.render(<Foo />, scratch);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support UNSAFE_componentWillUpdate #2', () => {
+ let spy = sinon.spy();
+
+ class Foo extends React.Component {
+ render() {
+ return <h1>foo</h1>;
+ }
+ }
+
+ Object.defineProperty(Foo.prototype, 'UNSAFE_componentWillUpdate', {
+ value: spy
+ });
+
+ React.render(<Foo />, scratch);
+ // Trigger an update
+ React.render(<Foo />, scratch);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should alias UNSAFE_* method to non-prefixed variant', () => {
+ let inst;
+ class Foo extends React.Component {
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillMount() {}
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillReceiveProps() {}
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillUpdate() {}
+ render() {
+ inst = this;
+ return <div>foo</div>;
+ }
+ }
+
+ React.render(<Foo />, scratch);
+
+ expect(inst.UNSAFE_componentWillMount).to.equal(inst.componentWillMount);
+ expect(inst.UNSAFE_componentWillReceiveProps).to.equal(
+ inst.UNSAFE_componentWillReceiveProps
+ );
+ expect(inst.UNSAFE_componentWillUpdate).to.equal(
+ inst.UNSAFE_componentWillUpdate
+ );
+ });
+
+ it('should call UNSAFE_* methods through Suspense with wrapper component #2525', () => {
+ class Page extends React.Component {
+ UNSAFE_componentWillMount() {}
+ render() {
+ return <h1>Example</h1>;
+ }
+ }
+
+ const Wrapper = () => <Page />;
+
+ sinon.spy(Page.prototype, 'UNSAFE_componentWillMount');
+
+ React.render(
+ <React.Suspense fallback={<div>fallback</div>}>
+ <Wrapper />
+ </React.Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<h1>Example</h1>');
+ expect(Page.prototype.UNSAFE_componentWillMount).to.have.been.called;
+ });
+ });
+});
diff --git a/preact/compat/test/browser/createElement.test.js b/preact/compat/test/browser/createElement.test.js
new file mode 100644
index 0000000..8a39b3f
--- /dev/null
+++ b/preact/compat/test/browser/createElement.test.js
@@ -0,0 +1,49 @@
+import React, { createElement, render } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { getSymbol } from './testUtils';
+
+describe('compat createElement()', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should normalize vnodes', () => {
+ let vnode = (
+ <div a="b">
+ <a>t</a>
+ </div>
+ );
+
+ const $$typeof = getSymbol('react.element', 0xeac7);
+ expect(vnode).to.have.property('$$typeof', $$typeof);
+ expect(vnode).to.have.property('type', 'div');
+ expect(vnode)
+ .to.have.property('props')
+ .that.is.an('object');
+ expect(vnode.props).to.have.property('children');
+ expect(vnode.props.children).to.have.property('$$typeof', $$typeof);
+ expect(vnode.props.children).to.have.property('type', 'a');
+ expect(vnode.props.children)
+ .to.have.property('props')
+ .that.is.an('object');
+ expect(vnode.props.children.props).to.eql({ children: 't' });
+ });
+
+ it('should not normalize text nodes', () => {
+ String.prototype.capFLetter = function() {
+ return this.charAt(0).toUpperCase() + this.slice(1);
+ };
+ let vnode = <div>hi buddy</div>;
+
+ render(vnode, scratch);
+
+ expect(scratch.innerHTML).to.equal('<div>hi buddy</div>');
+ });
+});
diff --git a/preact/compat/test/browser/createFactory.test.js b/preact/compat/test/browser/createFactory.test.js
new file mode 100644
index 0000000..8d4f929
--- /dev/null
+++ b/preact/compat/test/browser/createFactory.test.js
@@ -0,0 +1,26 @@
+import React, { render, createElement, createFactory } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('createFactory', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should create a DOM element', () => {
+ render(createFactory('span')({ class: 'foo' }, '1'), scratch);
+ expect(scratch.innerHTML).to.equal('<span class="foo">1</span>');
+ });
+
+ it('should create a component', () => {
+ const Foo = ({ id, children }) => <div id={id}>foo {children}</div>;
+ render(createFactory(Foo)({ id: 'value' }, 'bar'), scratch);
+ expect(scratch.innerHTML).to.equal('<div id="value">foo bar</div>');
+ });
+});
diff --git a/preact/compat/test/browser/events.test.js b/preact/compat/test/browser/events.test.js
new file mode 100644
index 0000000..40e4ccc
--- /dev/null
+++ b/preact/compat/test/browser/events.test.js
@@ -0,0 +1,278 @@
+import { render } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ createEvent
+} from '../../../test/_util/helpers';
+
+import React, { createElement } from 'preact/compat';
+
+describe('preact/compat events', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+ let proto;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+
+ proto = Element.prototype;
+ sinon.spy(proto, 'addEventListener');
+ sinon.spy(proto, 'removeEventListener');
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+
+ proto.addEventListener.restore();
+ proto.removeEventListener.restore();
+ });
+
+ it('should patch events', () => {
+ let spy = sinon.spy(event => {
+ // Calling ev.preventDefault() outside of an event handler
+ // does nothing in IE11. So we move these asserts inside
+ // the event handler. We ensure that it's called once
+ // in another assertion
+ expect(event.isDefaultPrevented()).to.be.false;
+ event.preventDefault();
+ expect(event.isDefaultPrevented()).to.be.true;
+
+ expect(event.isPropagationStopped()).to.be.false;
+ event.stopPropagation();
+ expect(event.isPropagationStopped()).to.be.true;
+ });
+
+ render(<div onClick={spy} />, scratch);
+ scratch.firstChild.click();
+
+ expect(spy).to.be.calledOnce;
+ const event = spy.args[0][0];
+ expect(event).to.haveOwnProperty('persist');
+ expect(event).to.haveOwnProperty('nativeEvent');
+ expect(event).to.haveOwnProperty('isDefaultPrevented');
+ expect(event).to.haveOwnProperty('isPropagationStopped');
+ expect(typeof event.persist).to.equal('function');
+ expect(typeof event.isDefaultPrevented).to.equal('function');
+ expect(typeof event.isPropagationStopped).to.equal('function');
+
+ expect(() => event.persist()).to.not.throw();
+ expect(() => event.isDefaultPrevented()).to.not.throw();
+ expect(() => event.isPropagationStopped()).to.not.throw();
+ });
+
+ it('should normalize ondoubleclick event', () => {
+ let vnode = <div onDoubleClick={() => null} />;
+ expect(vnode.props).to.haveOwnProperty('ondblclick');
+ });
+
+ it('should normalize onChange for textarea', () => {
+ let vnode = <textarea onChange={() => null} />;
+ expect(vnode.props).to.haveOwnProperty('oninput');
+ expect(vnode.props).to.not.haveOwnProperty('onchange');
+
+ vnode = <textarea oninput={() => null} onChange={() => null} />;
+ expect(vnode.props).to.haveOwnProperty('oninput');
+ expect(vnode.props).to.not.haveOwnProperty('onchange');
+ });
+
+ it('should normalize onChange for range, except in IE11', () => {
+ // NOTE: we don't normalize `onchange` for range inputs in IE11.
+ const eventType = /Trident\//.test(navigator.userAgent)
+ ? 'change'
+ : 'input';
+
+ render(<input type="range" onChange={() => null} />, scratch);
+ expect(proto.addEventListener).to.have.been.calledOnce;
+ expect(proto.addEventListener).to.have.been.calledWithExactly(
+ eventType,
+ sinon.match.func,
+ false
+ );
+ });
+
+ it('should normalize onChange for range, except in IE11, including when IE11 has Symbol polyfill', () => {
+ // NOTE: we don't normalize `onchange` for range inputs in IE11.
+ // This test mimics a specific scenario when a Symbol polyfill may
+ // be present, in which case onChange should still not be normalized
+
+ const isIE11 = /Trident\//.test(navigator.userAgent);
+ const eventType = isIE11 ? 'change' : 'input';
+
+ if (isIE11) {
+ window.Symbol = () => 'mockSymbolPolyfill';
+ }
+ sinon.spy(window, 'Symbol');
+
+ render(<input type="range" onChange={() => null} />, scratch);
+ expect(window.Symbol).to.have.been.calledOnce;
+ expect(proto.addEventListener).to.have.been.calledOnce;
+ expect(proto.addEventListener).to.have.been.calledWithExactly(
+ eventType,
+ sinon.match.func,
+ false
+ );
+
+ window.Symbol.restore();
+ if (isIE11) {
+ window.Symbol = undefined;
+ }
+ });
+
+ it('should support onAnimationEnd', () => {
+ const func = sinon.spy(() => {});
+ render(<div onAnimationEnd={func} />, scratch);
+
+ expect(
+ proto.addEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'animationend',
+ sinon.match.func,
+ false
+ );
+
+ scratch.firstChild.dispatchEvent(createEvent('animationend'));
+ expect(func).to.have.been.calledOnce;
+
+ render(<div />, scratch);
+ expect(
+ proto.removeEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'animationend',
+ sinon.match.func,
+ false
+ );
+ });
+
+ it('should support onTouch* events', () => {
+ const onTouchStart = sinon.spy();
+ const onTouchEnd = sinon.spy();
+ const onTouchMove = sinon.spy();
+ const onTouchCancel = sinon.spy();
+
+ render(
+ <div
+ onTouchStart={onTouchStart}
+ onTouchEnd={onTouchEnd}
+ onTouchMove={onTouchMove}
+ onTouchCancel={onTouchCancel}
+ />,
+ scratch
+ );
+
+ expect(proto.addEventListener.args.length).to.eql(4);
+ expect(proto.addEventListener.args[0].length).to.eql(3);
+ expect(proto.addEventListener.args[0][0]).to.eql('touchstart');
+ expect(proto.addEventListener.args[0][2]).to.eql(false);
+ expect(proto.addEventListener.args[1].length).to.eql(3);
+ expect(proto.addEventListener.args[1][0]).to.eql('touchend');
+ expect(proto.addEventListener.args[1][2]).to.eql(false);
+ expect(proto.addEventListener.args[2].length).to.eql(3);
+ expect(proto.addEventListener.args[2][0]).to.eql('touchmove');
+ expect(proto.addEventListener.args[2][2]).to.eql(false);
+ expect(proto.addEventListener.args[3].length).to.eql(3);
+ expect(proto.addEventListener.args[3][0]).to.eql('touchcancel');
+ expect(proto.addEventListener.args[3][2]).to.eql(false);
+
+ scratch.firstChild.dispatchEvent(createEvent('touchstart'));
+ expect(onTouchStart).to.have.been.calledOnce;
+
+ scratch.firstChild.dispatchEvent(createEvent('touchmove'));
+ expect(onTouchMove).to.have.been.calledOnce;
+
+ scratch.firstChild.dispatchEvent(createEvent('touchend'));
+ expect(onTouchEnd).to.have.been.calledOnce;
+
+ scratch.firstChild.dispatchEvent(createEvent('touchcancel'));
+ expect(onTouchCancel).to.have.been.calledOnce;
+
+ render(<div />, scratch);
+
+ expect(proto.removeEventListener.args.length).to.eql(4);
+ expect(proto.removeEventListener.args[0].length).to.eql(3);
+ expect(proto.removeEventListener.args[0][0]).to.eql('touchstart');
+ expect(proto.removeEventListener.args[0][2]).to.eql(false);
+ expect(proto.removeEventListener.args[1].length).to.eql(3);
+ expect(proto.removeEventListener.args[1][0]).to.eql('touchend');
+ expect(proto.removeEventListener.args[1][2]).to.eql(false);
+ expect(proto.removeEventListener.args[2].length).to.eql(3);
+ expect(proto.removeEventListener.args[2][0]).to.eql('touchmove');
+ expect(proto.removeEventListener.args[2][2]).to.eql(false);
+ expect(proto.removeEventListener.args[3].length).to.eql(3);
+ expect(proto.removeEventListener.args[3][0]).to.eql('touchcancel');
+ expect(proto.removeEventListener.args[3][2]).to.eql(false);
+ });
+
+ it('should support onTransitionEnd', () => {
+ const func = sinon.spy(() => {});
+ render(<div onTransitionEnd={func} />, scratch);
+
+ expect(
+ proto.addEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'transitionend',
+ sinon.match.func,
+ false
+ );
+
+ scratch.firstChild.dispatchEvent(createEvent('transitionend'));
+ expect(func).to.have.been.calledOnce;
+
+ render(<div />, scratch);
+ expect(
+ proto.removeEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'transitionend',
+ sinon.match.func,
+ false
+ );
+ });
+
+ it('should normalize onChange', () => {
+ let props = { onChange() {} };
+
+ function expectToBeNormalized(vnode, desc) {
+ expect(vnode, desc)
+ .to.have.property('props')
+ .with.all.keys(['oninput'].concat(vnode.props.type ? 'type' : []))
+ .and.property('oninput')
+ .that.is.a('function');
+ }
+
+ function expectToBeUnmodified(vnode, desc) {
+ expect(vnode, desc)
+ .to.have.property('props')
+ .eql({
+ ...props,
+ ...(vnode.props.type ? { type: vnode.props.type } : {})
+ });
+ }
+
+ expectToBeUnmodified(<div {...props} />, '<div>');
+ expectToBeUnmodified(
+ <input {...props} type="radio" />,
+ '<input type="radio">'
+ );
+ expectToBeUnmodified(
+ <input {...props} type="checkbox" />,
+ '<input type="checkbox">'
+ );
+ expectToBeUnmodified(
+ <input {...props} type="file" />,
+ '<input type="file">'
+ );
+
+ expectToBeNormalized(<textarea {...props} />, '<textarea>');
+ expectToBeNormalized(<input {...props} />, '<input>');
+ expectToBeNormalized(
+ <input {...props} type="text" />,
+ '<input type="text">'
+ );
+ });
+
+ it('should normalize beforeinput event listener', () => {
+ let spy = sinon.spy();
+ render(<input onBeforeInput={spy} />, scratch);
+ scratch.firstChild.dispatchEvent(createEvent('beforeinput'));
+ expect(spy).to.be.calledOnce;
+ });
+});
diff --git a/preact/compat/test/browser/exports.test.js b/preact/compat/test/browser/exports.test.js
new file mode 100644
index 0000000..f4a3f26
--- /dev/null
+++ b/preact/compat/test/browser/exports.test.js
@@ -0,0 +1,85 @@
+import Compat from 'preact/compat';
+// eslint-disable-next-line no-duplicate-imports
+import * as Named from 'preact/compat';
+
+describe('compat exports', () => {
+ it('should have a default export', () => {
+ expect(Compat.createElement).to.be.a('function');
+ expect(Compat.Component).to.be.a('function');
+ expect(Compat.Fragment).to.exist;
+ expect(Compat.render).to.be.a('function');
+ expect(Compat.hydrate).to.be.a('function');
+ expect(Compat.cloneElement).to.be.a('function');
+ expect(Compat.createContext).to.be.a('function');
+ expect(Compat.createRef).to.be.a('function');
+
+ // Hooks
+ expect(Compat.useState).to.be.a('function');
+ expect(Compat.useReducer).to.be.a('function');
+ expect(Compat.useEffect).to.be.a('function');
+ expect(Compat.useLayoutEffect).to.be.a('function');
+ expect(Compat.useRef).to.be.a('function');
+ expect(Compat.useMemo).to.be.a('function');
+ expect(Compat.useCallback).to.be.a('function');
+ expect(Compat.useContext).to.be.a('function');
+
+ // Suspense
+ expect(Compat.Suspense).to.be.a('function');
+ expect(Compat.lazy).to.be.a('function');
+
+ // Compat specific
+ expect(Compat.PureComponent).to.exist.and.be.a('function');
+ expect(Compat.createPortal).to.exist.and.be.a('function');
+ expect(Compat.createFactory).to.exist.and.be.a('function');
+ expect(Compat.isValidElement).to.exist.and.be.a('function');
+ expect(Compat.findDOMNode).to.exist.and.be.a('function');
+ expect(Compat.Children.map).to.exist.and.be.a('function');
+ expect(Compat.Children.forEach).to.exist.and.be.a('function');
+ expect(Compat.Children.count).to.exist.and.be.a('function');
+ expect(Compat.Children.toArray).to.exist.and.be.a('function');
+ expect(Compat.Children.only).to.exist.and.be.a('function');
+ expect(Compat.unmountComponentAtNode).to.exist.and.be.a('function');
+ expect(Compat.unstable_batchedUpdates).to.exist.and.be.a('function');
+ expect(Compat.version).to.exist.and.be.a('string');
+ });
+
+ it('should have named exports', () => {
+ expect(Named.createElement).to.be.a('function');
+ expect(Named.Component).to.be.a('function');
+ expect(Named.Fragment).to.exist;
+ expect(Named.render).to.be.a('function');
+ expect(Named.hydrate).to.be.a('function');
+ expect(Named.cloneElement).to.be.a('function');
+ expect(Named.createContext).to.be.a('function');
+ expect(Named.createRef).to.be.a('function');
+
+ // Hooks
+ expect(Named.useState).to.be.a('function');
+ expect(Named.useReducer).to.be.a('function');
+ expect(Named.useEffect).to.be.a('function');
+ expect(Named.useLayoutEffect).to.be.a('function');
+ expect(Named.useRef).to.be.a('function');
+ expect(Named.useMemo).to.be.a('function');
+ expect(Named.useCallback).to.be.a('function');
+ expect(Named.useContext).to.be.a('function');
+
+ // Suspense
+ expect(Named.Suspense).to.be.a('function');
+ expect(Named.lazy).to.be.a('function');
+
+ // Compat specific
+ expect(Named.PureComponent).to.exist.and.be.a('function');
+ expect(Named.createPortal).to.exist.and.be.a('function');
+ expect(Named.createFactory).to.exist.and.be.a('function');
+ expect(Named.isValidElement).to.exist.and.be.a('function');
+ expect(Named.findDOMNode).to.exist.and.be.a('function');
+ expect(Named.Children.map).to.exist.and.be.a('function');
+ expect(Named.Children.forEach).to.exist.and.be.a('function');
+ expect(Named.Children.count).to.exist.and.be.a('function');
+ expect(Named.Children.toArray).to.exist.and.be.a('function');
+ expect(Named.Children.only).to.exist.and.be.a('function');
+ expect(Named.unmountComponentAtNode).to.exist.and.be.a('function');
+ expect(Named.unstable_batchedUpdates).to.exist.and.be.a('function');
+ expect(Named.version).to.exist.and.be.a('string');
+ });
+});
diff --git a/preact/compat/test/browser/findDOMNode.test.js b/preact/compat/test/browser/findDOMNode.test.js
new file mode 100644
index 0000000..0812ed9
--- /dev/null
+++ b/preact/compat/test/browser/findDOMNode.test.js
@@ -0,0 +1,51 @@
+import React, { createElement, findDOMNode } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('findDOMNode()', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ class Helper extends React.Component {
+ render({ something }) {
+ if (something == null) return null;
+ if (something === false) return null;
+ return <div />;
+ }
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it.skip('should return DOM Node if render is not false nor null', () => {
+ const helper = React.render(<Helper />, scratch);
+ expect(findDOMNode(helper)).to.be.instanceof(Node);
+ });
+
+ it('should return null if given null', () => {
+ expect(findDOMNode(null)).to.be.null;
+ });
+
+ it('should return a regular DOM Element if given a regular DOM Element', () => {
+ let scratch = document.createElement('div');
+ expect(findDOMNode(scratch)).to.equalNode(scratch);
+ });
+
+ // NOTE: React.render() returning false or null has the component pointing
+ // to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
+ it('should return null if render returns false', () => {
+ const helper = React.render(<Helper something={false} />, scratch);
+ expect(findDOMNode(helper)).to.be.null;
+ });
+
+ // NOTE: React.render() returning false or null has the component pointing
+ // to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
+ it('should return null if render returns null', () => {
+ const helper = React.render(<Helper something={null} />, scratch);
+ expect(findDOMNode(helper)).to.be.null;
+ });
+});
diff --git a/preact/compat/test/browser/forwardRef.test.js b/preact/compat/test/browser/forwardRef.test.js
new file mode 100644
index 0000000..68f9219
--- /dev/null
+++ b/preact/compat/test/browser/forwardRef.test.js
@@ -0,0 +1,460 @@
+import React, {
+ createElement,
+ render,
+ createRef,
+ forwardRef,
+ hydrate,
+ memo,
+ useState,
+ useRef,
+ useImperativeHandle,
+ createPortal
+} from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { setupRerender, act } from 'preact/test-utils';
+import { getSymbol } from './testUtils';
+
+/* eslint-disable react/jsx-boolean-value, react/display-name, prefer-arrow-callback */
+
+describe('forwardRef', () => {
+ /** @type {HTMLDivElement} */
+ let scratch, rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should have isReactComponent flag', () => {
+ let App = forwardRef((_, ref) => <div ref={ref}>foo</div>);
+ expect(App.prototype.isReactComponent).to.equal(true);
+ });
+
+ it('should have $$typeof property', () => {
+ let App = forwardRef((_, ref) => <div ref={ref}>foo</div>);
+ const expected = getSymbol('react.forward_ref', 0xf47);
+ expect(App.$$typeof).to.equal(expected);
+ });
+
+ it('should pass ref with createRef', () => {
+ let App = forwardRef((_, ref) => <div ref={ref}>foo</div>);
+ let ref = createRef();
+ render(<App ref={ref} />, scratch);
+
+ expect(ref.current).to.equalNode(scratch.firstChild);
+ });
+
+ it('should share the same ref reference', () => {
+ let passedRef;
+ let App = forwardRef((_, ref) => {
+ passedRef = ref;
+ return <div ref={ref}>foo</div>;
+ });
+
+ let ref = createRef();
+ render(<App ref={ref} />, scratch);
+
+ expect(ref).to.equal(passedRef);
+ });
+
+ it('should pass ref with a callback', () => {
+ let App = forwardRef((_, ref) => (
+ <div>
+ <span ref={ref}>foo</span>
+ </div>
+ ));
+ let ref;
+ render(<App ref={x => (ref = x)} />, scratch);
+
+ expect(ref).to.equalNode(scratch.firstChild.firstChild);
+ });
+
+ it('should forward props', () => {
+ let spy = sinon.spy();
+ let App = forwardRef(spy);
+ render(<App foo="bar" />, scratch);
+
+ expect(spy).to.be.calledWithMatch({ foo: 'bar' });
+ });
+
+ it('should support nesting', () => {
+ let passedRef;
+ let Inner = forwardRef((_, ref) => {
+ passedRef = ref;
+ return <div ref={ref}>inner</div>;
+ });
+ let App = forwardRef((_, ref) => <Inner ref={ref} />);
+
+ let ref = createRef();
+ render(<App ref={ref} />, scratch);
+
+ expect(ref).to.equal(passedRef);
+ });
+
+ it('should forward null on unmount', () => {
+ let passedRef;
+ let App = forwardRef((_, ref) => {
+ passedRef = ref;
+ return <div ref={ref}>foo</div>;
+ });
+
+ let ref = createRef();
+ render(<App ref={ref} />, scratch);
+ render(null, scratch);
+
+ expect(passedRef.current).to.equal(null);
+ });
+
+ it('should be able to render and hydrate forwardRef components', () => {
+ const Foo = ({ label, forwardedRef }) => (
+ <div ref={forwardedRef}>{label}</div>
+ );
+ const App = forwardRef((props, ref) => (
+ <Foo {...props} forwardedRef={ref} />
+ ));
+
+ const ref = createRef();
+ const markup = <App ref={ref} label="Hi" />;
+
+ const element = document.createElement('div');
+ element.innerHTML = '<div>Hi</div>';
+ expect(element.textContent).to.equal('Hi');
+ expect(ref.current == null).to.equal(true);
+
+ hydrate(markup, element);
+ expect(element.textContent).to.equal('Hi');
+ expect(ref.current.tagName).to.equal('DIV');
+ });
+
+ it('should update refs when switching between children', () => {
+ function Foo({ forwardedRef, setRefOnDiv }) {
+ return (
+ <section>
+ <div ref={setRefOnDiv ? forwardedRef : null}>First</div>
+ <span ref={setRefOnDiv ? null : forwardedRef}>Second</span>
+ </section>
+ );
+ }
+
+ const App = forwardRef((props, ref) => (
+ <Foo {...props} forwardedRef={ref} />
+ ));
+
+ const ref = createRef();
+
+ render(<App ref={ref} setRefOnDiv={true} />, scratch);
+ expect(ref.current.nodeName).to.equal('DIV');
+
+ render(<App ref={ref} setRefOnDiv={false} />, scratch);
+ expect(ref.current.nodeName).to.equal('SPAN');
+ });
+
+ it('should support rendering null', () => {
+ const App = forwardRef(() => null);
+ const ref = createRef();
+
+ render(<App ref={ref} />, scratch);
+ expect(ref.current == null).to.equal(true);
+ });
+
+ it('should support rendering null for multiple children', () => {
+ const Foo = forwardRef(() => null);
+ const ref = createRef();
+
+ render(
+ <div>
+ <div />
+ <Foo ref={ref} />
+ <div />
+ </div>,
+ scratch
+ );
+ expect(ref.current == null).to.equal(true);
+ });
+
+ it('should support useImperativeHandle', () => {
+ let setValue;
+ const Foo = forwardRef((props, ref) => {
+ const result = useState('');
+ setValue = result[1];
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ getValue: () => result[0]
+ }),
+ [result[0]]
+ );
+
+ return <input ref={ref} value={result[0]} />;
+ });
+
+ const ref = createRef();
+ render(<Foo ref={ref} />, scratch);
+
+ expect(typeof ref.current.getValue).to.equal('function');
+ expect(ref.current.getValue()).to.equal('');
+
+ setValue('x');
+ rerender();
+ expect(typeof ref.current.getValue).to.equal('function');
+ expect(ref.current.getValue()).to.equal('x');
+ });
+
+ it('should not bailout if forwardRef is not wrapped in memo', () => {
+ const Component = props => <div {...props} />;
+
+ let renderCount = 0;
+
+ const App = forwardRef((props, ref) => {
+ renderCount++;
+ return <Component {...props} forwardedRef={ref} />;
+ });
+
+ const ref = createRef();
+
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(2);
+ });
+
+ it('should bailout if forwardRef is wrapped in memo', () => {
+ const Component = props => <div ref={props.forwardedRef} />;
+
+ let renderCount = 0;
+
+ const App = memo(
+ forwardRef((props, ref) => {
+ renderCount++;
+ return <Component {...props} forwardedRef={ref} />;
+ })
+ );
+
+ const ref = createRef();
+
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ expect(ref.current.nodeName).to.equal('DIV');
+
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ const differentRef = createRef();
+
+ render(<App ref={differentRef} optional="foo" />, scratch);
+ expect(renderCount).to.equal(2);
+
+ expect(ref.current == null).to.equal(true);
+ expect(differentRef.current.nodeName).to.equal('DIV');
+
+ render(<App ref={ref} optional="bar" />, scratch);
+ expect(renderCount).to.equal(3);
+ });
+
+ it('should bailout if forwardRef is wrapped in memo using function refs', () => {
+ const Component = props => <div ref={props.forwardedRef} />;
+
+ let renderCount = 0;
+
+ const App = memo(
+ forwardRef((props, ref) => {
+ renderCount++;
+ return <Component {...props} forwardedRef={ref} />;
+ })
+ );
+
+ const ref = sinon.spy();
+
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ expect(ref).to.have.been.called;
+
+ ref.resetHistory();
+ render(<App ref={ref} optional="foo" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ const differentRef = sinon.spy();
+
+ render(<App ref={differentRef} optional="foo" />, scratch);
+ expect(renderCount).to.equal(2);
+
+ expect(ref).to.have.been.calledWith(null);
+ expect(differentRef).to.have.been.called;
+
+ differentRef.resetHistory();
+ render(<App ref={ref} optional="bar" />, scratch);
+ expect(renderCount).to.equal(3);
+ });
+
+ it('should pass ref through memo() with custom comparer function', () => {
+ const Foo = props => <div ref={props.forwardedRef} />;
+
+ let renderCount = 0;
+
+ const App = memo(
+ forwardRef((props, ref) => {
+ renderCount++;
+ return <Foo {...props} forwardedRef={ref} />;
+ }),
+ (o, p) => o.a === p.a && o.b === p.b
+ );
+
+ const ref = createRef();
+
+ render(<App ref={ref} a="0" b="0" c="1" />, scratch);
+ expect(renderCount).to.equal(1);
+
+ expect(ref.current.nodeName).to.equal('DIV');
+
+ // Changing either a or b rerenders
+ render(<App ref={ref} a="0" b="1" c="1" />, scratch);
+ expect(renderCount).to.equal(2);
+
+ // Changing c doesn't rerender
+ render(<App ref={ref} a="0" b="1" c="2" />, scratch);
+ expect(renderCount).to.equal(2);
+
+ const App2 = memo(App, (o, p) => o.a === p.a && o.c === p.c);
+
+ render(<App2 ref={ref} a="0" b="0" c="0" />, scratch);
+ expect(renderCount).to.equal(3);
+
+ // Changing just b no longer updates
+ render(<App2 ref={ref} a="0" b="1" c="0" />, scratch);
+ expect(renderCount).to.equal(3);
+
+ // Changing just a and c updates
+ render(<App2 ref={ref} a="2" b="2" c="2" />, scratch);
+ expect(renderCount).to.equal(4);
+
+ // Changing just c does not update
+ render(<App2 ref={ref} a="2" b="2" c="3" />, scratch);
+ expect(renderCount).to.equal(4);
+
+ // Changing ref still rerenders
+ const differentRef = createRef();
+
+ render(<App2 ref={differentRef} a="2" b="2" c="3" />, scratch);
+ expect(renderCount).to.equal(5);
+
+ expect(ref.current == null).to.equal(true);
+ expect(differentRef.current.nodeName).to.equal('DIV');
+ });
+
+ it('calls ref when this is a function.', () => {
+ const spy = sinon.spy();
+ const Bar = forwardRef((props, ref) => {
+ useImperativeHandle(ref, () => ({ foo: 100 }));
+ return null;
+ });
+
+ render(<Bar ref={spy} />, scratch);
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWithExactly({ foo: 100 });
+ });
+
+ it('stale ref missing with passed useRef', () => {
+ let _ref = null;
+ let _set = null;
+ const Inner = forwardRef((props, ref) => {
+ const _hook = useState(null);
+ _ref = ref;
+ _set = _hook[1];
+ return <div ref={ref} />;
+ });
+
+ const Parent = () => {
+ const parentRef = useRef(null);
+ return <Inner ref={parentRef}>child</Inner>;
+ };
+
+ act(() => {
+ render(<Parent />, scratch);
+ });
+
+ expect(_ref.current).to.equal(scratch.firstChild);
+
+ act(() => {
+ _set(1);
+ rerender();
+ });
+
+ expect(_ref.current).to.equal(scratch.firstChild);
+ });
+
+ it('should forward at diff time instead vnode-creation.', () => {
+ let ref, forceTransition, forceOpen;
+
+ const Portal = ({ children, open }) =>
+ open ? createPortal(children, scratch) : null;
+
+ const Wrapper = forwardRef((_props, ref) => <div ref={ref}>Wrapper</div>);
+ const Transition = ({ children }) => {
+ const state = useState(0);
+ forceTransition = state[1];
+ expect(children.ref).to.not.be.undefined;
+ if (state[0] === 0) expect(children.props.ref).to.be.undefined;
+ return children;
+ };
+
+ const App = () => {
+ const openState = useState(false);
+ forceOpen = openState[1];
+ ref = useRef();
+ return (
+ <Portal open={openState[0]}>
+ <Transition>
+ <Wrapper ref={ref} />
+ </Transition>
+ </Portal>
+ );
+ };
+
+ render(<App />, scratch);
+
+ act(() => {
+ forceOpen(true);
+ });
+
+ expect(ref.current.innerHTML).to.equal('Wrapper');
+
+ act(() => {
+ forceTransition(1);
+ });
+
+ expect(ref.current.innerHTML).to.equal('Wrapper');
+ });
+
+ // Issue #2566
+ it('should pass null as ref when no ref is present', () => {
+ let actual;
+ const App = forwardRef((_, ref) => {
+ actual = ref;
+ return <div />;
+ });
+
+ render(<App />, scratch);
+ expect(actual).to.equal(null);
+ });
+
+ // Issue #2599
+ it('should not crash when explicitly passing null', () => {
+ let actual;
+ const App = forwardRef((_, ref) => {
+ actual = ref;
+ return <div />;
+ });
+
+ // eslint-disable-next-line new-cap
+ render(App({}, null), scratch);
+ expect(actual).to.equal(null);
+ });
+});
diff --git a/preact/compat/test/browser/hydrate.test.js b/preact/compat/test/browser/hydrate.test.js
new file mode 100644
index 0000000..e42cdb7
--- /dev/null
+++ b/preact/compat/test/browser/hydrate.test.js
@@ -0,0 +1,34 @@
+import React, { hydrate } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('compat hydrate', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should render react-style jsx', () => {
+ const input = document.createElement('input');
+ scratch.appendChild(input);
+ input.focus();
+ expect(document.activeElement).to.equal(input);
+
+ hydrate(<input />, scratch);
+ expect(document.activeElement).to.equal(input);
+ });
+
+ it('should call the callback', () => {
+ scratch.innerHTML = '<div></div>';
+
+ let spy = sinon.spy();
+ hydrate(<div />, scratch, spy);
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWithExactly();
+ });
+});
diff --git a/preact/compat/test/browser/isValidElement.test.js b/preact/compat/test/browser/isValidElement.test.js
new file mode 100644
index 0000000..0fa34ef
--- /dev/null
+++ b/preact/compat/test/browser/isValidElement.test.js
@@ -0,0 +1,22 @@
+import { createElement as preactCreateElement } from 'preact';
+import React, { isValidElement } from 'preact/compat';
+
+describe('isValidElement', () => {
+ it('should check return false for invalid arguments', () => {
+ expect(isValidElement(null)).to.equal(false);
+ expect(isValidElement(false)).to.equal(false);
+ expect(isValidElement(true)).to.equal(false);
+ expect(isValidElement('foo')).to.equal(false);
+ expect(isValidElement(123)).to.equal(false);
+ expect(isValidElement([])).to.equal(false);
+ expect(isValidElement({})).to.equal(false);
+ });
+
+ it('should detect a preact vnode', () => {
+ expect(isValidElement(preactCreateElement('div'))).to.equal(true);
+ });
+
+ it('should detect a compat vnode', () => {
+ expect(isValidElement(React.createElement('div'))).to.equal(true);
+ });
+});
diff --git a/preact/compat/test/browser/memo.test.js b/preact/compat/test/browser/memo.test.js
new file mode 100644
index 0000000..c1e155c
--- /dev/null
+++ b/preact/compat/test/browser/memo.test.js
@@ -0,0 +1,234 @@
+import { setupRerender } from 'preact/test-utils';
+import {
+ createEvent,
+ setupScratch,
+ teardown
+} from '../../../test/_util/helpers';
+import React, {
+ createElement,
+ Component,
+ render,
+ memo,
+ useState
+} from 'preact/compat';
+import { li, ol } from '../../../test/_util/dom';
+
+const h = React.createElement;
+
+describe('memo()', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should have isReactComponent flag', () => {
+ // eslint-disable-next-line react/display-name
+ let App = memo(() => <div>foo</div>);
+ expect(App.prototype.isReactComponent).to.equal(true);
+ });
+
+ it('should work with function components', () => {
+ let spy = sinon.spy();
+
+ function Foo() {
+ spy();
+ return <h1>Hello World</h1>;
+ }
+
+ let Memoized = memo(Foo);
+
+ let update;
+ class App extends Component {
+ constructor() {
+ super();
+ update = () => this.setState({});
+ }
+ render() {
+ return <Memoized />;
+ }
+ }
+ render(<App />, scratch);
+
+ expect(spy).to.be.calledOnce;
+
+ update();
+ rerender();
+
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should support adding refs', () => {
+ let spy = sinon.spy();
+
+ let ref = null;
+
+ function Foo() {
+ spy();
+ return <h1>Hello World</h1>;
+ }
+
+ let Memoized = memo(Foo);
+
+ let update;
+ class App extends Component {
+ constructor() {
+ super();
+ update = () => this.setState({});
+ }
+ render() {
+ return <Memoized ref={ref} />;
+ }
+ }
+ render(<App />, scratch);
+
+ expect(spy).to.be.calledOnce;
+
+ ref = {};
+
+ update();
+ rerender();
+
+ expect(ref.current).not.to.be.undefined;
+
+ // TODO: not sure whether this is in-line with react...
+ expect(spy).to.be.calledTwice;
+ });
+
+ it('should support custom comparer functions', () => {
+ function Foo() {
+ return <h1>Hello World</h1>;
+ }
+
+ let spy = sinon.spy(() => true);
+ let Memoized = memo(Foo, spy);
+
+ let update;
+ class App extends Component {
+ constructor() {
+ super();
+ update = () => this.setState({});
+ }
+ render() {
+ return <Memoized />;
+ }
+ }
+ render(<App />, scratch);
+
+ update();
+ rerender();
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith({}, {});
+ });
+
+ it('should rerender when custom comparer returns false', () => {
+ const spy = sinon.spy();
+ function Foo() {
+ spy();
+ return <h1>Hello World</h1>;
+ }
+
+ const App = memo(Foo, () => false);
+ render(<App />, scratch);
+ expect(spy).to.be.calledOnce;
+
+ render(<App foo="bar" />, scratch);
+ expect(spy).to.be.calledTwice;
+ });
+
+ it('should pass props and nextProps to comparer fn', () => {
+ const spy = sinon.spy(() => false);
+ function Foo() {
+ return <div>foo</div>;
+ }
+
+ const props = { foo: true };
+ const nextProps = { foo: false };
+ const App = memo(Foo, spy);
+ render(h(App, props), scratch);
+ render(h(App, nextProps), scratch);
+
+ expect(spy).to.be.calledWith(props, nextProps);
+ });
+
+ it('should nest without errors', () => {
+ const Foo = () => <div>foo</div>;
+ const App = memo(memo(Foo));
+
+ // eslint-disable-next-line prefer-arrow-callback
+ expect(function() {
+ render(<App />, scratch);
+ }).to.not.throw();
+ });
+
+ it('should pass ref through nested memos', () => {
+ class Foo extends Component {
+ render() {
+ return <h1>Hello World</h1>;
+ }
+ }
+
+ const App = memo(memo(Foo));
+
+ const ref = {};
+
+ render(<App ref={ref} />, scratch);
+
+ expect(ref.current).not.to.be.undefined;
+ expect(ref.current).to.be.instanceOf(Foo);
+ });
+
+ it('should not unnecessarily reorder children #2895', () => {
+ const array = [{ name: 'A' }, { name: 'B' }, { name: 'C' }, { name: 'D' }];
+
+ const List = () => {
+ const [selected, setSelected] = useState('');
+ return (
+ <ol>
+ {array.map(item => (
+ <ListItem
+ {...{
+ isSelected: item.name === selected,
+ setSelected,
+ ...item
+ }}
+ key={item.name}
+ />
+ ))}
+ </ol>
+ );
+ };
+
+ const ListItem = memo(({ name, isSelected, setSelected }) => {
+ const handleClick = () => setSelected(name);
+ return (
+ <li class={isSelected ? 'selected' : null} onClick={handleClick}>
+ {name}
+ </li>
+ );
+ });
+
+ render(<List />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ `<ol><li>A</li><li>B</li><li>C</li><li>D</li></ol>`
+ );
+
+ let listItem = scratch.querySelector('li:nth-child(3)');
+ listItem.dispatchEvent(createEvent('click'));
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ `<ol><li>A</li><li>B</li><li class="selected">C</li><li>D</li></ol>`
+ );
+ });
+});
diff --git a/preact/compat/test/browser/portals.test.js b/preact/compat/test/browser/portals.test.js
new file mode 100644
index 0000000..c114657
--- /dev/null
+++ b/preact/compat/test/browser/portals.test.js
@@ -0,0 +1,627 @@
+import React, {
+ createElement,
+ render,
+ createPortal,
+ useState,
+ Component
+} from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { setupRerender, act } from 'preact/test-utils';
+
+/* eslint-disable react/jsx-boolean-value, react/display-name, prefer-arrow-callback */
+
+describe('Portal', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should render into a different root node', () => {
+ let root = document.createElement('div');
+ document.body.appendChild(root);
+
+ function Foo(props) {
+ return <div>{createPortal(props.children, root)}</div>;
+ }
+ render(<Foo>foobar</Foo>, scratch);
+
+ expect(root.innerHTML).to.equal('foobar');
+
+ root.parentNode.removeChild(root);
+ });
+
+ it('should insert the portal', () => {
+ let setFalse;
+ function Foo(props) {
+ const [mounted, setMounted] = useState(true);
+ setFalse = () => setMounted(() => false);
+ return (
+ <div>
+ <p>Hello</p>
+ {mounted && createPortal(props.children, scratch)}
+ </div>
+ );
+ }
+ render(<Foo>foobar</Foo>, scratch);
+ expect(scratch.innerHTML).to.equal('foobar<div><p>Hello</p></div>');
+
+ setFalse();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+ });
+
+ it('should toggle the portal', () => {
+ let toggle;
+
+ function Foo(props) {
+ const [mounted, setMounted] = useState(true);
+ toggle = () => setMounted(s => !s);
+ return (
+ <div>
+ <p>Hello</p>
+ {mounted && createPortal(props.children, scratch)}
+ </div>
+ );
+ }
+
+ render(
+ <Foo>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div>foobar</div><div><p>Hello</p></div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+ });
+
+ it('should notice prop changes on the portal', () => {
+ let set;
+
+ function Foo(props) {
+ const [additionalProps, setProps] = useState({
+ style: { backgroundColor: 'red' }
+ });
+ set = c => setProps(c);
+ return (
+ <div>
+ <p>Hello</p>
+ {createPortal(<p {...additionalProps}>Foo</p>, scratch)}
+ </div>
+ );
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.firstChild.style.backgroundColor).to.equal('red');
+
+ set({});
+ rerender();
+ expect(scratch.firstChild.style.backgroundColor).to.equal('');
+ });
+
+ it('should not unmount the portal component', () => {
+ let spy = sinon.spy();
+ let set;
+ class Child extends Component {
+ componentWillUnmount() {
+ spy();
+ }
+
+ render(props) {
+ return props.children;
+ }
+ }
+
+ function Foo(props) {
+ const [additionalProps, setProps] = useState({
+ style: { background: 'red' }
+ });
+ set = c => setProps(c);
+ return (
+ <div>
+ <p>Hello</p>
+ {createPortal(<Child {...additionalProps}>Foo</Child>, scratch)}
+ </div>
+ );
+ }
+
+ render(<Foo />, scratch);
+ expect(spy).not.to.be.called;
+
+ set({});
+ rerender();
+ expect(spy).not.to.be.called;
+ });
+
+ it('should not render <undefined> for Portal nodes', () => {
+ let root = document.createElement('div');
+ let dialog = document.createElement('div');
+ dialog.id = 'container';
+
+ scratch.appendChild(root);
+ scratch.appendChild(dialog);
+
+ function Dialog() {
+ return <div>Dialog content</div>;
+ }
+
+ function App() {
+ return <div>{createPortal(<Dialog />, dialog)}</div>;
+ }
+
+ render(<App />, root);
+ expect(scratch.firstChild.firstChild.childNodes.length).to.equal(0);
+ });
+
+ it('should unmount Portal', () => {
+ let root = document.createElement('div');
+ let dialog = document.createElement('div');
+ dialog.id = 'container';
+
+ scratch.appendChild(root);
+ scratch.appendChild(dialog);
+
+ function Dialog() {
+ return <div>Dialog content</div>;
+ }
+
+ function App() {
+ return <div>{createPortal(<Dialog />, dialog)}</div>;
+ }
+
+ render(<App />, root);
+ expect(dialog.childNodes.length).to.equal(1);
+ render(null, root);
+ expect(dialog.childNodes.length).to.equal(0);
+ });
+
+ it('should leave a working root after the portal', () => {
+ let toggle, toggle2;
+
+ function Foo(props) {
+ const [mounted, setMounted] = useState(false);
+ const [mounted2, setMounted2] = useState(true);
+ toggle = () => setMounted(s => !s);
+ toggle2 = () => setMounted2(s => !s);
+ return (
+ <div>
+ {mounted && createPortal(props.children, scratch)}
+ {mounted2 && <p>Hello</p>}
+ </div>
+ );
+ }
+
+ render(
+ <Foo>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div></div><div>foobar</div>');
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should work with stacking portals', () => {
+ let toggle, toggle2;
+
+ function Foo(props) {
+ const [mounted, setMounted] = useState(false);
+ const [mounted2, setMounted2] = useState(false);
+ toggle = () => setMounted(s => !s);
+ toggle2 = () => setMounted2(s => !s);
+ return (
+ <div>
+ <p>Hello</p>
+ {mounted && createPortal(props.children, scratch)}
+ {mounted2 && createPortal(props.children2, scratch)}
+ </div>
+ );
+ }
+
+ render(
+ <Foo children2={<div>foobar2</div>}>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div><div>foobar2</div>'
+ );
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+ });
+
+ it('should work with changing the container', () => {
+ let set, ref;
+
+ function Foo(props) {
+ const [container, setContainer] = useState(scratch);
+ set = setContainer;
+
+ return (
+ <div
+ ref={r => {
+ ref = r;
+ }}
+ >
+ <p>Hello</p>
+ {createPortal(props.children, container)}
+ </div>
+ );
+ }
+
+ render(
+ <Foo>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div>foobar</div><div><p>Hello</p></div>'
+ );
+
+ set(() => ref);
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p><div>foobar</div></div>'
+ );
+ });
+
+ it('should work with replacing placeholder portals', () => {
+ let toggle, toggle2;
+
+ function Foo(props) {
+ const [mounted, setMounted] = useState(false);
+ const [mounted2, setMounted2] = useState(false);
+ toggle = () => setMounted(s => !s);
+ toggle2 = () => setMounted2(s => !s);
+ return (
+ <div>
+ <p>Hello</p>
+ {createPortal(mounted && props.children, scratch)}
+ {createPortal(mounted2 && props.children, scratch)}
+ </div>
+ );
+ }
+
+ render(
+ <Foo>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div>foobar</div>'
+ );
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+ });
+
+ it('should work with removing an element from stacked container to new one', () => {
+ let toggle, root2;
+
+ function Foo(props) {
+ const [root, setRoot] = useState(scratch);
+ toggle = () => setRoot(() => root2);
+ return (
+ <div
+ ref={r => {
+ root2 = r;
+ }}
+ >
+ <p>Hello</p>
+ {createPortal(props.children, scratch)}
+ {createPortal(props.children, root)}
+ </div>
+ );
+ }
+
+ render(
+ <Foo>
+ <div>foobar</div>
+ </Foo>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div>foobar</div><div>foobar</div><div><p>Hello</p></div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div>foobar</div><div><p>Hello</p><div>foobar</div></div>'
+ );
+ });
+
+ it('should support nested portals', () => {
+ let toggle, toggle2, inner;
+
+ function Bar() {
+ const [mounted, setMounted] = useState(false);
+ toggle2 = () => setMounted(s => !s);
+ return (
+ <div
+ ref={r => {
+ inner = r;
+ }}
+ >
+ <p>Inner</p>
+ {mounted && createPortal(<p>hiFromBar</p>, scratch)}
+ {mounted && createPortal(<p>innerPortal</p>, inner)}
+ </div>
+ );
+ }
+
+ function Foo(props) {
+ const [mounted, setMounted] = useState(false);
+ toggle = () => setMounted(s => !s);
+ return (
+ <div>
+ <p>Hello</p>
+ {mounted && createPortal(<Bar />, scratch)}
+ </div>
+ );
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div><p>Inner</p></div>'
+ );
+
+ toggle2();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>Hello</p></div><div><p>Inner</p><p>innerPortal</p></div><p>hiFromBar</p>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><p>Hello</p></div>');
+ });
+
+ it('should support nested portals remounting #2669', () => {
+ let setVisible;
+ let i = 0;
+
+ function PortalComponent(props) {
+ const innerVnode = <div id="inner">{i}</div>;
+ innerVnode.___id = 'inner_' + i++;
+ const outerVnode = (
+ <div id="outer">
+ {i}
+ {props.show && createPortal(innerVnode, scratch)}
+ </div>
+ );
+ outerVnode.___id = 'outer_' + i++;
+ return createPortal(outerVnode, scratch);
+ }
+
+ function App() {
+ const [visible, _setVisible] = useState(true);
+ setVisible = _setVisible;
+
+ return (
+ <div id="app">
+ test
+ <PortalComponent show={visible} />
+ </div>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div id="inner">0</div><div id="outer">1</div><div id="app">test</div>'
+ );
+
+ act(() => {
+ setVisible(false);
+ });
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div id="outer">3</div><div id="app">test</div>'
+ );
+
+ act(() => {
+ setVisible(true);
+ });
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div id="outer">5</div><div id="app">test</div><div id="inner">4</div>'
+ );
+
+ act(() => {
+ setVisible(false);
+ });
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div id="outer">7</div><div id="app">test</div>'
+ );
+ });
+
+ it('should not unmount when parent renders', () => {
+ let root = document.createElement('div');
+ let dialog = document.createElement('div');
+ dialog.id = 'container';
+
+ scratch.appendChild(root);
+ scratch.appendChild(dialog);
+
+ let spy = sinon.spy();
+ class Child extends Component {
+ componentDidMount() {
+ spy();
+ }
+
+ render() {
+ return <div id="child">child</div>;
+ }
+ }
+
+ let spyParent = sinon.spy();
+ class App extends Component {
+ componentDidMount() {
+ spyParent();
+ }
+ render() {
+ return <div>{createPortal(<Child />, dialog)}</div>;
+ }
+ }
+
+ render(<App />, root);
+ let dom = document.getElementById('child');
+ expect(spyParent).to.be.calledOnce;
+ expect(spy).to.be.calledOnce;
+
+ // Render twice to trigger update scenario
+ render(<App />, root);
+ render(<App />, root);
+
+ let domNew = document.getElementById('child');
+ expect(dom).to.equal(domNew);
+ expect(spyParent).to.be.calledOnce;
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should switch between non portal and portal node (Modal as lastChild)', () => {
+ let toggle;
+ const Modal = ({ children, open }) =>
+ open ? createPortal(<div>{children}</div>, scratch) : <div>Closed</div>;
+
+ const App = () => {
+ const [open, setOpen] = useState(false);
+ toggle = setOpen.bind(this, x => !x);
+ return (
+ <div>
+ <button onClick={() => setOpen(!open)}>Show</button>
+ {open ? 'Open' : 'Closed'}
+ <Modal open={open}>Hello</Modal>
+ </div>
+ );
+ };
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div><button>Show</button>Closed<div>Closed</div></div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><button>Show</button>Open</div><div>Hello</div>'
+ );
+ });
+
+ it('should switch between non portal and portal node (Modal as firstChild)', () => {
+ let toggle;
+ const Modal = ({ children, open }) =>
+ open ? createPortal(<div>{children}</div>, scratch) : <div>Closed</div>;
+
+ const App = () => {
+ const [open, setOpen] = useState(false);
+ toggle = setOpen.bind(this, x => !x);
+ return (
+ <div>
+ <Modal open={open}>Hello</Modal>
+ <button onClick={() => setOpen(!open)}>Show</button>
+ {open ? 'Open' : 'Closed'}
+ </div>
+ );
+ };
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>Closed</div><button>Show</button>Closed</div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><button>Show</button>Open</div><div>Hello</div>'
+ );
+
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>Closed</div><button>Show</button>Closed</div>'
+ );
+ });
+});
diff --git a/preact/compat/test/browser/render.test.js b/preact/compat/test/browser/render.test.js
new file mode 100644
index 0000000..5d9ff5c
--- /dev/null
+++ b/preact/compat/test/browser/render.test.js
@@ -0,0 +1,454 @@
+import React, {
+ createElement,
+ render,
+ Component,
+ hydrate,
+ createContext
+} from 'preact/compat';
+import { setupRerender, act } from 'preact/test-utils';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml,
+ createEvent
+} from '../../../test/_util/helpers';
+
+describe('compat render', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ const ce = type => document.createElement(type);
+ const text = text => document.createTextNode(text);
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should render react-style jsx', () => {
+ let jsx = (
+ <div className="foo bar" data-foo="bar">
+ <span id="some_id">inner!</span>
+ {['a', 'b']}
+ </div>
+ );
+
+ expect(jsx.props).to.have.property('className', 'foo bar');
+
+ React.render(jsx, scratch);
+ expect(serializeHtml(scratch)).to.equal(
+ '<div class="foo bar" data-foo="bar"><span id="some_id">inner!</span>ab</div>'
+ );
+ });
+
+ it('should replace isomorphic content', () => {
+ let root = ce('div');
+ let initialChild = ce('div');
+ initialChild.appendChild(text('initial content'));
+ root.appendChild(initialChild);
+
+ render(<div>dynamic content</div>, root);
+ expect(root)
+ .to.have.property('textContent')
+ .that.is.a('string')
+ .that.equals('dynamic content');
+ });
+
+ it('should remove extra elements', () => {
+ let root = ce('div');
+ let inner = ce('div');
+
+ root.appendChild(inner);
+
+ let c1 = ce('div');
+ c1.appendChild(text('isomorphic content'));
+ inner.appendChild(c1);
+
+ let c2 = ce('div');
+ c2.appendChild(text('extra content'));
+ inner.appendChild(c2);
+
+ render(<div>dynamic content</div>, root);
+ expect(root)
+ .to.have.property('textContent')
+ .that.is.a('string')
+ .that.equals('dynamic content');
+ });
+
+ // Note: Replacing text nodes inside the root itself is currently unsupported.
+ // We do replace them everywhere else, though.
+ it('should remove text nodes', () => {
+ let root = ce('div');
+
+ let div = ce('div');
+ root.appendChild(div);
+ div.appendChild(text('Text Content'));
+ div.appendChild(text('More Text Content'));
+
+ render(<div>dynamic content</div>, root);
+ expect(root)
+ .to.have.property('textContent')
+ .that.is.a('string')
+ .that.equals('dynamic content');
+ });
+
+ it('should ignore maxLength / minLength when is null', () => {
+ render(<input maxLength={null} minLength={null} />, scratch);
+ expect(scratch.firstElementChild.getAttribute('maxlength')).to.equal(null);
+ expect(scratch.firstElementChild.getAttribute('minlength')).to.equal(null);
+ });
+
+ it('should support defaultValue', () => {
+ render(<input defaultValue="foo" />, scratch);
+ expect(scratch.firstElementChild).to.have.property('value', 'foo');
+ });
+
+ it('should add defaultValue when value is null/undefined', () => {
+ render(<input defaultValue="foo" value={null} />, scratch);
+ expect(scratch.firstElementChild).to.have.property('value', 'foo');
+
+ render(<input defaultValue="foo" value={undefined} />, scratch);
+ expect(scratch.firstElementChild).to.have.property('value', 'foo');
+ });
+
+ it('should support defaultValue for select tag', () => {
+ function App() {
+ return (
+ <select defaultValue="2">
+ <option value="1">Picked 1</option>
+ <option value="2">Picked 2</option>
+ <option value="3">Picked 3</option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ const options = scratch.firstChild.children;
+ expect(options[0]).to.have.property('selected', false);
+ expect(options[1]).to.have.property('selected', true);
+ });
+
+ it('should support defaultValue for select tag when using multi selection', () => {
+ function App() {
+ return (
+ <select multiple defaultValue={['1', '3']}>
+ <option value="1">Picked 1</option>
+ <option value="2">Picked 2</option>
+ <option value="3">Picked 3</option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ const options = scratch.firstChild.children;
+ expect(options[0]).to.have.property('selected', true);
+ expect(options[1]).to.have.property('selected', false);
+ expect(options[2]).to.have.property('selected', true);
+ });
+
+ it('should ignore defaultValue when value is 0', () => {
+ render(<input defaultValue={2} value={0} />, scratch);
+ expect(scratch.firstElementChild.value).to.equal('0');
+ });
+
+ it('should keep value of uncontrolled inputs using defaultValue', () => {
+ // See https://github.com/preactjs/preact/issues/2391
+
+ const spy = sinon.spy();
+
+ class Input extends Component {
+ render() {
+ return (
+ <input
+ type="text"
+ defaultValue="bar"
+ onChange={() => {
+ spy();
+ this.forceUpdate();
+ }}
+ />
+ );
+ }
+ }
+
+ render(<Input />, scratch);
+ expect(scratch.firstChild.value).to.equal('bar');
+ scratch.firstChild.focus();
+ scratch.firstChild.value = 'foo';
+
+ scratch.firstChild.dispatchEvent(createEvent('input'));
+ rerender();
+ expect(scratch.firstChild.value).to.equal('foo');
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should call the callback', () => {
+ let spy = sinon.spy();
+ render(<div />, scratch, spy);
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWithExactly();
+ });
+
+ // Issue #1727
+ it('should destroy the any existing DOM nodes inside the container', () => {
+ scratch.appendChild(document.createElement('div'));
+ scratch.appendChild(document.createElement('div'));
+
+ render(<span>foo</span>, scratch);
+ expect(scratch.innerHTML).to.equal('<span>foo</span>');
+ });
+
+ it('should only destroy existing DOM nodes on first render', () => {
+ scratch.appendChild(document.createElement('div'));
+ scratch.appendChild(document.createElement('div'));
+
+ render(<input />, scratch);
+
+ let child = scratch.firstChild;
+ child.focus();
+ render(<input />, scratch);
+ expect(document.activeElement.nodeName).to.equal('INPUT');
+ });
+
+ it('should normalize class+className even on components', () => {
+ function Foo(props) {
+ return (
+ <div class={props.class} className={props.className}>
+ foo
+ </div>
+ );
+ }
+ render(<Foo class="foo" />, scratch);
+ expect(scratch.firstChild.className).to.equal('foo');
+ render(null, scratch);
+
+ render(<Foo className="foo" />, scratch);
+ expect(scratch.firstChild.className).to.equal('foo');
+ });
+
+ it('should normalize className when it has an empty string', () => {
+ function Foo(props) {
+ expect(props.className).to.equal('');
+ return <div className="">foo</div>;
+ }
+
+ render(<Foo className="" />, scratch);
+ });
+
+ // Issue #2275
+ it('should normalize class+className + DOM properties', () => {
+ function Foo(props) {
+ return <ul class="old" {...props} />;
+ }
+
+ render(<Foo fontSize="xlarge" className="new" />, scratch);
+ expect(scratch.firstChild.className).to.equal('new');
+ });
+
+ it('should give precedence to last-applied class/className prop', () => {
+ render(<ul className="from className" class="from class" />, scratch);
+ expect(scratch.firstChild.className).to.equal('from className');
+
+ render(<ul class="from class" className="from className" />, scratch);
+ expect(scratch.firstChild.className).to.equal('from className');
+ });
+
+ describe('className normalization', () => {
+ it('should give precedence to className over class', () => {
+ const { props } = <ul className="from className" class="from class" />;
+ expect(props).to.have.property('className', 'from className');
+ expect(props).to.have.property('class', 'from className');
+ });
+
+ it('should preserve className, add class alias', () => {
+ const { props } = <ul className="from className" />;
+ expect(props).to.have.property('className', 'from className');
+ expect(props).to.have.property('class', 'from className');
+ });
+
+ it('should preserve class, and add className alias', () => {
+ const { props } = <ul class="from class" />;
+ expect(props).to.have.property('class', 'from class');
+ expect(props.propertyIsEnumerable('className')).to.equal(false);
+ expect(props).to.have.property('className', 'from class');
+ });
+
+ it('should preserve class when spreading', () => {
+ const { props } = <ul class="from class" />;
+ const spreaded = (<li a {...props} />).props;
+ expect(spreaded).to.have.property('class', 'from class');
+ expect(spreaded.propertyIsEnumerable('className')).to.equal(false);
+ expect(spreaded).to.have.property('className', 'from class');
+ });
+
+ it('should preserve className when spreading', () => {
+ const { props } = <ul className="from className" />;
+ const spreaded = (<li a {...props} />).props;
+ expect(spreaded).to.have.property('className', 'from className');
+ expect(spreaded).to.have.property('class', 'from className');
+ expect(spreaded.propertyIsEnumerable('class')).to.equal(true);
+ });
+
+ // Issue #2772
+ it('should give precedence to className from spread props', () => {
+ const Foo = ({ className, ...props }) => {
+ return <div className={`${className} foo`} {...props} />;
+ };
+ render(<Foo className="bar" />, scratch);
+ expect(scratch.firstChild.className).to.equal('bar foo');
+ });
+
+ it('should give precedence to class from spread props', () => {
+ const Foo = ({ class: c, ...props }) => {
+ return <div class={`${c} foo`} {...props} />;
+ };
+ render(<Foo class="bar" />, scratch);
+ expect(scratch.firstChild.className).to.equal('bar foo');
+ });
+
+ // Issue #2224
+ it('should not mark both class and className as enumerable', () => {
+ function ClassNameCheck(props) {
+ return (
+ <div>{props.propertyIsEnumerable('className') ? 'Failed' : ''}</div>
+ );
+ }
+
+ let update;
+ class OtherThing extends Component {
+ render({ children }) {
+ update = () => this.forceUpdate();
+ return (
+ <div>
+ {children}
+ <ClassNameCheck class="test" />
+ </div>
+ );
+ }
+ }
+
+ function App() {
+ return (
+ <OtherThing>
+ <ClassNameCheck class="test" />
+ </OtherThing>
+ );
+ }
+
+ render(<App />, scratch);
+
+ update();
+ rerender();
+
+ expect(/Failed/g.test(scratch.textContent)).to.equal(
+ false,
+ 'not enumerable'
+ );
+ });
+ });
+
+ it('should cast boolean "download" values', () => {
+ render(<a download />, scratch);
+ expect(scratch.firstChild.getAttribute('download')).to.equal('');
+
+ render(<a download={false} />, scratch);
+ expect(scratch.firstChild.getAttribute('download')).to.equal(null);
+ });
+
+ it('should support static content', () => {
+ const updateSpy = sinon.spy();
+ const mountSpy = sinon.spy();
+ const renderSpy = sinon.spy();
+
+ function StaticContent({ children, element = 'div', staticMode }) {
+ // if we're in the server or a spa navigation, just render it
+ if (!staticMode) {
+ return createElement(element, {
+ children
+ });
+ }
+
+ // avoid re-render on the client
+ return createElement(element, {
+ dangerouslySetInnerHTML: { __html: '' }
+ });
+ }
+
+ class App extends Component {
+ componentDidMount() {
+ mountSpy();
+ }
+
+ componentDidUpdate() {
+ updateSpy();
+ }
+
+ render() {
+ renderSpy();
+ return <div>Staticness</div>;
+ }
+ }
+
+ act(() => {
+ render(
+ <StaticContent staticMode={false}>
+ <App />
+ </StaticContent>,
+ scratch
+ );
+ });
+
+ expect(scratch.innerHTML).to.eq('<div><div>Staticness</div></div>');
+ expect(renderSpy).to.be.calledOnce;
+ expect(mountSpy).to.be.calledOnce;
+ expect(updateSpy).to.not.be.calledOnce;
+
+ act(() => {
+ hydrate(
+ <StaticContent staticMode>
+ <App />
+ </StaticContent>,
+ scratch
+ );
+ });
+
+ expect(scratch.innerHTML).to.eq('<div><div>Staticness</div></div>');
+ expect(renderSpy).to.be.calledOnce;
+ expect(mountSpy).to.be.calledOnce;
+ expect(updateSpy).to.not.be.calledOnce;
+ });
+
+ it("should support react-relay's usage of __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED", () => {
+ const Ctx = createContext('foo');
+
+ // Simplified version of: https://github.com/facebook/relay/blob/fba79309977bf6b356ee77a5421ca5e6f306223b/packages/react-relay/readContext.js#L17-L28
+ function readContext(Context) {
+ const {
+ ReactCurrentDispatcher
+ } = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+ const dispatcher = ReactCurrentDispatcher.current;
+ return dispatcher.readContext(Context);
+ }
+
+ function Foo() {
+ const value = readContext(Ctx);
+ return <div>{value}</div>;
+ }
+
+ React.render(
+ <Ctx.Provider value="foo">
+ <Foo />
+ </Ctx.Provider>,
+ scratch
+ );
+
+ expect(scratch.textContent).to.equal('foo');
+ });
+});
diff --git a/preact/compat/test/browser/scheduler.test.js b/preact/compat/test/browser/scheduler.test.js
new file mode 100644
index 0000000..fdb426d
--- /dev/null
+++ b/preact/compat/test/browser/scheduler.test.js
@@ -0,0 +1,39 @@
+import {
+ unstable_runWithPriority,
+ unstable_NormalPriority,
+ unstable_LowPriority,
+ unstable_IdlePriority,
+ unstable_UserBlockingPriority,
+ unstable_ImmediatePriority,
+ unstable_now
+} from 'preact/compat/scheduler';
+
+describe('scheduler', () => {
+ describe('runWithPriority', () => {
+ it('should call callback ', () => {
+ const spy = sinon.spy();
+ unstable_runWithPriority(unstable_IdlePriority, spy);
+ expect(spy.callCount).to.equal(1);
+
+ unstable_runWithPriority(unstable_LowPriority, spy);
+ expect(spy.callCount).to.equal(2);
+
+ unstable_runWithPriority(unstable_NormalPriority, spy);
+ expect(spy.callCount).to.equal(3);
+
+ unstable_runWithPriority(unstable_UserBlockingPriority, spy);
+ expect(spy.callCount).to.equal(4);
+
+ unstable_runWithPriority(unstable_ImmediatePriority, spy);
+ expect(spy.callCount).to.equal(5);
+ });
+ });
+
+ describe('unstable_now', () => {
+ it('should return number', () => {
+ const res = unstable_now();
+ expect(res).is.a('number');
+ expect(res > 0).to.equal(true);
+ });
+ });
+});
diff --git a/preact/compat/test/browser/select.test.js b/preact/compat/test/browser/select.test.js
new file mode 100644
index 0000000..bf8c9b9
--- /dev/null
+++ b/preact/compat/test/browser/select.test.js
@@ -0,0 +1,33 @@
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import React, { createElement, render } from 'preact/compat';
+
+describe('Select', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should work with multiple selected (array of values)', () => {
+ function App() {
+ return (
+ <select multiple value={['B', 'C']}>
+ <option value="A">A</option>
+ <option value="B">B</option>
+ <option value="C">C</option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ const options = scratch.firstChild.children;
+ expect(options[0]).to.have.property('selected', false);
+ expect(options[1]).to.have.property('selected', true);
+ expect(options[2]).to.have.property('selected', true);
+ expect(scratch.firstChild.value).to.equal('B');
+ });
+});
diff --git a/preact/compat/test/browser/suspense-hydration.test.js b/preact/compat/test/browser/suspense-hydration.test.js
new file mode 100644
index 0000000..b8d45f8
--- /dev/null
+++ b/preact/compat/test/browser/suspense-hydration.test.js
@@ -0,0 +1,778 @@
+import { setupRerender } from 'preact/test-utils';
+import React, {
+ createElement,
+ hydrate,
+ Fragment,
+ Suspense,
+ useState
+} from 'preact/compat';
+import { logCall, getLog, clearLog } from '../../../test/_util/logCall';
+import {
+ createEvent,
+ setupScratch,
+ teardown
+} from '../../../test/_util/helpers';
+import { ul, li, div } from '../../../test/_util/dom';
+import { createLazy } from './suspense-utils';
+
+/* eslint-env browser, mocha */
+describe('suspense hydration', () => {
+ /** @type {HTMLDivElement} */
+ let scratch,
+ rerender,
+ unhandledEvents = [];
+
+ const List = ({ children }) => <ul>{children}</ul>;
+ const ListItem = ({ children, onClick = null }) => (
+ <li onClick={onClick}>{children}</li>
+ );
+
+ function onUnhandledRejection(event) {
+ unhandledEvents.push(event);
+ }
+
+ let resetAppendChild;
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+
+ before(() => {
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ resetRemove = logCall(Element.prototype, 'remove');
+ });
+
+ after(() => {
+ resetAppendChild();
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ unhandledEvents = [];
+ if ('onunhandledrejection' in window) {
+ window.addEventListener('unhandledrejection', onUnhandledRejection);
+ }
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+
+ if ('onunhandledrejection' in window) {
+ window.removeEventListener('unhandledrejection', onUnhandledRejection);
+
+ if (unhandledEvents.length) {
+ throw unhandledEvents[0].reason;
+ }
+ }
+ });
+
+ it('should leave DOM untouched when suspending while hydrating', () => {
+ scratch.innerHTML = '<div>Hello</div>';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <Suspense>
+ <Lazy />
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(() => <div>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+ });
+ });
+
+ it('should properly attach event listeners when suspending while hydrating', () => {
+ scratch.innerHTML = '<div>Hello</div><div>World</div>';
+ clearLog();
+
+ const helloListener = sinon.spy();
+ const worldListener = sinon.spy();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <Suspense>
+ <Lazy />
+ <div onClick={worldListener}>World!</div>
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div>Hello</div><div>World!</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch.querySelector('div:last-child').dispatchEvent(createEvent('click'));
+ expect(worldListener, 'worldListener 1').to.have.been.calledOnce;
+
+ return resolve(() => <div onClick={helloListener}>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Hello</div><div>World!</div>');
+ expect(getLog()).to.deep.equal([]);
+
+ scratch
+ .querySelector('div:first-child')
+ .dispatchEvent(createEvent('click'));
+ expect(helloListener, 'helloListener').to.have.been.calledOnce;
+
+ scratch
+ .querySelector('div:last-child')
+ .dispatchEvent(createEvent('click'));
+ expect(worldListener, 'worldListener 2').to.have.been.calledTwice;
+
+ clearLog();
+ });
+ });
+
+ it('should allow siblings to update around suspense boundary', () => {
+ scratch.innerHTML = '<div>Count: 0</div><div>Hello</div>';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+
+ /** @type {() => void} */
+ let increment;
+ function Counter() {
+ const [count, setCount] = useState(0);
+ increment = () => setCount(c => c + 1);
+ return <div>Count: {count}</div>;
+ }
+
+ hydrate(
+ <Fragment>
+ <Counter />
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ </Fragment>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div>Count: 0</div><div>Hello</div>');
+ // Re: DOM OP below - Known issue with hydrating merged text nodes
+ expect(getLog()).to.deep.equal(['<div>Count: .appendChild(#text)']);
+ clearLog();
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div>Count: 1</div><div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(() => <div>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Count: 1</div><div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+ });
+ });
+
+ it('should allow parents to update around suspense boundary and unmount', async () => {
+ scratch.innerHTML = '<div>Count: 0</div><div>Hello</div>';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+
+ /** @type {() => void} */
+ let increment;
+ function Counter() {
+ const [count, setCount] = useState(0);
+ increment = () => setCount(c => c + 1);
+ return (
+ <Fragment>
+ <div>Count: {count}</div>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ </Fragment>
+ );
+ }
+
+ let hide;
+ function Component() {
+ const [show, setShow] = useState(true);
+ hide = () => setShow(false);
+
+ return show ? <Counter /> : null;
+ }
+
+ hydrate(<Component />, scratch);
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div>Count: 0</div><div>Hello</div>');
+ // Re: DOM OP below - Known issue with hydrating merged text nodes
+ expect(getLog()).to.deep.equal(['<div>Count: .appendChild(#text)']);
+ clearLog();
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div>Count: 1</div><div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ await resolve(() => <div>Hello</div>);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Count: 1</div><div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should allow parents to update around suspense boundary and unmount before resolves', async () => {
+ scratch.innerHTML = '<div>Count: 0</div><div>Hello</div>';
+ clearLog();
+
+ const [Lazy] = createLazy();
+
+ /** @type {() => void} */
+ let increment;
+ function Counter() {
+ const [count, setCount] = useState(0);
+ increment = () => setCount(c => c + 1);
+ return (
+ <Fragment>
+ <div>Count: {count}</div>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ </Fragment>
+ );
+ }
+
+ let hide;
+ function Component() {
+ const [show, setShow] = useState(true);
+ hide = () => setShow(false);
+
+ return show ? <Counter /> : null;
+ }
+
+ hydrate(<Component />, scratch);
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div>Count: 0</div><div>Hello</div>');
+ // Re: DOM OP below - Known issue with hydrating merged text nodes
+ expect(getLog()).to.deep.equal(['<div>Count: .appendChild(#text)']);
+ clearLog();
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div>Count: 1</div><div>Hello</div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should allow parents to unmount before resolves', async () => {
+ scratch.innerHTML = '<div>Count: 0</div><div>Hello</div>';
+
+ const [Lazy] = createLazy();
+
+ function Counter() {
+ return (
+ <Fragment>
+ <div>Count: 0</div>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ </Fragment>
+ );
+ }
+
+ let hide;
+ function Component() {
+ const [show, setShow] = useState(true);
+ hide = () => setShow(false);
+
+ return show ? <Counter /> : null;
+ }
+
+ hydrate(<Component />, scratch);
+ rerender(); // Flush rerender queue to mimic what preact will really do
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should properly hydrate when there is DOM and Components between Suspense and suspender', () => {
+ scratch.innerHTML = '<div><div>Hello</div></div>';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <Suspense>
+ <div>
+ <Fragment>
+ <Lazy />
+ </Fragment>
+ </div>
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('<div><div>Hello</div></div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(() => <div>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><div>Hello</div></div>');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+ });
+ });
+
+ it('should properly hydrate suspense with Fragment siblings', () => {
+ const originalHtml = ul([li(0), li(1), li(2), li(3), li(4)]);
+
+ const listeners = [
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy()
+ ];
+
+ scratch.innerHTML = originalHtml;
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <ul>
+ <Fragment>
+ <li onClick={listeners[0]}>0</li>
+ <li onClick={listeners[1]}>1</li>
+ </Fragment>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ <Fragment>
+ <li onClick={listeners[3]}>3</li>
+ <li onClick={listeners[4]}>4</li>
+ </Fragment>
+ </ul>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ expect(listeners[4]).not.to.have.been.called;
+
+ clearLog();
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+ expect(listeners[4]).to.have.been.calledOnce;
+
+ return resolve(() => (
+ <Fragment>
+ <li onClick={listeners[2]}>2</li>
+ </Fragment>
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch
+ .querySelector('li:nth-child(3)')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[2]).to.have.been.calledOnce;
+
+ scratch
+ .querySelector('li:last-child')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[4]).to.have.been.calledTwice;
+ });
+ });
+
+ it('should properly hydrate suspense with Component & Fragment siblings', () => {
+ const originalHtml = ul([li(0), li(1), li(2), li(3), li(4)]);
+
+ const listeners = [
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy()
+ ];
+
+ scratch.innerHTML = originalHtml;
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <List>
+ <Fragment>
+ <ListItem onClick={listeners[0]}>0</ListItem>
+ <ListItem onClick={listeners[1]}>1</ListItem>
+ </Fragment>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ <Fragment>
+ <ListItem onClick={listeners[3]}>3</ListItem>
+ <ListItem onClick={listeners[4]}>4</ListItem>
+ </Fragment>
+ </List>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ expect(listeners[4]).not.to.have.been.called;
+
+ clearLog();
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+ expect(listeners[4]).to.have.been.calledOnce;
+
+ return resolve(() => (
+ <Fragment>
+ <ListItem onClick={listeners[2]}>2</ListItem>
+ </Fragment>
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch
+ .querySelector('li:nth-child(3)')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[2]).to.have.been.calledOnce;
+
+ scratch
+ .querySelector('li:last-child')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[4]).to.have.been.calledTwice;
+ });
+ });
+
+ it('should suspend hydration with components with state and event listeners between suspender and Suspense', () => {
+ let html = div([div('Count: 0'), div('Hello')]);
+ scratch.innerHTML = html;
+ clearLog();
+
+ function Counter({ children }) {
+ const [count, setCount] = useState(0);
+ return (
+ <div onClick={() => setCount(count + 1)}>
+ <div>Count: {count}</div>
+ {children}
+ </div>
+ );
+ }
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <Suspense>
+ <Counter>
+ <Lazy />
+ </Counter>
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal(['<div>Count: .appendChild(#text)']);
+ clearLog();
+
+ scratch.firstElementChild.dispatchEvent(createEvent('click'));
+ rerender();
+
+ html = div([div('Count: 1'), div('Hello')]);
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ const lazySpy = sinon.spy();
+ return resolve(() => <div onClick={lazySpy}>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ const lazyDiv = scratch.firstChild.firstChild.nextSibling;
+ expect(lazyDiv.textContent).to.equal('Hello');
+ expect(lazySpy).not.to.have.been.called;
+
+ lazyDiv.dispatchEvent(createEvent('click'));
+ rerender();
+
+ expect(lazySpy).to.have.been.calledOnce;
+ });
+ });
+
+ it('should maintain state of sibling components around suspender', () => {
+ let html = [div('Count: 0'), div('Hello'), div('Count: 0')].join('');
+ scratch.innerHTML = html;
+ clearLog();
+
+ function Counter() {
+ const [count, setCount] = useState(0);
+ return <div onClick={() => setCount(count + 1)}>Count: {count}</div>;
+ }
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <Suspense>
+ <Counter />
+ <Lazy />
+ <Counter />
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([
+ '<div>Count: .appendChild(#text)',
+ '<div>Count: .appendChild(#text)'
+ ]);
+ clearLog();
+
+ // Update state of first Counter
+ scratch.firstElementChild.dispatchEvent(createEvent('click'));
+ rerender();
+
+ html = [div('Count: 1'), div('Hello'), div('Count: 0')].join('');
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ // Update state of second Counter
+ scratch.lastElementChild.dispatchEvent(createEvent('click'));
+ rerender();
+
+ html = [div('Count: 1'), div('Hello'), div('Count: 1')].join('');
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ const lazySpy = sinon.spy();
+ return resolve(() => <div onClick={lazySpy}>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ const lazyDiv = scratch.firstChild.nextSibling;
+ expect(lazyDiv.textContent).to.equal('Hello');
+ expect(lazySpy).not.to.have.been.called;
+
+ lazyDiv.dispatchEvent(createEvent('click'));
+ rerender();
+
+ expect(lazySpy).to.have.been.calledOnce;
+ });
+ });
+
+ it('should allow component to re-suspend using normal suspension mechanics after initial suspended hydration resumes', () => {
+ const originalHtml = [div('a'), div('b1'), div('c')].join('');
+ scratch.innerHTML = originalHtml;
+ clearLog();
+
+ const bOnClickSpy = sinon.spy();
+ const cOnClickSpy = sinon.spy();
+
+ const [Lazy, resolve] = createLazy();
+
+ /** @type {(c: React.JSX.Element) => void} */
+ let setChild;
+ function App() {
+ // Mimic some state that may cause a suspend
+ const [child, setChildInternal] = useState(<Lazy />);
+ setChild = setChildInternal;
+
+ return (
+ <Suspense fallback={<div>fallback</div>}>
+ <div>a</div>
+ {child}
+ <div onClick={cOnClickSpy}>c</div>
+ </Suspense>
+ );
+ }
+
+ // Validate initial hydration suspend resumes (initial markup stays the same
+ // and event listeners attached)
+ hydrate(<App />, scratch);
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML, 'initial HTML').to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch.lastChild.dispatchEvent(createEvent('click'));
+ rerender();
+ expect(cOnClickSpy).to.have.been.calledOnce;
+
+ return resolve(() => <div onClick={bOnClickSpy}>b1</div>)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML, 'hydration resumes').to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch.firstChild.nextSibling.dispatchEvent(createEvent('click'));
+ rerender();
+ expect(bOnClickSpy).to.have.been.calledOnce;
+
+ // suspend again and validate normal suspension works (fallback renders
+ // and result)
+ const [Lazy2, resolve2] = createLazy();
+ setChild(<Lazy2 />);
+ rerender();
+
+ expect(scratch.innerHTML, 'second suspend').to.equal(div('fallback'));
+
+ return resolve2(() => <div onClick={bOnClickSpy}>b2</div>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML, 'second suspend resumes').to.equal(
+ [div('a'), div('b2'), div('c')].join('')
+ );
+
+ scratch.lastChild.dispatchEvent(createEvent('click'));
+ expect(cOnClickSpy).to.have.been.calledTwice;
+
+ scratch.firstChild.nextSibling.dispatchEvent(createEvent('click'));
+ expect(bOnClickSpy).to.have.been.calledTwice;
+ });
+ });
+
+ // Currently not supported. Hydration doesn't set attributes... but should it
+ // when coming back from suspense if props were updated?
+ it.skip('should hydrate and update attributes with latest props', () => {
+ const originalHtml = '<p>Count: 0</p><p data-count="0">Lazy count: 0</p>';
+ scratch.innerHTML = originalHtml;
+ clearLog();
+
+ /** @type {() => void} */
+ let increment;
+ const [Lazy, resolve] = createLazy();
+ function App() {
+ const [count, setCount] = useState(0);
+ increment = () => setCount(c => c + 1);
+
+ return (
+ <Suspense>
+ <p>Count: {count}</p>
+ <Lazy count={count} />
+ </Suspense>
+ );
+ }
+
+ hydrate(<App />, scratch);
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ // Re: DOM OP below - Known issue with hydrating merged text nodes
+ expect(getLog()).to.deep.equal(['<p>Count: .appendChild(#text)']);
+ clearLog();
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ '<p>Count: 1</p><p data-count="0">Lazy count: 0</p>'
+ );
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(({ count }) => (
+ <p data-count={count}>Lazy count: {count}</p>
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<p>Count: 1</p><p data-count="1">Lazy count: 1</p>'
+ );
+ // Re: DOM OP below - Known issue with hydrating merged text nodes
+ expect(getLog()).to.deep.equal(['<p>Lazy count: .appendChild(#text)']);
+ clearLog();
+ });
+ });
+
+ // Currently not supported, but I wrote the test before I realized that so
+ // leaving it here in case we do support it eventually
+ it.skip('should properly hydrate suspense when resolves to a Fragment', () => {
+ const originalHtml = ul([li(0), li(1), li(2), li(3), li(4), li(5)]);
+
+ const listeners = [
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy()
+ ];
+
+ scratch.innerHTML = originalHtml;
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <List>
+ <Fragment>
+ <ListItem onClick={listeners[0]}>0</ListItem>
+ <ListItem onClick={listeners[1]}>1</ListItem>
+ </Fragment>
+ <Suspense>
+ <Lazy />
+ </Suspense>
+ <Fragment>
+ <ListItem onClick={listeners[4]}>4</ListItem>
+ <ListItem onClick={listeners[5]}>5</ListItem>
+ </Fragment>
+ </List>,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ expect(listeners[5]).not.to.have.been.called;
+
+ clearLog();
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+ expect(listeners[5]).to.have.been.calledOnce;
+
+ return resolve(() => (
+ <Fragment>
+ <ListItem onClick={listeners[2]}>2</ListItem>
+ <ListItem onClick={listeners[3]}>3</ListItem>
+ </Fragment>
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(originalHtml);
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ scratch
+ .querySelector('li:nth-child(4)')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[3]).to.have.been.calledOnce;
+
+ scratch
+ .querySelector('li:last-child')
+ .dispatchEvent(createEvent('click'));
+ expect(listeners[5]).to.have.been.calledTwice;
+ });
+ });
+});
diff --git a/preact/compat/test/browser/suspense-list.test.js b/preact/compat/test/browser/suspense-list.test.js
new file mode 100644
index 0000000..f3d4c91
--- /dev/null
+++ b/preact/compat/test/browser/suspense-list.test.js
@@ -0,0 +1,588 @@
+import { setupRerender } from 'preact/test-utils';
+import React, {
+ createElement,
+ render,
+ Component,
+ Suspense,
+ SuspenseList
+} from 'preact/compat';
+import { useState } from 'preact/hooks';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+const h = React.createElement;
+/* eslint-env browser, mocha */
+
+function getSuspendableComponent(text) {
+ let resolve;
+ let resolved = false;
+ const promise = new Promise(_resolve => {
+ resolve = () => {
+ resolved = true;
+ _resolve();
+ return promise;
+ };
+ });
+
+ class LifecycleSuspender extends Component {
+ render() {
+ if (!resolved) {
+ throw promise;
+ }
+ return <span>{text}</span>;
+ }
+ }
+
+ LifecycleSuspender.resolve = () => {
+ resolve();
+ };
+
+ return LifecycleSuspender;
+}
+
+describe('suspense-list', () => {
+ /** @type {HTMLDivElement} */
+ let scratch,
+ rerender,
+ unhandledEvents = [];
+
+ function onUnhandledRejection(event) {
+ unhandledEvents.push(event);
+ }
+
+ function getSuspenseList(revealOrder) {
+ const A = getSuspendableComponent('A');
+ const B = getSuspendableComponent('B');
+ const C = getSuspendableComponent('C');
+ render(
+ <SuspenseList revealOrder={revealOrder}>
+ <Suspense fallback={<span>Loading...</span>}>
+ <A />
+ </Suspense>
+ <Suspense fallback={<span>Loading...</span>}>
+ <B />
+ </Suspense>
+ <Suspense fallback={<span>Loading...</span>}>
+ <C />
+ </Suspense>
+ </SuspenseList>,
+ scratch
+ ); // Render initial state
+
+ return [A.resolve, B.resolve, C.resolve];
+ }
+
+ function getNestedSuspenseList(outerRevealOrder, innerRevealOrder) {
+ const A = getSuspendableComponent('A');
+ const B = getSuspendableComponent('B');
+ const C = getSuspendableComponent('C');
+ const D = getSuspendableComponent('D');
+
+ render(
+ <SuspenseList revealOrder={outerRevealOrder}>
+ <Suspense fallback={<span>Loading...</span>}>
+ <A />
+ </Suspense>
+ <SuspenseList revealOrder={innerRevealOrder}>
+ <Suspense fallback={<span>Loading...</span>}>
+ <B />
+ </Suspense>
+ <Suspense fallback={<span>Loading...</span>}>
+ <C />
+ </Suspense>
+ </SuspenseList>
+ <Suspense fallback={<span>Loading...</span>}>
+ <D />
+ </Suspense>
+ </SuspenseList>,
+ scratch
+ );
+ return [A.resolve, B.resolve, C.resolve, D.resolve];
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ unhandledEvents = [];
+
+ if ('onunhandledrejection' in window) {
+ window.addEventListener('unhandledrejection', onUnhandledRejection);
+ }
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+
+ if ('onunhandledrejection' in window) {
+ window.removeEventListener('unhandledrejection', onUnhandledRejection);
+
+ if (unhandledEvents.length) {
+ throw unhandledEvents[0].reason;
+ }
+ }
+ });
+
+ it('should work for single element', async () => {
+ const Component = getSuspendableComponent('A');
+ render(
+ <SuspenseList>
+ <Suspense fallback={<span>Loading...</span>}>
+ <Component />
+ </Suspense>
+ </SuspenseList>,
+ scratch
+ ); // Render initial state
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(`<span>Loading...</span>`);
+
+ await Component.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<span>A</span>`);
+ });
+
+ it('should let components appear backwards if no revealOrder is mentioned', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList();
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>B</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>B</span><span>C</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should let components appear forwards if no revealOrder is mentioned', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList();
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should let components appear in forwards if revealOrder=forwards and first one resolves before others', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('forwards');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should make components appear together if revealOrder=forwards and others resolves before first', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('forwards');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should let components appear backwards if revealOrder=backwards and others resolves before first', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('backwards');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>C</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>B</span><span>C</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should make components appear together if revealOrder=backwards and first one resolves others', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('backwards');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>C</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should make components appear together if revealOrder=together and first one resolves others', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('together');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should make components appear together if revealOrder=together and second one resolves before others', async () => {
+ const [resolver1, resolver2, resolver3] = getSuspenseList('together');
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver2();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver1();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolver3();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span>`
+ );
+ });
+
+ it('should not do anything to non suspense elements', async () => {
+ const A = getSuspendableComponent('A');
+ const B = getSuspendableComponent('B');
+ render(
+ <SuspenseList>
+ <Suspense fallback={<span>Loading...</span>}>
+ <A />
+ </Suspense>
+ <div>foo</div>
+ <Suspense fallback={<span>Loading...</span>}>
+ <B />
+ </Suspense>
+ <span>bar</span>
+ </SuspenseList>,
+ scratch
+ );
+
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><div>foo</div><span>Loading...</span><span>bar</span>`
+ );
+
+ await A.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><div>foo</div><span>Loading...</span><span>bar</span>`
+ );
+
+ await B.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><div>foo</div><span>B</span><span>bar</span>`
+ );
+ });
+
+ it('should make sure nested SuspenseList works with forwards', async () => {
+ const [resolveA, resolveB, resolveC, resolveD] = getNestedSuspenseList(
+ 'forwards',
+ 'forwards'
+ );
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveB();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveA();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveC();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span><span>Loading...</span>`
+ );
+
+ await resolveD();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span><span>D</span>`
+ );
+ });
+
+ it('should make sure nested SuspenseList works with backwards', async () => {
+ const [resolveA, resolveB, resolveC, resolveD] = getNestedSuspenseList(
+ 'forwards',
+ 'backwards'
+ );
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveA();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveC();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>Loading...</span><span>C</span><span>Loading...</span>`
+ );
+
+ await resolveB();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span><span>Loading...</span>`
+ );
+
+ await resolveD();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span><span>D</span>`
+ );
+ });
+
+ it('should make sure nested SuspenseList works with together', async () => {
+ const [resolveA, resolveB, resolveC, resolveD] = getNestedSuspenseList(
+ 'together',
+ 'forwards'
+ );
+ rerender(); // Re-render with fallback cuz lazy threw
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveA();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveD();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveB();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>Loading...</span><span>Loading...</span><span>Loading...</span><span>Loading...</span>`
+ );
+
+ await resolveC();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>A</span><span>B</span><span>C</span><span>D</span>`
+ );
+ });
+
+ it('should work with forwards even when a <Suspense> child does not suspend', async () => {
+ const Component = getSuspendableComponent('A');
+
+ render(
+ <SuspenseList revealOrder="forwards">
+ <Suspense fallback={<span>Loading...</span>}>
+ <div />
+ </Suspense>
+ <Suspense fallback={<span>Loading...</span>}>
+ <Component />
+ </Suspense>
+ </SuspenseList>,
+ scratch
+ ); // Render initial state
+
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>Loading...</span>`);
+
+ await Component.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>A</span>`);
+ });
+
+ it('should work with together even when a <Suspense> child does not suspend', async () => {
+ const Component = getSuspendableComponent('A');
+
+ render(
+ <SuspenseList revealOrder="together">
+ <Suspense fallback={<span>Loading...</span>}>
+ <div />
+ </Suspense>
+ <Suspense fallback={<span>Loading...</span>}>
+ <Component />
+ </Suspense>
+ </SuspenseList>,
+ scratch
+ ); // Render initial state
+
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>Loading...</span>`);
+
+ await Component.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>A</span>`);
+ });
+
+ it('should not suspend resolved children if a new suspense comes in between', async () => {
+ const ComponentA = getSuspendableComponent('A');
+ const ComponentB = getSuspendableComponent('B');
+
+ let showB;
+ function Container() {
+ const [showHidden, setShowHidden] = useState(false);
+ showB = setShowHidden;
+ return (
+ <SuspenseList revealOrder="together">
+ <Suspense fallback={<span>Loading...</span>}>
+ <div />
+ </Suspense>
+ {showHidden && (
+ <Suspense fallback={<span>Loading...</span>}>
+ <ComponentB />
+ </Suspense>
+ )}
+ <Suspense fallback={<span>Loading...</span>}>
+ <ComponentA />
+ </Suspense>
+ </SuspenseList>
+ );
+ }
+ render(<Container />, scratch); // Render initial state
+
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>Loading...</span>`);
+
+ await ComponentA.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>A</span>`);
+
+ showB(true);
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div></div><span>Loading...</span><span>A</span>`
+ );
+
+ await ComponentB.resolve();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div></div><span>B</span><span>A</span>`);
+ });
+});
diff --git a/preact/compat/test/browser/suspense-utils.js b/preact/compat/test/browser/suspense-utils.js
new file mode 100644
index 0000000..f8f380b
--- /dev/null
+++ b/preact/compat/test/browser/suspense-utils.js
@@ -0,0 +1,116 @@
+import React, { Component, lazy } from 'preact/compat';
+
+const h = React.createElement;
+
+/**
+ * Create a Lazy component whose promise is controlled by by the test. This
+ * function returns 3 values: The Lazy component to render, a `resolve`
+ * function, and a `reject` function. Call `resolve` with the component the Lazy
+ * component should resolve with. Call `reject` with the error the Lazy
+ * component should reject with
+ *
+ * @example
+ * // 1. Create and render the Lazy component
+ * const [Lazy, resolve] = createLazy();
+ * render(
+ * <Suspense fallback={<div>Suspended...</div>}>
+ * <Lazy />
+ * </Suspense>,
+ * scratch
+ * );
+ * rerender(); // Rerender is required so the fallback is displayed
+ * expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ *
+ * // 2. Resolve the Lazy with a new component to render
+ * return resolve(() => <div>Hello</div>).then(() => {
+ * rerender();
+ * expect(scratch.innerHTML).to.equal(`<div>Hello</div>`);
+ * });
+ *
+ * @typedef {import('../../../src').ComponentType<any>} ComponentType
+ * @returns {[typeof Component, (c: ComponentType) => Promise<void>, (e: Error) => Promise<void>]}
+ */
+export function createLazy() {
+ /** @type {(c: ComponentType) => Promise<void>} */
+ let resolver, rejecter;
+ const Lazy = lazy(() => {
+ let promise = new Promise((resolve, reject) => {
+ resolver = c => {
+ resolve({ default: c });
+ return promise;
+ };
+
+ rejecter = e => {
+ reject(e);
+ return promise;
+ };
+ });
+
+ return promise;
+ });
+
+ return [Lazy, c => resolver(c), e => rejecter(e)];
+}
+
+/**
+ * Returns a Component and a function (named `suspend`) that will suspend the component when called.
+ * `suspend` will return two functions, `resolve` and `reject`. Call `resolve` with a Component the
+ * suspended component should resume with or reject with the Error the suspended component should
+ * reject with
+ *
+ * @example
+ * // 1. Create a suspender with initial children (argument to createSuspender) and render it
+ * const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+ * render(
+ * <Suspense fallback={<div>Suspended...</div>}>
+ * <Suspender />
+ * </Suspense>,
+ * scratch
+ * );
+ * expect(scratch.innerHTML).to.eql(`div>Hello</div>`);
+ *
+ * // 2. Cause the component to suspend and rerender the update (i.e. the fallback)
+ * const [resolve] = suspend();
+ * rerender();
+ * expect(scratch.innerHTML).to.eql(`div>Suspended...</div>`);
+ *
+ * // 3. Resolve the suspended component with a new component and rerender
+ * return resolve(() => <div>Hello2</div>).then(() => {
+ * rerender();
+ * expect(scratch.innerHTML).to.eql(`div>Hello2</div>`);
+ * });
+ *
+ * @typedef {Component<{}, any>} Suspender
+ * @typedef {[(c: ComponentType) => Promise<void>, (error: Error) => Promise<void>]} Resolvers
+ * @param {ComponentType} DefaultComponent
+ * @returns {[typeof Suspender, () => Resolvers]}
+ */
+export function createSuspender(DefaultComponent) {
+ /** @type {(lazy: typeof Component) => void} */
+ let renderLazy;
+ class Suspender extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = { Lazy: null };
+
+ renderLazy = Lazy => this.setState({ Lazy });
+ }
+
+ render(props, state) {
+ return state.Lazy ? h(state.Lazy, props) : h(DefaultComponent, props);
+ }
+ }
+
+ sinon.spy(Suspender.prototype, 'render');
+
+ /**
+ * @returns {Resolvers}
+ */
+ function suspend() {
+ const [Lazy, resolve, reject] = createLazy();
+ renderLazy(Lazy);
+ return [resolve, reject];
+ }
+
+ return [Suspender, suspend];
+}
diff --git a/preact/compat/test/browser/suspense.test.js b/preact/compat/test/browser/suspense.test.js
new file mode 100644
index 0000000..cc2cd84
--- /dev/null
+++ b/preact/compat/test/browser/suspense.test.js
@@ -0,0 +1,2091 @@
+import { setupRerender } from 'preact/test-utils';
+import React, {
+ createElement,
+ render,
+ Component,
+ Suspense,
+ lazy,
+ Fragment,
+ createContext,
+ useState,
+ useEffect,
+ useLayoutEffect
+} from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { createLazy, createSuspender } from './suspense-utils';
+
+const h = React.createElement;
+/* eslint-env browser, mocha */
+
+class Catcher extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { error: false };
+ }
+
+ componentDidCatch(e) {
+ if (e.then) {
+ this.setState({ error: { message: '{Promise}' } });
+ } else {
+ this.setState({ error: e });
+ }
+ }
+
+ render(props, state) {
+ return state.error ? (
+ <div>Catcher did catch: {state.error.message}</div>
+ ) : (
+ props.children
+ );
+ }
+}
+
+describe('suspense', () => {
+ /** @type {HTMLDivElement} */
+ let scratch,
+ rerender,
+ unhandledEvents = [];
+
+ function onUnhandledRejection(event) {
+ unhandledEvents.push(event);
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ unhandledEvents = [];
+ if ('onunhandledrejection' in window) {
+ window.addEventListener('unhandledrejection', onUnhandledRejection);
+ }
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+
+ if ('onunhandledrejection' in window) {
+ window.removeEventListener('unhandledrejection', onUnhandledRejection);
+
+ if (unhandledEvents.length) {
+ throw unhandledEvents[0].reason;
+ }
+ }
+ });
+
+ it('should support lazy', () => {
+ const LazyComp = ({ name }) => <div>Hello from {name}</div>;
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ const Lazy = lazy(() => {
+ const p = new Promise(res => {
+ resolve = () => {
+ res({ default: LazyComp });
+ return p;
+ };
+ });
+
+ return p;
+ });
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Lazy name="LazyComp" />
+ </Suspense>,
+ scratch
+ ); // Render initial state
+ rerender(); // Re-render with fallback cuz lazy threw
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve().then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Hello from LazyComp</div>`);
+ });
+ });
+
+ it('should reset hooks of components', () => {
+ let set;
+ const LazyComp = ({ name }) => <div>Hello from {name}</div>;
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ const Lazy = lazy(() => {
+ const p = new Promise(res => {
+ resolve = () => {
+ res({ default: LazyComp });
+ return p;
+ };
+ });
+
+ return p;
+ });
+
+ const Parent = ({ children }) => {
+ const [state, setState] = useState(false);
+ set = setState;
+
+ return (
+ <div>
+ <p>hi</p>
+ {state && children}
+ </div>
+ );
+ };
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Parent>
+ <Lazy name="LazyComp" />
+ </Parent>
+ </Suspense>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.eql(`<div><p>hi</p></div>`);
+
+ set(true);
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<div>Suspended...</div>');
+
+ return resolve().then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div><p>hi</p></div>`);
+ });
+ });
+
+ it('should call effect cleanups', () => {
+ let set;
+ const effectSpy = sinon.spy();
+ const layoutEffectSpy = sinon.spy();
+ const LazyComp = ({ name }) => <div>Hello from {name}</div>;
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ const Lazy = lazy(() => {
+ const p = new Promise(res => {
+ resolve = () => {
+ res({ default: LazyComp });
+ return p;
+ };
+ });
+
+ return p;
+ });
+
+ const Parent = ({ children }) => {
+ const [state, setState] = useState(false);
+ set = setState;
+ useEffect(() => {
+ return () => {
+ effectSpy();
+ };
+ }, []);
+
+ useLayoutEffect(() => {
+ return () => {
+ layoutEffectSpy();
+ };
+ }, []);
+
+ return state ? (
+ <div>{children}</div>
+ ) : (
+ <div>
+ <p>hi</p>
+ </div>
+ );
+ };
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Parent>
+ <Lazy name="LazyComp" />
+ </Parent>
+ </Suspense>,
+ scratch
+ );
+
+ set(true);
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>Suspended...</div>');
+ expect(effectSpy).to.be.calledOnce;
+ expect(layoutEffectSpy).to.be.calledOnce;
+
+ return resolve().then(() => {
+ rerender();
+ expect(effectSpy).to.be.calledOnce;
+ expect(layoutEffectSpy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.eql(`<div><p>hi</p></div>`);
+ });
+ });
+
+ it('should support a call to setState before rendering the fallback', () => {
+ const LazyComp = ({ name }) => <div>Hello from {name}</div>;
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ const Lazy = lazy(() => {
+ const p = new Promise(res => {
+ resolve = () => {
+ res({ default: LazyComp });
+ return p;
+ };
+ });
+
+ return p;
+ });
+
+ /** @type {(Object) => void} */
+ let setState;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ setState = this.setState.bind(this);
+ }
+ render(props, state) {
+ return (
+ <Fragment>
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Lazy name="LazyComp" />
+ </Suspense>
+ </Fragment>
+ );
+ }
+ }
+
+ render(<App />, scratch); // Render initial state
+
+ setState({ foo: 'bar' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve().then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Hello from LazyComp</div>`);
+ });
+ });
+
+ it('lazy should forward refs', () => {
+ const LazyComp = () => <div>Hello from LazyComp</div>;
+ let ref = {};
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ const Lazy = lazy(() => {
+ const p = new Promise(res => {
+ resolve = () => {
+ res({ default: LazyComp });
+ return p;
+ };
+ });
+
+ return p;
+ });
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Lazy ref={ref} />
+ </Suspense>,
+ scratch
+ );
+ rerender();
+
+ return resolve().then(() => {
+ rerender();
+ expect(ref.current.constructor).to.equal(LazyComp);
+ });
+ });
+
+ it('should suspend when a promise is thrown', () => {
+ class ClassWrapper extends Component {
+ render(props) {
+ return <div id="class-wrapper">{props.children}</div>;
+ }
+ }
+
+ const FuncWrapper = props => <div id="func-wrapper">{props.children}</div>;
+
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <ClassWrapper>
+ <FuncWrapper>
+ <Suspender />
+ </FuncWrapper>
+ </ClassWrapper>
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div id="class-wrapper"><div id="func-wrapper"><div>Hello</div></div></div>`
+ );
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Hello2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div id="class-wrapper"><div id="func-wrapper"><div>Hello2</div></div></div>`
+ );
+ });
+ });
+
+ it('should not call lifecycle methods of an initially suspending component', () => {
+ let componentWillMount = sinon.spy();
+ let componentDidMount = sinon.spy();
+ let componentWillUnmount = sinon.spy();
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ let resolved = false;
+ const promise = new Promise(_resolve => {
+ resolve = () => {
+ resolved = true;
+ _resolve();
+ return promise;
+ };
+ });
+
+ class LifecycleSuspender extends Component {
+ render() {
+ if (!resolved) {
+ throw promise;
+ }
+ return <div>Lifecycle</div>;
+ }
+ componentWillMount() {
+ componentWillMount();
+ }
+ componentDidMount() {
+ componentDidMount();
+ }
+ componentWillUnmount() {
+ componentWillUnmount();
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <LifecycleSuspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(``);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.not.have.been.called;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.not.have.been.called;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ return resolve().then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Lifecycle</div>`);
+
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+ });
+ });
+
+ it('should properly call lifecycle methods and maintain state of a delayed suspending component', () => {
+ let componentWillMount = sinon.spy();
+ let componentDidMount = sinon.spy();
+ let componentDidUpdate = sinon.spy();
+ let componentWillUnmount = sinon.spy();
+
+ /** @type {() => void} */
+ let increment;
+
+ /** @type {() => Promise<void>} */
+ let resolve;
+ let resolved = false;
+ const promise = new Promise(_resolve => {
+ resolve = () => {
+ resolved = true;
+ _resolve();
+ return promise;
+ };
+ });
+
+ class LifecycleSuspender extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { count: 0 };
+
+ increment = () => this.setState(({ count }) => ({ count: count + 1 }));
+ }
+ render() {
+ if (this.state.count == 2 && !resolved) {
+ throw promise;
+ }
+
+ return (
+ <Fragment>
+ <p>Count: {this.state.count}</p>
+ </Fragment>
+ );
+ }
+ componentWillMount() {
+ componentWillMount();
+ }
+ componentDidMount() {
+ componentDidMount();
+ }
+ componentWillUnmount() {
+ componentWillUnmount();
+ }
+ componentDidUpdate() {
+ componentDidUpdate();
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <LifecycleSuspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<p>Count: 0</p>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentDidUpdate).to.not.have.been.called;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<p>Count: 1</p>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentDidUpdate).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentDidUpdate).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ return resolve().then(() => {
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<p>Count: 2</p>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ // TODO: This is called thrice since the cDU queued up after the second
+ // increment is never cleared once the component suspends. So when it
+ // resumes and the component is rerendered, we queue up another cDU so
+ // cDU is called an extra time.
+ expect(componentDidUpdate).to.have.been.calledThrice;
+ expect(componentWillUnmount).to.not.have.been.called;
+ });
+ });
+
+ it('should not call lifecycle methods when a sibling suspends', () => {
+ let componentWillMount = sinon.spy();
+ let componentDidMount = sinon.spy();
+ let componentWillUnmount = sinon.spy();
+ class LifecycleLogger extends Component {
+ render() {
+ return <div>Lifecycle</div>;
+ }
+ componentWillMount() {
+ componentWillMount();
+ }
+ componentDidMount() {
+ componentDidMount();
+ }
+ componentWillUnmount() {
+ componentWillUnmount();
+ }
+ }
+
+ const [Suspender, suspend] = createSuspender(() => <div>Suspense</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Suspender />
+ <LifecycleLogger />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspense</div><div>Lifecycle</div>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ const [resolve] = suspend();
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ return resolve(() => <div>Suspense 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense 2</div><div>Lifecycle</div>`
+ );
+
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+ });
+ });
+
+ it("should call fallback's lifecycle methods when suspending", () => {
+ class LifecycleLogger extends Component {
+ render() {
+ return <div>Lifecycle</div>;
+ }
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ }
+
+ const componentWillMount = sinon.spy(
+ LifecycleLogger.prototype,
+ 'componentWillMount'
+ );
+ const componentDidMount = sinon.spy(
+ LifecycleLogger.prototype,
+ 'componentDidMount'
+ );
+ const componentWillUnmount = sinon.spy(
+ LifecycleLogger.prototype,
+ 'componentWillUnmount'
+ );
+
+ const [Suspender, suspend] = createSuspender(() => <div>Suspense</div>);
+
+ render(
+ <Suspense fallback={<LifecycleLogger />}>
+ <Suspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspense</div>`);
+ expect(componentWillMount).to.not.have.been.called;
+ expect(componentDidMount).to.not.have.been.called;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ const [resolve] = suspend();
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Lifecycle</div>`);
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.not.have.been.called;
+
+ return resolve(() => <div>Suspense 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Suspense 2</div>`);
+
+ expect(componentWillMount).to.have.been.calledOnce;
+ expect(componentDidMount).to.have.been.calledOnce;
+ expect(componentWillUnmount).to.have.been.calledOnce;
+ });
+ });
+
+ it('should keep state of siblings when suspending', () => {
+ /** @type {(state: { s: string }) => void} */
+ let setState;
+ class Stateful extends Component {
+ constructor(props) {
+ super(props);
+ setState = this.setState.bind(this);
+ this.state = { s: 'initial' };
+ }
+ render(props, state) {
+ return <div>Stateful: {state.s}</div>;
+ }
+ }
+
+ const [Suspender, suspend] = createSuspender(() => <div>Suspense</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Suspender />
+ <Stateful />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: initial</div>`
+ );
+
+ setState({ s: 'first' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: first</div>`
+ );
+
+ const [resolve] = suspend();
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Suspense 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense 2</div><div>Stateful: first</div>`
+ );
+ });
+ });
+
+ it('should allow children to update state while suspending', () => {
+ /** @type {(state: { s: string }) => void} */
+ let setState;
+ class Stateful extends Component {
+ constructor(props) {
+ super(props);
+ setState = this.setState.bind(this);
+ this.state = { s: 'initial' };
+ }
+ render(props, state) {
+ return <div>Stateful: {state.s}</div>;
+ }
+ }
+
+ const [Suspender, suspend] = createSuspender(() => <div>Suspense</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Suspender />
+ <Stateful />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: initial</div>`
+ );
+
+ setState({ s: 'first' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: first</div>`
+ );
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ setState({ s: 'second' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Suspense 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense 2</div><div>Stateful: second</div>`
+ );
+ });
+ });
+
+ it('should allow siblings of Suspense to update state while suspending', () => {
+ /** @type {(state: { s: string }) => void} */
+ let setState;
+ class Stateful extends Component {
+ constructor(props) {
+ super(props);
+ setState = this.setState.bind(this);
+ this.state = { s: 'initial' };
+ }
+ render(props, state) {
+ return <div>Stateful: {state.s}</div>;
+ }
+ }
+
+ const [Suspender, suspend] = createSuspender(() => <div>Suspense</div>);
+
+ render(
+ <Fragment>
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Suspender />
+ </Suspense>
+ <Stateful />
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: initial</div>`
+ );
+
+ setState({ s: 'first' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense</div><div>Stateful: first</div>`
+ );
+
+ const [resolve] = suspend();
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspended...</div><div>Stateful: first</div>`
+ );
+
+ setState({ s: 'second' });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspended...</div><div>Stateful: second</div>`
+ );
+
+ return resolve(() => <div>Suspense 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Suspense 2</div><div>Stateful: second</div>`
+ );
+ });
+ });
+
+ it('should suspend with custom error boundary', () => {
+ const [Suspender, suspend] = createSuspender(() => (
+ <div>within error boundary</div>
+ ));
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Catcher>
+ <Suspender />
+ </Catcher>
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>within error boundary</div>`);
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>within error boundary 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>within error boundary 2</div>`);
+ });
+ });
+
+ it('should allow multiple sibling children to suspend', () => {
+ const [Suspender1, suspend1] = createSuspender(() => (
+ <div>Hello first</div>
+ ));
+ const [Suspender2, suspend2] = createSuspender(() => (
+ <div>Hello second</div>
+ ));
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Catcher>
+ <Suspender1 />
+ <Suspender2 />
+ </Catcher>
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Hello first</div><div>Hello second</div>`
+ );
+ expect(Suspender1.prototype.render).to.have.been.calledOnce;
+ expect(Suspender2.prototype.render).to.have.been.calledOnce;
+
+ const [resolve1] = suspend1();
+ const [resolve2] = suspend2();
+ expect(Suspender1.prototype.render).to.have.been.calledOnce;
+ expect(Suspender2.prototype.render).to.have.been.calledOnce;
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(Suspender1.prototype.render).to.have.been.calledTwice;
+ expect(Suspender2.prototype.render).to.have.been.calledTwice;
+
+ return resolve1(() => <div>Hello first 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(Suspender1.prototype.render).to.have.been.calledTwice;
+ expect(Suspender2.prototype.render).to.have.been.calledTwice;
+
+ return resolve2(() => <div>Hello second 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Hello first 2</div><div>Hello second 2</div>`
+ );
+ expect(Suspender1.prototype.render).to.have.been.calledThrice;
+ expect(Suspender2.prototype.render).to.have.been.calledThrice;
+ });
+ });
+ });
+
+ it('should call multiple nested sibling suspending components render in one go', () => {
+ const [Suspender1, suspend1] = createSuspender(() => (
+ <div>Hello first</div>
+ ));
+ const [Suspender2, suspend2] = createSuspender(() => (
+ <div>Hello second</div>
+ ));
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Catcher>
+ <Suspender1 />
+ <div>
+ <Suspender2 />
+ </div>
+ </Catcher>
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>Hello first</div><div><div>Hello second</div></div>`
+ );
+ expect(Suspender1.prototype.render).to.have.been.calledOnce;
+ expect(Suspender2.prototype.render).to.have.been.calledOnce;
+
+ const [resolve1] = suspend1();
+ const [resolve2] = suspend2();
+ expect(Suspender1.prototype.render).to.have.been.calledOnce;
+ expect(Suspender2.prototype.render).to.have.been.calledOnce;
+
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(Suspender1.prototype.render).to.have.been.calledTwice;
+ expect(Suspender2.prototype.render).to.have.been.calledTwice;
+
+ return resolve1(() => <div>Hello first 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+ expect(Suspender1.prototype.render).to.have.been.calledTwice;
+ expect(Suspender2.prototype.render).to.have.been.calledTwice;
+
+ return resolve2(() => <div>Hello second 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Hello first 2</div><div><div>Hello second 2</div></div>`
+ );
+ expect(Suspender1.prototype.render).to.have.been.calledThrice;
+ expect(Suspender2.prototype.render).to.have.been.calledThrice;
+ });
+ });
+ });
+
+ it('should support text directly under Suspense', () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ Text
+ {/* Adding a <div> here will make things work... */}
+ <Suspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`Text<div>Hello</div>`);
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Hello 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`Text<div>Hello 2</div>`);
+ });
+ });
+
+ it('should support to change DOM tag directly under suspense', () => {
+ /** @type {(state: {tag: string}) => void} */
+ let setState;
+ class StatefulComp extends Component {
+ constructor(props) {
+ super(props);
+ setState = this.setState.bind(this);
+ this.state = {
+ tag: props.defaultTag
+ };
+ }
+ render(props, { tag: Tag }) {
+ return <Tag>Stateful</Tag>;
+ }
+ }
+
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <StatefulComp defaultTag="div" />
+ <Suspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>Stateful</div><div>Hello</div>`);
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ setState({ tag: 'article' });
+
+ return resolve(() => <div>Hello 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<article>Stateful</article><div>Hello 2</div>`
+ );
+ });
+ });
+
+ it('should only suspend the most inner Suspend', () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended... 1</div>}>
+ Not suspended...
+ <Suspense fallback={<div>Suspended... 2</div>}>
+ <Catcher>
+ <Suspender />
+ </Catcher>
+ </Suspense>
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`Not suspended...<div>Hello</div>`);
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `Not suspended...<div>Suspended... 2</div>`
+ );
+
+ return resolve(() => <div>Hello 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`Not suspended...<div>Hello 2</div>`);
+ });
+ });
+
+ it('should throw when missing Suspense', () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Catcher>
+ <Suspender />
+ </Catcher>,
+ scratch
+ );
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Hello</div>`);
+
+ suspend();
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Catcher did catch: {Promise}</div>`);
+ });
+
+ it("should throw when lazy's loader throws", () => {
+ /** @type {() => Promise<any>} */
+ let reject;
+ const ThrowingLazy = lazy(() => {
+ const prom = new Promise((res, rej) => {
+ reject = () => {
+ rej(new Error("Thrown in lazy's loader..."));
+ return prom;
+ };
+ });
+
+ return prom;
+ });
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Catcher>
+ <ThrowingLazy />
+ </Catcher>
+ </Suspense>,
+ scratch
+ );
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return reject().then(
+ () => {
+ expect.fail('Suspended promises resolved instead of rejected.');
+ },
+ () => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<div>Catcher did catch: Thrown in lazy's loader...</div>`
+ );
+ }
+ );
+ });
+
+ it('should support null fallback', () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <div id="wrapper">
+ <Suspense fallback={null}>
+ <div id="inner">
+ <Suspender />
+ </div>
+ </Suspense>
+ </div>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ `<div id="wrapper"><div id="inner"><div>Hello</div></div></div>`
+ );
+
+ const [resolve] = suspend();
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div id="wrapper"></div>`);
+
+ return resolve(() => <div>Hello2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ `<div id="wrapper"><div id="inner"><div>Hello2</div></div></div>`
+ );
+ });
+ });
+
+ it('should support suspending multiple times', () => {
+ const [Suspender, suspend] = createSuspender(() => (
+ <div>initial render</div>
+ ));
+ const Loading = () => <div>Suspended...</div>;
+
+ render(
+ <Suspense fallback={<Loading />}>
+ <Suspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>initial render</div>`);
+
+ let [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Hello1</div>)
+ .then(() => {
+ // Rerender promise resolution
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Hello1</div>`);
+
+ // suspend again
+ [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ return resolve(() => <div>Hello2</div>);
+ })
+ .then(() => {
+ // Rerender promise resolution
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>Hello2</div>`);
+ });
+ });
+
+ it("should correctly render when a suspended component's child also suspends", () => {
+ const [Suspender1, suspend1] = createSuspender(() => <div>Hello1</div>);
+ const [LazyChild, resolveChild] = createLazy();
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Suspender1 />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(`<div>Hello1</div>`);
+
+ let [resolve1] = suspend1();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolve1(() => <LazyChild />)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolveChild(() => <div>All done!</div>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>All done!</div>');
+ });
+ });
+
+ it('should correctly render nested Suspense components', () => {
+ // Inspired by the nested-suspense demo from #1865
+ // TODO: Explore writing a test that varies the loading orders
+
+ const [Lazy1, resolve1] = createLazy();
+ const [Lazy2, resolve2] = createLazy();
+ const [Lazy3, resolve3] = createLazy();
+
+ const Loading = () => <div>Suspended...</div>;
+ const loadingHtml = `<div>Suspended...</div>`;
+
+ render(
+ <Suspense fallback={<Loading />}>
+ <Lazy1 />
+ <div>
+ <Suspense fallback={<Loading />}>
+ <Lazy2 />
+ </Suspense>
+ <Lazy3 />
+ </div>
+ <b>4</b>
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Rerender with the fallback HTML
+
+ expect(scratch.innerHTML).to.equal(loadingHtml);
+
+ return resolve1(() => <b>1</b>)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(loadingHtml);
+
+ return resolve3(() => <b>3</b>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ `<b>1</b><div>${loadingHtml}<b>3</b></div><b>4</b>`
+ );
+
+ return resolve2(() => <b>2</b>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ `<b>1</b><div><b>2</b><b>3</b></div><b>4</b>`
+ );
+ });
+ });
+
+ it('should correctly render nested Suspense components without intermediate DOM #2747', () => {
+ const [ProfileDetails, resolveDetails] = createLazy();
+ const [ProfileTimeline, resolveTimeline] = createLazy();
+
+ function ProfilePage() {
+ return (
+ <Suspense fallback={<h1>Loading profile...</h1>}>
+ <ProfileDetails />
+ <Suspense fallback={<h2>Loading posts...</h2>}>
+ <ProfileTimeline />
+ </Suspense>
+ </Suspense>
+ );
+ }
+
+ render(<ProfilePage />, scratch);
+ rerender(); // Render fallback
+
+ expect(scratch.innerHTML).to.equal('<h1>Loading profile...</h1>');
+
+ return resolveDetails(() => <h1>Ringo Starr</h1>)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<h1>Ringo Starr</h1><h2>Loading posts...</h2>'
+ );
+
+ return resolveTimeline(() => <p>Timeline details</p>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<h1>Ringo Starr</h1><p>Timeline details</p>'
+ );
+ });
+ });
+
+ it('should correctly render Suspense components inside Fragments', () => {
+ // Issue #2106.
+
+ const [Lazy1, resolve1] = createLazy();
+ const [Lazy2, resolve2] = createLazy();
+ const [Lazy3, resolve3] = createLazy();
+
+ const Loading = () => <div>Suspended...</div>;
+ const loadingHtml = `<div>Suspended...</div>`;
+
+ render(
+ <Fragment>
+ <Suspense fallback={<Loading />}>
+ <Lazy1 />
+ </Suspense>
+ <Fragment>
+ <Suspense fallback={<Loading />}>
+ <Lazy2 />
+ </Suspense>
+ </Fragment>
+ <Suspense fallback={<Loading />}>
+ <Lazy3 />
+ </Suspense>
+ </Fragment>,
+ scratch
+ );
+
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `${loadingHtml}${loadingHtml}${loadingHtml}`
+ );
+
+ return resolve2(() => <span>2</span>)
+ .then(() => {
+ return resolve1(() => <span>1</span>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>1</span><span>2</span>${loadingHtml}`
+ );
+ return resolve3(() => <span>3</span>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ `<span>1</span><span>2</span><span>3</span>`
+ );
+ });
+ });
+
+ it('should not render any of the children if one child suspends', () => {
+ const [Lazy, resolve] = createLazy();
+
+ const Loading = () => <div>Suspended...</div>;
+ const loadingHtml = `<div>Suspended...</div>`;
+
+ render(
+ <Suspense fallback={<Loading />}>
+ <Lazy />
+ <div>World</div>
+ </Suspense>,
+ scratch
+ );
+ rerender();
+ expect(scratch.innerHTML).to.eql(loadingHtml);
+
+ return resolve(() => <div>Hello</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div>Hello</div><div>World</div>`);
+ });
+ });
+
+ it('should render correctly when multiple children suspend with the same promise', () => {
+ /** @type {() => Promise<void>} */
+ let resolve;
+ let resolved = false;
+ const promise = new Promise(_resolve => {
+ resolve = () => {
+ resolved = true;
+ _resolve();
+ return promise;
+ };
+ });
+
+ const Child = props => {
+ if (!resolved) {
+ throw promise;
+ }
+ return props.children;
+ };
+
+ const Loading = () => <div>Suspended...</div>;
+ const loadingHtml = `<div>Suspended...</div>`;
+
+ render(
+ <Suspense fallback={<Loading />}>
+ <Child>
+ <div>A</div>
+ </Child>
+ <Child>
+ <div>B</div>
+ </Child>
+ </Suspense>,
+ scratch
+ );
+ rerender();
+ expect(scratch.innerHTML).to.eql(loadingHtml);
+
+ return resolve().then(() => {
+ resolved = true;
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div>A</div><div>B</div>`);
+ });
+ });
+
+ it('should un-suspend when suspender unmounts', () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Suspender</div>);
+
+ let hide;
+
+ class Conditional extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: true };
+
+ hide = () => {
+ this.setState({ show: false });
+ };
+ }
+
+ render(props, { show }) {
+ return (
+ <div>
+ conditional {show ? 'show' : 'hide'}
+ {show && <Suspender />}
+ </div>
+ );
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Conditional />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div>conditional show<div>Suspender</div></div>`
+ );
+ expect(Suspender.prototype.render).to.have.been.calledOnce;
+
+ suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ hide();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>conditional hide</div>`);
+ });
+
+ it('should allow suspended multiple times', async () => {
+ const [Suspender1, suspend1] = createSuspender(() => (
+ <div>Suspender 1</div>
+ ));
+ const [Suspender2, suspend2] = createSuspender(() => (
+ <div>Suspender 2</div>
+ ));
+
+ let hide, resolve;
+
+ class Conditional extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: true };
+
+ hide = () => {
+ this.setState({ show: false });
+ };
+ }
+
+ render(props, { show }) {
+ return (
+ <div>
+ conditional {show ? 'show' : 'hide'}
+ {show && (
+ <Suspense fallback="Suspended">
+ <Suspender1 />
+ <Suspender2 />
+ </Suspense>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<Conditional />, scratch);
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Suspender 1</div><div>Suspender 2</div></div>'
+ );
+
+ resolve = suspend1()[0];
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional showSuspended</div>');
+
+ await resolve(() => <div>Done 1</div>);
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Done 1</div><div>Suspender 2</div></div>'
+ );
+
+ resolve = suspend2()[0];
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional showSuspended</div>');
+
+ await resolve(() => <div>Done 2</div>);
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Done 1</div><div>Done 2</div></div>'
+ );
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional hide</div>');
+ });
+
+ it('should allow same component to be suspended multiple times', async () => {
+ const cache = { '1': true };
+ function Lazy({ value }) {
+ if (!cache[value]) {
+ throw new Promise(resolve => {
+ cache[value] = resolve;
+ });
+ }
+ return <div>{`Lazy ${value}`}</div>;
+ }
+
+ let hide, setValue;
+
+ class Conditional extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: true, value: '1' };
+
+ hide = () => {
+ this.setState({ show: false });
+ };
+ setValue = value => {
+ this.setState({ value });
+ };
+ }
+
+ render(props, { show, value }) {
+ return (
+ <div>
+ conditional {show ? 'show' : 'hide'}
+ {show && (
+ <Suspense fallback="Suspended">
+ <Lazy value={value} />
+ </Suspense>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<Conditional />, scratch);
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Lazy 1</div></div>'
+ );
+
+ setValue('2');
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<div>conditional showSuspended</div>');
+
+ await cache[2]();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Lazy 2</div></div>'
+ );
+
+ setValue('3');
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<div>conditional showSuspended</div>');
+
+ await cache[3]();
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Lazy 3</div></div>'
+ );
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional hide</div>');
+ });
+
+ it('should allow resolve suspense promise after unmounts', async () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Suspender</div>);
+
+ let hide, resolve;
+
+ class Conditional extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: true };
+
+ hide = () => {
+ this.setState({ show: false });
+ };
+ }
+
+ render(props, { show }) {
+ return (
+ <div>
+ conditional {show ? 'show' : 'hide'}
+ {show && (
+ <Suspense fallback="Suspended">
+ <Suspender />
+ </Suspense>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<Conditional />, scratch);
+ expect(scratch.innerHTML).to.eql(
+ '<div>conditional show<div>Suspender</div></div>'
+ );
+
+ resolve = suspend()[0];
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional showSuspended</div>');
+
+ hide();
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional hide</div>');
+
+ await resolve(() => <div>Done</div>);
+ rerender();
+ expect(scratch.innerHTML).to.eql('<div>conditional hide</div>');
+ });
+
+ it('should support updating state while suspended', async () => {
+ const [Suspender, suspend] = createSuspender(() => <div>Suspender</div>);
+
+ let increment;
+
+ class Updater extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { i: 0 };
+
+ increment = () => {
+ this.setState(({ i }) => ({ i: i + 1 }));
+ };
+ }
+
+ render(props, { i }) {
+ return (
+ <div>
+ i: {i}
+ <Suspender />
+ </div>
+ );
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Updater />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>i: 0<div>Suspender</div></div>`);
+ expect(Suspender.prototype.render).to.have.been.calledOnce;
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ await resolve(() => <div>Resolved</div>);
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(`<div>i: 1<div>Resolved</div></div>`);
+
+ increment();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(`<div>i: 2<div>Resolved</div></div>`);
+ });
+
+ it('should call componentWillUnmount on a suspended component', () => {
+ const cWUSpy = sinon.spy();
+
+ // eslint-disable-next-line react/require-render-return
+ class Suspender extends Component {
+ render() {
+ throw new Promise(() => {});
+ }
+ }
+
+ Suspender.prototype.componentWillUnmount = cWUSpy;
+
+ let hide;
+
+ let suspender = null;
+ let suspenderRef = s => {
+ // skip null values as we want to keep the ref even after unmount
+ if (s) {
+ suspender = s;
+ }
+ };
+
+ class Conditional extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: true };
+
+ hide = () => {
+ this.setState({ show: false });
+ };
+ }
+
+ render(props, { show }) {
+ return (
+ <div>
+ conditional {show ? 'show' : 'hide'}
+ {show && <Suspender ref={suspenderRef} />}
+ </div>
+ );
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Conditional />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div>conditional show</div>`);
+ expect(cWUSpy).to.not.have.been.called;
+
+ hide();
+ rerender();
+
+ expect(cWUSpy).to.have.been.calledOnce;
+ expect(suspender).not.to.be.undefined;
+ expect(suspender).not.to.be.null;
+ expect(cWUSpy.getCall(0).thisValue).to.eql(suspender);
+ expect(scratch.innerHTML).to.eql(`<div>conditional hide</div>`);
+ });
+
+ it('should support sCU=false when un-suspending', () => {
+ // See #2176 #2125
+ const [Suspender, suspend] = createSuspender(() => <div>Hello</div>);
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ Text
+ {/* Adding a <div> here will make things work... */}
+ <Suspender />
+ </Suspense>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`Text<div>Hello</div>`);
+
+ const [resolve] = suspend();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
+
+ Suspender.prototype.shouldComponentUpdate = () => false;
+
+ return resolve(() => <div>Hello 2</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`Text<div>Hello 2</div>`);
+ });
+ });
+
+ // TODO: Revisit later. Consider using an "options.commit" plugin to detect
+ // when a suspended component has rerendered and trigger a rerender on the
+ // parent Suspense
+ it.skip('should allow suspended children to update', () => {
+ const log = [];
+ class Logger extends Component {
+ constructor(props) {
+ super(props);
+ log.push('construct');
+ }
+
+ render({ children }) {
+ log.push('render');
+ return children;
+ }
+ }
+
+ let suspender;
+ class Suspender extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { promise: new Promise(() => {}) };
+ suspender = this;
+ }
+
+ unsuspend() {
+ this.setState({ promise: null });
+ }
+
+ render() {
+ if (this.state.promise) {
+ throw this.state.promise;
+ }
+
+ return <div>Suspender un-suspended</div>;
+ }
+ }
+
+ render(
+ <section>
+ <Suspense fallback={<div>fallback</div>}>
+ <Suspender />
+ <Logger />
+ </Suspense>
+ </section>,
+ scratch
+ );
+
+ expect(log).to.eql(['construct', 'render']);
+ expect(scratch.innerHTML).to.eql('<section></section>');
+
+ // this rerender is needed because of Suspense issuing a forceUpdate itself
+ rerender();
+ expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');
+
+ suspender.unsuspend();
+
+ rerender();
+
+ expect(log).to.eql(['construct', 'render', 'render']);
+ expect(scratch.innerHTML).to.eql(
+ '<section><div>Suspender un-suspended</div></section>'
+ );
+ });
+
+ // TODO: Revisit later. Consider using an "options.commit" plugin to detect
+ // when a suspended component has rerendered and trigger a rerender on the
+ // parent Suspense
+ it.skip('should allow multiple suspended children to update', () => {
+ function createSuspender() {
+ let suspender;
+ class Suspender extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { promise: new Promise(() => {}) };
+ suspender = this;
+ }
+
+ unsuspend(content) {
+ this.setState({ promise: null, content });
+ }
+
+ render() {
+ if (this.state.promise) {
+ throw this.state.promise;
+ }
+
+ return this.state.content;
+ }
+ }
+ return [content => suspender.unsuspend(content), Suspender];
+ }
+
+ const [unsuspender1, Suspender1] = createSuspender();
+ const [unsuspender2, Suspender2] = createSuspender();
+
+ render(
+ <section>
+ <Suspense fallback={<div>fallback</div>}>
+ <Suspender1 />
+ <div>
+ <Suspender2 />
+ </div>
+ </Suspense>
+ </section>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql('<section><div></div></section>');
+
+ // this rerender is needed because of Suspense issuing a forceUpdate itself
+ rerender();
+ expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');
+
+ unsuspender1(
+ <>
+ <div>Suspender un-suspended 1</div>
+ <div>Suspender un-suspended 2</div>
+ </>
+ );
+
+ rerender();
+ expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');
+
+ unsuspender2(<div>Suspender 2</div>);
+
+ rerender();
+ expect(scratch.innerHTML).to.eql(
+ '<section><div>Suspender un-suspended 1</div><div>Suspender un-suspended 2</div><div><div>Suspender 2</div></div></section>'
+ );
+ });
+
+ // TODO: Revisit later. Consider using an "options.commit" plugin to detect
+ // when a suspended component has rerendered and trigger a rerender on the
+ // parent Suspense
+ it.skip('should allow suspended children children to update', () => {
+ function Suspender({ promise, content }) {
+ if (promise) {
+ throw promise;
+ }
+ return content;
+ }
+
+ let parent;
+ class Parent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { promise: new Promise(() => {}), condition: true };
+ parent = this;
+ }
+
+ render() {
+ const { condition, promise, content } = this.state;
+ if (condition) {
+ return <Suspender promise={promise} content={content} />;
+ }
+ return <div>Parent</div>;
+ }
+ }
+
+ render(
+ <section>
+ <Suspense fallback={<div>fallback</div>}>
+ <Parent />
+ </Suspense>
+ </section>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql('<section></section>');
+
+ // this rerender is needed because of Suspense issuing a forceUpdate itself
+ rerender();
+ expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');
+
+ // hide the <Suspender /> thus unsuspends
+ parent.setState({ condition: false });
+
+ rerender();
+ expect(scratch.innerHTML).to.eql('<section><div>Parent</div></section>');
+
+ // show the <Suspender /> thus re-suspends
+ parent.setState({ condition: true });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<section><div>fallback</div></section>');
+
+ // update state so that <Suspender /> no longer suspends
+ parent.setState({ promise: null, content: <div>Content</div> });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<section><div>Content</div></section>');
+
+ // hide the <Suspender /> again
+ parent.setState({ condition: false });
+ rerender();
+
+ expect(scratch.innerHTML).to.eql('<section><div>Parent</div></section>');
+ });
+
+ it('should render delayed lazy components through components using shouldComponentUpdate', () => {
+ const [Suspender1, suspend1] = createSuspender(() => <i>1</i>);
+ const [Suspender2, suspend2] = createSuspender(() => <i>2</i>);
+
+ class Blocker extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render(props) {
+ return (
+ <b>
+ <i>a</i>
+ {props.children}
+ <i>d</i>
+ </b>
+ );
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Blocker>
+ <Suspender1 />
+ <Suspender2 />
+ </Blocker>
+ </Suspense>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<b><i>a</i><i>1</i><i>2</i><i>d</i></b>'
+ );
+
+ const [resolve1] = suspend1();
+ const [resolve2] = suspend2();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolve1(() => <i>b</i>)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolve2(() => <i>c</i>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<b><i>a</i><i>b</i><i>c</i><i>d</i></b>'
+ );
+ });
+ });
+
+ it('should render initially lazy components through components using shouldComponentUpdate', () => {
+ const [Lazy1, resolve1] = createLazy();
+ const [Lazy2, resolve2] = createLazy();
+
+ class Blocker extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render(props) {
+ return (
+ <b>
+ <i>a</i>
+ {props.children}
+ <i>d</i>
+ </b>
+ );
+ }
+ }
+
+ render(
+ <Suspense fallback={<div>Suspended...</div>}>
+ <Blocker>
+ <Lazy1 />
+ <Lazy2 />
+ </Blocker>
+ </Suspense>,
+ scratch
+ );
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolve1(() => <i>b</i>)
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>Suspended...</div>');
+
+ return resolve2(() => <i>c</i>);
+ })
+ .then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<b><i>a</i><i>b</i><i>c</i><i>d</i></b>'
+ );
+ });
+ });
+
+ it('should render initially lazy components through createContext', () => {
+ const ctx = createContext(null);
+ const [Lazy, resolve] = createLazy();
+
+ const suspense = (
+ <Suspense fallback={<div>Suspended...</div>}>
+ <ctx.Provider value="123">
+ <ctx.Consumer>{value => <Lazy value={value} />}</ctx.Consumer>
+ </ctx.Provider>
+ </Suspense>
+ );
+
+ render(suspense, scratch);
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div>Suspended...</div>`);
+
+ return resolve(props => <div>{props.value}</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>123</div>`);
+ });
+ });
+
+ it('should render delayed lazy components through createContext', () => {
+ const ctx = createContext(null);
+ const [Suspender, suspend] = createSuspender(({ value }) => (
+ <span>{value}</span>
+ ));
+
+ const suspense = (
+ <Suspense fallback={<div>Suspended...</div>}>
+ <ctx.Provider value="123">
+ <ctx.Consumer>{value => <Suspender value={value} />}</ctx.Consumer>
+ </ctx.Provider>
+ </Suspense>
+ );
+
+ render(suspense, scratch);
+ expect(scratch.innerHTML).to.equal('<span>123</span>');
+
+ const [resolve] = suspend();
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div>Suspended...</div>`);
+
+ return resolve(props => <div>{props.value}</div>).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.eql(`<div>123</div>`);
+ });
+ });
+});
diff --git a/preact/compat/test/browser/svg.test.js b/preact/compat/test/browser/svg.test.js
new file mode 100644
index 0000000..3b45859
--- /dev/null
+++ b/preact/compat/test/browser/svg.test.js
@@ -0,0 +1,94 @@
+import React, { createElement } from 'preact/compat';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml,
+ sortAttributes
+} from '../../../test/_util/helpers';
+
+describe('svg', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should render SVG to string', () => {
+ let svg = (
+ <svg viewBox="0 0 360 360">
+ <path
+ stroke="white"
+ fill="black"
+ d="M347.1 357.9L183.3 256.5 13 357.9V1.7h334.1v356.2zM58.5 47.2v231.4l124.8-74.1 118.3 72.8V47.2H58.5z"
+ />
+ </svg>
+ );
+ // string -> parse
+ expect(svg).to.eql(svg);
+ });
+
+ it('should render SVG to DOM #1', () => {
+ const Demo = () => (
+ <svg viewBox="0 0 360 360">
+ <path
+ stroke="white"
+ fill="black"
+ d="M347.1 357.9L183.3 256.5 L 13 357.9V1.7h334.1v356.2zM58.5 47.2v231.4l124.8-74.1 l 118.3 72.8V47.2H58.5z"
+ />
+ </svg>
+ );
+ React.render(<Demo />, scratch);
+
+ expect(serializeHtml(scratch)).to.equal(
+ sortAttributes(
+ '<svg viewBox="0 0 360 360"><path stroke="white" fill="black" d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"></path></svg>'
+ )
+ );
+ });
+
+ it('should render SVG to DOM #2', () => {
+ React.render(
+ <svg viewBox="0 0 100 100">
+ <text textAnchor="mid">foo</text>
+ <path vectorEffect="non-scaling-stroke" d="M0 0 L100 100" />
+ </svg>,
+ scratch
+ );
+
+ expect(serializeHtml(scratch)).to.equal(
+ sortAttributes(
+ '<svg viewBox="0 0 100 100"><text text-anchor="mid">foo</text><path vector-effect="non-scaling-stroke" d="M 0 0 L 100 100"></path></svg>'
+ )
+ );
+ });
+
+ it('should render correct SVG attribute names to the DOM', () => {
+ React.render(
+ <svg
+ clipPath="value"
+ clipRule="value"
+ clipPathUnits="value"
+ glyphOrientationHorizontal="value"
+ glyphRef="value"
+ markerStart="value"
+ markerHeight="value"
+ markerUnits="value"
+ markerWidth="value"
+ x1="value"
+ xChannelSelector="value"
+ />,
+ scratch
+ );
+
+ expect(serializeHtml(scratch)).to.eql(
+ sortAttributes(
+ '<svg clip-path="value" clip-rule="value" clipPathUnits="value" glyph-orientationhorizontal="value" glyphRef="value" marker-start="value" markerHeight="value" markerUnits="value" markerWidth="value" x1="value" xChannelSelector="value"></svg>'
+ )
+ );
+ });
+});
diff --git a/preact/compat/test/browser/testUtils.js b/preact/compat/test/browser/testUtils.js
new file mode 100644
index 0000000..04ed784
--- /dev/null
+++ b/preact/compat/test/browser/testUtils.js
@@ -0,0 +1,24 @@
+/**
+ * Retrieve a Symbol if supported or use the fallback value
+ * @param {string} name The name of the Symbol to look up
+ * @param {number} fallback Fallback value if Symbols are not supported
+ */
+export function getSymbol(name, fallback) {
+ let out = fallback;
+
+ try {
+ // eslint-disable-next-line
+ if (
+ Function.prototype.toString
+ .call(eval('Symbol.for'))
+ .match(/\[native code\]/)
+ ) {
+ // Concatenate these string literals to prevent the test
+ // harness and/or Babel from modifying the symbol value.
+ // eslint-disable-next-line
+ out = eval('Sym' + 'bol.for("' + name + '")');
+ }
+ } catch (e) {}
+
+ return out;
+}
diff --git a/preact/compat/test/browser/textarea.test.js b/preact/compat/test/browser/textarea.test.js
new file mode 100644
index 0000000..d1c114e
--- /dev/null
+++ b/preact/compat/test/browser/textarea.test.js
@@ -0,0 +1,64 @@
+import React, { render, useState } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { act } from 'preact/test-utils';
+
+describe('Textarea', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should alias value to children', () => {
+ render(<textarea value="foo" />, scratch);
+
+ expect(scratch.firstElementChild.value).to.equal('foo');
+ });
+
+ it('should alias defaultValue to children', () => {
+ // TODO: IE11 doesn't update `node.value` when
+ // `node.defaultValue` is set.
+ if (/Trident/.test(navigator.userAgent)) return;
+
+ render(<textarea defaultValue="foo" />, scratch);
+
+ expect(scratch.firstElementChild.value).to.equal('foo');
+ });
+
+ it('should support resetting the value', () => {
+ let set;
+ const App = () => {
+ const [state, setState] = useState('');
+ set = setState;
+ return <textarea value={state} />;
+ };
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<textarea></textarea>');
+
+ act(() => {
+ set('hello');
+ });
+ // Note: This looks counterintuitive, but it's working correctly - the value
+ // missing from HTML because innerHTML doesn't serialize form field values.
+ // See demo: https://jsfiddle.net/4had2Lu8
+ // Related renderToString PR: preactjs/preact-render-to-string#161
+ //
+ // This is not true for IE11. It displays the value in
+ // node.innerHTML regardless.
+ if (!/Trident/.test(window.navigator.userAgent)) {
+ expect(scratch.innerHTML).to.equal('<textarea></textarea>');
+ }
+ expect(scratch.firstElementChild.value).to.equal('hello');
+
+ act(() => {
+ set('');
+ });
+ expect(scratch.innerHTML).to.equal('<textarea></textarea>');
+ expect(scratch.firstElementChild.value).to.equal('');
+ });
+});
diff --git a/preact/compat/test/browser/unmountComponentAtNode.test.js b/preact/compat/test/browser/unmountComponentAtNode.test.js
new file mode 100644
index 0000000..bcf87df
--- /dev/null
+++ b/preact/compat/test/browser/unmountComponentAtNode.test.js
@@ -0,0 +1,28 @@
+import React, { createElement, unmountComponentAtNode } from 'preact/compat';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('unmountComponentAtNode', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should unmount a root node', () => {
+ const App = () => <div>foo</div>;
+ React.render(<App />, scratch);
+
+ expect(unmountComponentAtNode(scratch)).to.equal(true);
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should do nothing if root is not mounted', () => {
+ expect(unmountComponentAtNode(scratch)).to.equal(false);
+ expect(scratch.innerHTML).to.equal('');
+ });
+});
diff --git a/preact/compat/test/browser/unstable_batchedUpdates.test.js b/preact/compat/test/browser/unstable_batchedUpdates.test.js
new file mode 100644
index 0000000..61b2e8a
--- /dev/null
+++ b/preact/compat/test/browser/unstable_batchedUpdates.test.js
@@ -0,0 +1,15 @@
+import { unstable_batchedUpdates } from 'preact/compat';
+
+describe('unstable_batchedUpdates', () => {
+ it('should call the callback', () => {
+ const spy = sinon.spy();
+ unstable_batchedUpdates(spy);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should call callback with only one arg', () => {
+ const spy = sinon.spy();
+ unstable_batchedUpdates(spy, 'foo', 'bar');
+ expect(spy).to.be.calledWithExactly('foo');
+ });
+});
diff --git a/preact/compat/test/ts/forward-ref.tsx b/preact/compat/test/ts/forward-ref.tsx
new file mode 100644
index 0000000..9a920cb
--- /dev/null
+++ b/preact/compat/test/ts/forward-ref.tsx
@@ -0,0 +1,26 @@
+import React from '../../src';
+
+const MyInput: React.ForwardFn<{ id: string }, { focus(): void }> = (
+ props,
+ ref
+) => {
+ const inputRef = React.useRef<HTMLInputElement>(null);
+
+ React.useImperativeHandle(ref, () => ({
+ focus: () => {
+ if (inputRef.current) {
+ inputRef.current.focus();
+ }
+ }
+ }));
+
+ return <input {...props} ref={inputRef} />;
+};
+
+export const foo = React.forwardRef(MyInput);
+
+export const Bar = React.forwardRef<HTMLDivElement, { children: any }>(
+ (props, ref) => {
+ return <div ref={ref}>{props.children}</div>;
+ }
+);
diff --git a/preact/compat/test/ts/lazy.tsx b/preact/compat/test/ts/lazy.tsx
new file mode 100644
index 0000000..b3797c1
--- /dev/null
+++ b/preact/compat/test/ts/lazy.tsx
@@ -0,0 +1,17 @@
+import * as React from '../../src';
+
+export interface LazyProps {
+ isProp: boolean;
+}
+
+interface LazyState {
+ forState: string;
+}
+export default class IsLazyComponent extends React.Component<
+ LazyProps,
+ LazyState
+> {
+ render({ isProp }: LazyProps) {
+ return <div>{isProp ? 'Super Lazy TRUE' : 'Super Lazy FALSE'}</div>;
+ }
+}
diff --git a/preact/compat/test/ts/memo.tsx b/preact/compat/test/ts/memo.tsx
new file mode 100644
index 0000000..4e89e26
--- /dev/null
+++ b/preact/compat/test/ts/memo.tsx
@@ -0,0 +1,56 @@
+import * as React from '../../src';
+import { expectType } from './utils';
+
+interface MemoProps {
+ required: string;
+ optional?: string;
+ defaulted: string;
+}
+
+interface MemoPropsExceptDefaults {
+ required: string;
+ optional?: string;
+}
+
+const ComponentExceptDefaults = () => <div></div>;
+
+const ReadonlyBaseComponent = (props: Readonly<MemoProps>) => (
+ <div>{props.required + props.optional + props.defaulted}</div>
+);
+ReadonlyBaseComponent.defaultProps = { defaulted: '' };
+
+const BaseComponent = (props: MemoProps) => (
+ <div>{props.required + props.optional + props.defaulted}</div>
+);
+BaseComponent.defaultProps = { defaulted: '' };
+
+// memo for readonly component with default comparison
+const MemoedReadonlyComponent = React.memo(ReadonlyBaseComponent);
+expectType<React.FunctionComponent<MemoProps>>(MemoedReadonlyComponent);
+export const memoedReadonlyComponent = (
+ <MemoedReadonlyComponent required="hi" />
+);
+
+// memo for non-readonly component with default comparison
+const MemoedComponent = React.memo(BaseComponent);
+expectType<React.FunctionComponent<MemoProps>>(MemoedComponent);
+export const memoedComponent = <MemoedComponent required="hi" />;
+
+// memo with custom comparison
+const CustomMemoedComponent = React.memo(BaseComponent, (a, b) => {
+ expectType<MemoProps>(a);
+ expectType<MemoProps>(b);
+ return a.required === b.required;
+});
+expectType<React.FunctionComponent<MemoProps>>(CustomMemoedComponent);
+export const customMemoedComponent = <CustomMemoedComponent required="hi" />;
+
+const MemoedComponentExceptDefaults = React.memo<MemoPropsExceptDefaults>(
+ ComponentExceptDefaults
+);
+expectType<React.FunctionComponent<MemoPropsExceptDefaults>>(
+ MemoedComponentExceptDefaults
+);
+export const memoedComponentExceptDefaults = (
+ <MemoedComponentExceptDefaults required="hi" />
+);
diff --git a/preact/compat/test/ts/react-default.tsx b/preact/compat/test/ts/react-default.tsx
new file mode 100644
index 0000000..f46c0b4
--- /dev/null
+++ b/preact/compat/test/ts/react-default.tsx
@@ -0,0 +1,6 @@
+import React from '../../src';
+class ReactIsh extends React.Component {
+ render() {
+ return <div>Text</div>;
+ }
+}
diff --git a/preact/compat/test/ts/react-star.tsx b/preact/compat/test/ts/react-star.tsx
new file mode 100644
index 0000000..da82690
--- /dev/null
+++ b/preact/compat/test/ts/react-star.tsx
@@ -0,0 +1,7 @@
+// import React from '../../src';
+import * as React from '../../src';
+class ReactIsh extends React.Component {
+ render() {
+ return <div>Text</div>;
+ }
+}
diff --git a/preact/compat/test/ts/scheduler.ts b/preact/compat/test/ts/scheduler.ts
new file mode 100644
index 0000000..999e652
--- /dev/null
+++ b/preact/compat/test/ts/scheduler.ts
@@ -0,0 +1,19 @@
+import {
+ unstable_runWithPriority,
+ unstable_NormalPriority,
+ unstable_LowPriority,
+ unstable_IdlePriority,
+ unstable_UserBlockingPriority,
+ unstable_ImmediatePriority,
+ unstable_now
+} from '../../src';
+
+const noop = () => null;
+unstable_runWithPriority(unstable_IdlePriority, noop);
+unstable_runWithPriority(unstable_LowPriority, noop);
+unstable_runWithPriority(unstable_NormalPriority, noop);
+unstable_runWithPriority(unstable_UserBlockingPriority, noop);
+unstable_runWithPriority(unstable_ImmediatePriority, noop);
+
+if (typeof unstable_now() === 'number') {
+}
diff --git a/preact/compat/test/ts/suspense.tsx b/preact/compat/test/ts/suspense.tsx
new file mode 100644
index 0000000..916dd6b
--- /dev/null
+++ b/preact/compat/test/ts/suspense.tsx
@@ -0,0 +1,52 @@
+import * as React from '../../src';
+
+interface LazyProps {
+ isProp: boolean;
+}
+
+const IsLazyFunctional = (props: LazyProps) => (
+ <div>{props.isProp ? 'Super Lazy TRUE' : 'Super Lazy FALSE'}</div>
+);
+
+const FallBack = () => <div>Still working...</div>;
+/**
+ * Have to mock dynamic import as import() throws a syntax error in the test runner
+ */
+const componentPromise = new Promise<{ default: typeof IsLazyFunctional }>(
+ resolve => {
+ setTimeout(() => {
+ resolve({ default: IsLazyFunctional });
+ }, 800);
+ }
+);
+
+/**
+ * For usage with import:
+ * const IsLazyComp = lazy(() => import('./lazy'));
+ */
+const IsLazyFunc = React.lazy(() => componentPromise);
+
+// Suspense using lazy component
+class SuspensefulFunc extends React.Component {
+ render() {
+ return (
+ <React.Suspense fallback={<FallBack />}>
+ <IsLazyFunc isProp={false} />
+ </React.Suspense>
+ );
+ }
+}
+
+//SuspenseList using lazy components
+function SuspenseListTester(props: any) {
+ return (
+ <React.SuspenseList revealOrder="together">
+ <React.Suspense fallback={<FallBack />}>
+ <IsLazyFunc isProp={false} />
+ </React.Suspense>
+ <React.Suspense fallback={<FallBack />}>
+ <IsLazyFunc isProp={false} />
+ </React.Suspense>
+ </React.SuspenseList>
+ );
+}
diff --git a/preact/compat/test/ts/tsconfig.json b/preact/compat/test/ts/tsconfig.json
new file mode 100644
index 0000000..742a039
--- /dev/null
+++ b/preact/compat/test/ts/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "es6",
+ "moduleResolution": "node",
+ "lib": [
+ "es6",
+ "dom",
+ ],
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "noEmit": true,
+ "allowSyntheticDefaultImports": true
+ },
+ "include": [
+ "./**/*.ts",
+ "./**/*.tsx"
+ ]
+}
diff --git a/preact/compat/test/ts/utils.ts b/preact/compat/test/ts/utils.ts
new file mode 100644
index 0000000..16ec22d
--- /dev/null
+++ b/preact/compat/test/ts/utils.ts
@@ -0,0 +1,4 @@
+/**
+ * Assert the parameter is of a specific type.
+ */
+export const expectType = <T>(_: T): void => undefined;
diff --git a/preact/config/codemod-const.js b/preact/config/codemod-const.js
new file mode 100644
index 0000000..37eee5b
--- /dev/null
+++ b/preact/config/codemod-const.js
@@ -0,0 +1,43 @@
+/* eslint no-console:0 */
+
+/** Find constants (identified by ALL_CAPS_DECLARATIONS), and inline them globally.
+ * This is safe because Preact *only* uses global constants.
+ */
+export default (file, api) => {
+ let j = api.jscodeshift,
+ code = j(file.source),
+ constants = {},
+ found = 0;
+
+ code
+ .find(j.VariableDeclaration)
+ .filter(decl => {
+ for (let i = decl.value.declarations.length; i--; ) {
+ let node = decl.value.declarations[i],
+ name = node.id && node.id.name,
+ init = node.init;
+ if (name && init && name.match(/^[A-Z0-9_$]+$/g) && !init.regex) {
+ if (init.type === 'Literal') {
+ // console.log(`Inlining constant: ${name}=${init.raw}`);
+ found++;
+ constants[name] = init;
+ // remove declaration
+ decl.value.declarations.splice(i, 1);
+ // if it's the last, we'll remove the whole statement
+ return !decl.value.declarations.length;
+ }
+ }
+ }
+ return false;
+ })
+ .remove();
+
+ code
+ .find(j.Identifier)
+ .filter(
+ path => path.value.name && constants.hasOwnProperty(path.value.name)
+ )
+ .replaceWith(path => (found++, constants[path.value.name]));
+
+ return found ? code.toSource({ quote: 'single' }) : null;
+};
diff --git a/preact/config/codemod-let-name.js b/preact/config/codemod-let-name.js
new file mode 100644
index 0000000..5f69411
--- /dev/null
+++ b/preact/config/codemod-let-name.js
@@ -0,0 +1,16 @@
+/**
+ * Restores var names transformed by babel's let block scoping
+ */
+export default (file, api) => {
+ let j = api.jscodeshift;
+ let code = j(file.source);
+
+ // @TODO unsafe, but without it we gain 20b gzipped: https://www.diffchecker.com/bVrOJWTO
+ code
+ .findVariableDeclarators()
+ .filter(d => /^_i/.test(d.value.id.name))
+ .renameTo('i');
+ code.findVariableDeclarators('_key').renameTo('key');
+
+ return code.toSource({ quote: 'single' });
+};
diff --git a/preact/config/codemod-strip-tdz.js b/preact/config/codemod-strip-tdz.js
new file mode 100644
index 0000000..469c9c3
--- /dev/null
+++ b/preact/config/codemod-strip-tdz.js
@@ -0,0 +1,60 @@
+/* eslint no-console:0 */
+
+// parent node types that we don't want to remove pointless initializations from (because it breaks hoisting)
+const BLOCKED = ['ForStatement', 'WhileStatement']; // 'IfStatement', 'SwitchStatement'
+
+/** Removes var initialization to `void 0`, which Babel adds for TDZ strictness. */
+export default (file, api) => {
+ let { jscodeshift } = api,
+ found = 0;
+
+ let code = jscodeshift(file.source)
+ .find(jscodeshift.VariableDeclaration)
+ .forEach(handleDeclaration);
+
+ function handleDeclaration(decl) {
+ let p = decl,
+ remove = true;
+
+ while ((p = p.parentPath)) {
+ if (~BLOCKED.indexOf(p.value.type)) {
+ remove = false;
+ break;
+ }
+ }
+
+ decl.value.declarations.filter(isPointless).forEach(node => {
+ if (remove === false) {
+ console.log(
+ `> Skipping removal of undefined init for "${node.id.name}": within ${p.value.type}`
+ );
+ } else {
+ removeNodeInitialization(node);
+ }
+ });
+ }
+
+ function removeNodeInitialization(node) {
+ node.init = null;
+ found++;
+ }
+
+ function isPointless(node) {
+ let { init } = node;
+ if (init) {
+ if (
+ init.type === 'UnaryExpression' &&
+ init.operator === 'void' &&
+ init.argument.value == 0
+ ) {
+ return true;
+ }
+ if (init.type === 'Identifier' && init.name === 'undefined') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return found ? code.toSource({ quote: 'single' }) : null;
+};
diff --git a/preact/config/compat-entries.js b/preact/config/compat-entries.js
new file mode 100644
index 0000000..6fd771b
--- /dev/null
+++ b/preact/config/compat-entries.js
@@ -0,0 +1,25 @@
+const path = require('path');
+const fs = require('fs');
+const kl = require('kolorist');
+
+const pkgFiles = new Set(require('../package.json').files);
+const compatDir = path.join(__dirname, '..', 'compat');
+const files = fs.readdirSync(compatDir);
+
+let missing = 0;
+for (const file of files) {
+ const expected = 'compat/' + file;
+ if (/\.(js|mjs)$/.test(file) && !pkgFiles.has(expected)) {
+ missing++;
+
+ const filePath = kl.cyan('compat/' + file);
+ const label = kl.inverse(kl.red(' ERROR '));
+ console.error(
+ `${label} File ${filePath} is missing in "files" entry in package.json`
+ );
+ }
+}
+
+if (missing > 0) {
+ process.exit(1);
+}
diff --git a/preact/config/node-13-exports.js b/preact/config/node-13-exports.js
new file mode 100644
index 0000000..9528d2a
--- /dev/null
+++ b/preact/config/node-13-exports.js
@@ -0,0 +1,32 @@
+const fs = require('fs');
+
+const subRepositories = [
+ 'compat',
+ 'debug',
+ 'devtools',
+ 'hooks',
+ 'jsx-runtime',
+ 'test-utils'
+];
+const snakeCaseToCamelCase = str =>
+ str.replace(/([-_][a-z])/g, group => group.toUpperCase().replace('-', ''));
+
+const copyPreact = () => {
+ // Copy .module.js --> .mjs for Node 13 compat.
+ fs.writeFileSync(
+ `${process.cwd()}/dist/preact.mjs`,
+ fs.readFileSync(`${process.cwd()}/dist/preact.module.js`)
+ );
+};
+
+const copy = name => {
+ // Copy .module.js --> .mjs for Node 13 compat.
+ const filename = name.includes('-') ? snakeCaseToCamelCase(name) : name;
+ fs.writeFileSync(
+ `${process.cwd()}/${name}/dist/${filename}.mjs`,
+ fs.readFileSync(`${process.cwd()}/${name}/dist/${filename}.module.js`)
+ );
+};
+
+copyPreact();
+subRepositories.forEach(copy);
diff --git a/preact/debug/LICENSE b/preact/debug/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/debug/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/debug/mangle.json b/preact/debug/mangle.json
new file mode 100644
index 0000000..506a6a4
--- /dev/null
+++ b/preact/debug/mangle.json
@@ -0,0 +1,21 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/preact/debug/package.json b/preact/debug/package.json
new file mode 100644
index 0000000..bc6ef7b
--- /dev/null
+++ b/preact/debug/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "preact-debug",
+ "amdName": "preactDebug",
+ "version": "1.0.0",
+ "private": true,
+ "description": "Preact extensions for development",
+ "main": "dist/debug.js",
+ "module": "dist/debug.module.js",
+ "umd:main": "dist/debug.umd.js",
+ "source": "src/index.js",
+ "license": "MIT",
+ "mangle": {
+ "regex": "^(?!_renderer)^_"
+ },
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ }
+}
diff --git a/preact/debug/src/check-props.js b/preact/debug/src/check-props.js
new file mode 100644
index 0000000..6f48bbe
--- /dev/null
+++ b/preact/debug/src/check-props.js
@@ -0,0 +1,54 @@
+const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
+
+let loggedTypeFailures = {};
+
+/**
+ * Reset the history of which prop type warnings have been logged.
+ */
+export function resetPropWarnings() {
+ loggedTypeFailures = {};
+}
+
+/**
+ * Assert that the values match with the type specs.
+ * Error messages are memorized and will only be shown once.
+ *
+ * Adapted from https://github.com/facebook/prop-types/blob/master/checkPropTypes.js
+ *
+ * @param {object} typeSpecs Map of name to a ReactPropType
+ * @param {object} values Runtime values that need to be type-checked
+ * @param {string} location e.g. "prop", "context", "child context"
+ * @param {string} componentName Name of the component for error messages.
+ * @param {?Function} getStack Returns the component stack.
+ */
+export function checkPropTypes(
+ typeSpecs,
+ values,
+ location,
+ componentName,
+ getStack
+) {
+ Object.keys(typeSpecs).forEach(typeSpecName => {
+ let error;
+ try {
+ error = typeSpecs[typeSpecName](
+ values,
+ typeSpecName,
+ componentName,
+ location,
+ null,
+ ReactPropTypesSecret
+ );
+ } catch (e) {
+ error = e;
+ }
+ if (error && !(error.message in loggedTypeFailures)) {
+ loggedTypeFailures[error.message] = true;
+ console.error(
+ `Failed ${location} type: ${error.message}${(getStack &&
+ `\n${getStack()}`) ||
+ ''}`
+ );
+ }
+ });
+}
diff --git a/preact/debug/src/component-stack.js b/preact/debug/src/component-stack.js
new file mode 100644
index 0000000..58830ed
--- /dev/null
+++ b/preact/debug/src/component-stack.js
@@ -0,0 +1,146 @@
+import { options, Fragment } from 'preact';
+
+/**
+ * Get human readable name of the component/dom node
+ * @param {import('./internal').VNode} vnode
+ * @param {import('./internal').VNode} vnode
+ * @returns {string}
+ */
+export function getDisplayName(vnode) {
+ if (vnode.type === Fragment) {
+ return 'Fragment';
+ } else if (typeof vnode.type == 'function') {
+ return vnode.type.displayName || vnode.type.name;
+ } else if (typeof vnode.type == 'string') {
+ return vnode.type;
+ }
+
+ return '#text';
+}
+
+/**
+ * Used to keep track of the currently rendered `vnode` and print it
+ * in debug messages.
+ */
+let renderStack = [];
+
+/**
+ * Keep track of the current owners. An owner describes a component
+ * which was responsible to render a specific `vnode`. This exclude
+ * children that are passed via `props.children`, because they belong
+ * to the parent owner.
+ *
+ * ```jsx
+ * const Foo = props => <div>{props.children}</div> // div's owner is Foo
+ * const Bar = props => {
+ * return (
+ * <Foo><span /></Foo> // Foo's owner is Bar, span's owner is Bar
+ * )
+ * }
+ * ```
+ *
+ * Note: A `vnode` may be hoisted to the root scope due to compiler
+ * optimiztions. In these cases the `_owner` will be different.
+ */
+let ownerStack = [];
+
+/**
+ * Get the currently rendered `vnode`
+ * @returns {import('./internal').VNode | null}
+ */
+export function getCurrentVNode() {
+ return renderStack.length > 0 ? renderStack[renderStack.length - 1] : null;
+}
+
+/**
+ * If the user doesn't have `@babel/plugin-transform-react-jsx-source`
+ * somewhere in his tool chain we can't print the filename and source
+ * location of a component. In that case we just omit that, but we'll
+ * print a helpful message to the console, notifying the user of it.
+ */
+let hasBabelPlugin = false;
+
+/**
+ * Check if a `vnode` is a possible owner.
+ * @param {import('./internal').VNode} vnode
+ */
+function isPossibleOwner(vnode) {
+ return typeof vnode.type == 'function' && vnode.type != Fragment;
+}
+
+/**
+ * Return the component stack that was captured up to this point.
+ * @param {import('./internal').VNode} vnode
+ * @returns {string}
+ */
+export function getOwnerStack(vnode) {
+ const stack = [vnode];
+ let next = vnode;
+ while (next._owner != null) {
+ stack.push(next._owner);
+ next = next._owner;
+ }
+
+ return stack.reduce((acc, owner) => {
+ acc += ` in ${getDisplayName(owner)}`;
+
+ const source = owner.__source;
+ if (source) {
+ acc += ` (at ${source.fileName}:${source.lineNumber})`;
+ } else if (!hasBabelPlugin) {
+ hasBabelPlugin = true;
+ console.warn(
+ 'Add @babel/plugin-transform-react-jsx-source to get a more detailed component stack. Note that you should not add it to production builds of your App for bundle size reasons.'
+ );
+ }
+
+ return (acc += '\n');
+ }, '');
+}
+
+/**
+ * Setup code to capture the component trace while rendering. Note that
+ * we cannot simply traverse `vnode._parent` upwards, because we have some
+ * debug messages for `this.setState` where the `vnode` is `undefined`.
+ */
+export function setupComponentStack() {
+ let oldDiff = options._diff;
+ let oldDiffed = options.diffed;
+ let oldRoot = options._root;
+ let oldVNode = options.vnode;
+ let oldRender = options._render;
+
+ options.diffed = vnode => {
+ if (isPossibleOwner(vnode)) {
+ ownerStack.pop();
+ }
+ renderStack.pop();
+ if (oldDiffed) oldDiffed(vnode);
+ };
+
+ options._diff = vnode => {
+ if (isPossibleOwner(vnode)) {
+ renderStack.push(vnode);
+ }
+ if (oldDiff) oldDiff(vnode);
+ };
+
+ options._root = (vnode, parent) => {
+ ownerStack = [];
+ if (oldRoot) oldRoot(vnode, parent);
+ };
+
+ options.vnode = vnode => {
+ vnode._owner =
+ ownerStack.length > 0 ? ownerStack[ownerStack.length - 1] : null;
+ if (oldVNode) oldVNode(vnode);
+ };
+
+ options._render = vnode => {
+ if (isPossibleOwner(vnode)) {
+ ownerStack.push(vnode);
+ }
+
+ if (oldRender) oldRender(vnode);
+ };
+}
diff --git a/preact/debug/src/constants.js b/preact/debug/src/constants.js
new file mode 100644
index 0000000..e15b547
--- /dev/null
+++ b/preact/debug/src/constants.js
@@ -0,0 +1,3 @@
+export const ELEMENT_NODE = 1;
+export const DOCUMENT_NODE = 9;
+export const DOCUMENT_FRAGMENT_NODE = 11;
diff --git a/preact/debug/src/debug.js b/preact/debug/src/debug.js
new file mode 100644
index 0000000..27927cb
--- /dev/null
+++ b/preact/debug/src/debug.js
@@ -0,0 +1,442 @@
+import { checkPropTypes } from './check-props';
+import { options, Component } from 'preact';
+import {
+ ELEMENT_NODE,
+ DOCUMENT_NODE,
+ DOCUMENT_FRAGMENT_NODE
+} from './constants';
+import {
+ getOwnerStack,
+ setupComponentStack,
+ getCurrentVNode,
+ getDisplayName
+} from './component-stack';
+import { assign } from './util';
+
+const isWeakMapSupported = typeof WeakMap == 'function';
+
+function getClosestDomNodeParent(parent) {
+ if (!parent) return {};
+ if (typeof parent.type == 'function') {
+ return getClosestDomNodeParent(parent._parent);
+ }
+ return parent;
+}
+
+export function initDebug() {
+ setupComponentStack();
+
+ let hooksAllowed = false;
+
+ /* eslint-disable no-console */
+ let oldBeforeDiff = options._diff;
+ let oldDiffed = options.diffed;
+ let oldVnode = options.vnode;
+ let oldCatchError = options._catchError;
+ let oldRoot = options._root;
+ let oldHook = options._hook;
+ const warnedComponents = !isWeakMapSupported
+ ? null
+ : {
+ useEffect: new WeakMap(),
+ useLayoutEffect: new WeakMap(),
+ lazyPropTypes: new WeakMap()
+ };
+ const deprecations = [];
+
+ options._catchError = (error, vnode, oldVNode) => {
+ let component = vnode && vnode._component;
+ if (component && typeof error.then == 'function') {
+ const promise = error;
+ error = new Error(
+ `Missing Suspense. The throwing component was: ${getDisplayName(vnode)}`
+ );
+
+ let parent = vnode;
+ for (; parent; parent = parent._parent) {
+ if (parent._component && parent._component._childDidSuspend) {
+ error = promise;
+ break;
+ }
+ }
+
+ // We haven't recovered and we know at this point that there is no
+ // Suspense component higher up in the tree
+ if (error instanceof Error) {
+ throw error;
+ }
+ }
+
+ try {
+ oldCatchError(error, vnode, oldVNode);
+
+ // when an error was handled by an ErrorBoundary we will nontheless emit an error
+ // event on the window object. This is to make up for react compatibility in dev mode
+ // and thus make the Next.js dev overlay work.
+ if (typeof error.then != 'function') {
+ setTimeout(() => {
+ throw error;
+ });
+ }
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ options._root = (vnode, parentNode) => {
+ if (!parentNode) {
+ throw new Error(
+ 'Undefined parent passed to render(), this is the second argument.\n' +
+ 'Check if the element is available in the DOM/has the correct id.'
+ );
+ }
+
+ let isValid;
+ switch (parentNode.nodeType) {
+ case ELEMENT_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_NODE:
+ isValid = true;
+ break;
+ default:
+ isValid = false;
+ }
+
+ if (!isValid) {
+ let componentName = getDisplayName(vnode);
+ throw new Error(
+ `Expected a valid HTML node as a second argument to render. Received ${parentNode} instead: render(<${componentName} />, ${parentNode});`
+ );
+ }
+
+ if (oldRoot) oldRoot(vnode, parentNode);
+ };
+
+ options._diff = vnode => {
+ let { type, _parent: parent } = vnode;
+ let parentVNode = getClosestDomNodeParent(parent);
+
+ hooksAllowed = true;
+
+ if (type === undefined) {
+ throw new Error(
+ 'Undefined component passed to createElement()\n\n' +
+ 'You likely forgot to export your component or might have mixed up default and named imports' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ } else if (type != null && typeof type == 'object') {
+ if (type._children !== undefined && type._dom !== undefined) {
+ throw new Error(
+ `Invalid type passed to createElement(): ${type}\n\n` +
+ 'Did you accidentally pass a JSX literal as JSX twice?\n\n' +
+ ` let My${getDisplayName(vnode)} = ${serializeVNode(type)};\n` +
+ ` let vnode = <My${getDisplayName(vnode)} />;\n\n` +
+ 'This usually happens when you export a JSX literal and not the component.' +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
+
+ throw new Error(
+ 'Invalid type passed to createElement(): ' +
+ (Array.isArray(type) ? 'array' : type)
+ );
+ }
+
+ if (
+ (type === 'thead' || type === 'tfoot' || type === 'tbody') &&
+ parentVNode.type !== 'table'
+ ) {
+ console.error(
+ 'Improper nesting of table. Your <thead/tbody/tfoot> should have a <table> parent.' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ } else if (
+ type === 'tr' &&
+ parentVNode.type !== 'thead' &&
+ parentVNode.type !== 'tfoot' &&
+ parentVNode.type !== 'tbody' &&
+ parentVNode.type !== 'table'
+ ) {
+ console.error(
+ 'Improper nesting of table. Your <tr> should have a <thead/tbody/tfoot/table> parent.' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ } else if (type === 'td' && parentVNode.type !== 'tr') {
+ console.error(
+ 'Improper nesting of table. Your <td> should have a <tr> parent.' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ } else if (type === 'th' && parentVNode.type !== 'tr') {
+ console.error(
+ 'Improper nesting of table. Your <th> should have a <tr>.' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
+
+ if (
+ vnode.ref !== undefined &&
+ typeof vnode.ref != 'function' &&
+ typeof vnode.ref != 'object' &&
+ !('$$typeof' in vnode) // allow string refs when preact-compat is installed
+ ) {
+ throw new Error(
+ `Component's "ref" property should be a function, or an object created ` +
+ `by createRef(), but got [${typeof vnode.ref}] instead\n` +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
+
+ if (typeof vnode.type == 'string') {
+ for (const key in vnode.props) {
+ if (
+ key[0] === 'o' &&
+ key[1] === 'n' &&
+ typeof vnode.props[key] != 'function' &&
+ vnode.props[key] != null
+ ) {
+ throw new Error(
+ `Component's "${key}" property should be a function, ` +
+ `but got [${typeof vnode.props[key]}] instead\n` +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
+ }
+ }
+
+ // Check prop-types if available
+ if (typeof vnode.type == 'function' && vnode.type.propTypes) {
+ if (
+ vnode.type.displayName === 'Lazy' &&
+ warnedComponents &&
+ !warnedComponents.lazyPropTypes.has(vnode.type)
+ ) {
+ const m =
+ 'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
+ try {
+ const lazyVNode = vnode.type();
+ warnedComponents.lazyPropTypes.set(vnode.type, true);
+ console.warn(
+ m + `Component wrapped in lazy() is ${getDisplayName(lazyVNode)}`
+ );
+ } catch (promise) {
+ console.warn(
+ m + "We will log the wrapped component's name once it is loaded."
+ );
+ }
+ }
+
+ let values = vnode.props;
+ if (vnode.type._forwarded) {
+ values = assign({}, values);
+ delete values.ref;
+ }
+
+ checkPropTypes(
+ vnode.type.propTypes,
+ values,
+ 'prop',
+ getDisplayName(vnode),
+ () => getOwnerStack(vnode)
+ );
+ }
+
+ if (oldBeforeDiff) oldBeforeDiff(vnode);
+ };
+
+ options._hook = (comp, index, type) => {
+ if (!comp || !hooksAllowed) {
+ throw new Error('Hook can only be invoked from render methods.');
+ }
+
+ if (oldHook) oldHook(comp, index, type);
+ };
+
+ // Ideally we'd want to print a warning once per component, but we
+ // don't have access to the vnode that triggered it here. As a
+ // compromise and to avoid flooding the console with warnings we
+ // print each deprecation warning only once.
+ const warn = (property, message) => ({
+ get() {
+ const key = 'get' + property + message;
+ if (deprecations && deprecations.indexOf(key) < 0) {
+ deprecations.push(key);
+ console.warn(`getting vnode.${property} is deprecated, ${message}`);
+ }
+ },
+ set() {
+ const key = 'set' + property + message;
+ if (deprecations && deprecations.indexOf(key) < 0) {
+ deprecations.push(key);
+ console.warn(`setting vnode.${property} is not allowed, ${message}`);
+ }
+ }
+ });
+
+ const deprecatedAttributes = {
+ nodeName: warn('nodeName', 'use vnode.type'),
+ attributes: warn('attributes', 'use vnode.props'),
+ children: warn('children', 'use vnode.props.children')
+ };
+
+ const deprecatedProto = Object.create({}, deprecatedAttributes);
+
+ options.vnode = vnode => {
+ const props = vnode.props;
+ if (
+ vnode.type !== null &&
+ props != null &&
+ ('__source' in props || '__self' in props)
+ ) {
+ const newProps = (vnode.props = {});
+ for (let i in props) {
+ const v = props[i];
+ if (i === '__source') vnode.__source = v;
+ else if (i === '__self') vnode.__self = v;
+ else newProps[i] = v;
+ }
+ }
+
+ // eslint-disable-next-line
+ vnode.__proto__ = deprecatedProto;
+ if (oldVnode) oldVnode(vnode);
+ };
+
+ options.diffed = vnode => {
+ // Check if the user passed plain objects as children. Note that we cannot
+ // move this check into `options.vnode` because components can receive
+ // children in any shape they want (e.g.
+ // `<MyJSONFormatter>{{ foo: 123, bar: "abc" }}</MyJSONFormatter>`).
+ // Putting this check in `options.diffed` ensures that
+ // `vnode._children` is set and that we only validate the children
+ // that were actually rendered.
+ if (vnode._children) {
+ vnode._children.forEach(child => {
+ if (child && child.type === undefined) {
+ // Remove internal vnode keys that will always be patched
+ delete child._parent;
+ delete child._depth;
+ const keys = Object.keys(child).join(',');
+ throw new Error(
+ `Objects are not valid as a child. Encountered an object with the keys {${keys}}.` +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+ }
+ });
+ }
+
+ hooksAllowed = false;
+
+ if (oldDiffed) oldDiffed(vnode);
+
+ if (vnode._children != null) {
+ const keys = [];
+ for (let i = 0; i < vnode._children.length; i++) {
+ const child = vnode._children[i];
+ if (!child || child.key == null) continue;
+
+ const key = child.key;
+ if (keys.indexOf(key) !== -1) {
+ console.error(
+ 'Following component has two or more children with the ' +
+ `same key attribute: "${key}". This may cause glitches and misbehavior ` +
+ 'in rendering process. Component: \n\n' +
+ serializeVNode(vnode) +
+ `\n\n${getOwnerStack(vnode)}`
+ );
+
+ // Break early to not spam the console
+ break;
+ }
+
+ keys.push(key);
+ }
+ }
+ };
+}
+
+const setState = Component.prototype.setState;
+Component.prototype.setState = function(update, callback) {
+ if (this._vnode == null) {
+ // `this._vnode` will be `null` during componentWillMount. But it
+ // is perfectly valid to call `setState` during cWM. So we
+ // need an additional check to verify that we are dealing with a
+ // call inside constructor.
+ if (this.state == null) {
+ console.warn(
+ `Calling "this.setState" inside the constructor of a component is a ` +
+ `no-op and might be a bug in your application. Instead, set ` +
+ `"this.state = {}" directly.\n\n${getOwnerStack(getCurrentVNode())}`
+ );
+ }
+ } else if (this._parentDom == null) {
+ console.warn(
+ `Can't call "this.setState" on an unmounted component. This is a no-op, ` +
+ `but it indicates a memory leak in your application. To fix, cancel all ` +
+ `subscriptions and asynchronous tasks in the componentWillUnmount method.` +
+ `\n\n${getOwnerStack(this._vnode)}`
+ );
+ }
+
+ return setState.call(this, update, callback);
+};
+
+const forceUpdate = Component.prototype.forceUpdate;
+Component.prototype.forceUpdate = function(callback) {
+ if (this._vnode == null) {
+ console.warn(
+ `Calling "this.forceUpdate" inside the constructor of a component is a ` +
+ `no-op and might be a bug in your application.\n\n${getOwnerStack(
+ getCurrentVNode()
+ )}`
+ );
+ } else if (this._parentDom == null) {
+ console.warn(
+ `Can't call "this.forceUpdate" on an unmounted component. This is a no-op, ` +
+ `but it indicates a memory leak in your application. To fix, cancel all ` +
+ `subscriptions and asynchronous tasks in the componentWillUnmount method.` +
+ `\n\n${getOwnerStack(this._vnode)}`
+ );
+ }
+ return forceUpdate.call(this, callback);
+};
+
+/**
+ * Serialize a vnode tree to a string
+ * @param {import('./internal').VNode} vnode
+ * @returns {string}
+ */
+export function serializeVNode(vnode) {
+ let { props } = vnode;
+ let name = getDisplayName(vnode);
+
+ let attrs = '';
+ for (let prop in props) {
+ if (props.hasOwnProperty(prop) && prop !== 'children') {
+ let value = props[prop];
+
+ // If it is an object but doesn't have toString(), use Object.toString
+ if (typeof value == 'function') {
+ value = `function ${value.displayName || value.name}() {}`;
+ }
+
+ value =
+ Object(value) === value && !value.toString
+ ? Object.prototype.toString.call(value)
+ : value + '';
+
+ attrs += ` ${prop}=${JSON.stringify(value)}`;
+ }
+ }
+
+ let children = props.children;
+ return `<${name}${attrs}${
+ children && children.length ? '>..</' + name + '>' : ' />'
+ }`;
+}
diff --git a/preact/debug/src/index.js b/preact/debug/src/index.js
new file mode 100644
index 0000000..37eee3b
--- /dev/null
+++ b/preact/debug/src/index.js
@@ -0,0 +1,6 @@
+import { initDebug } from './debug';
+import 'preact/devtools';
+
+initDebug();
+
+export { resetPropWarnings } from './check-props';
diff --git a/preact/debug/src/internal.d.ts b/preact/debug/src/internal.d.ts
new file mode 100644
index 0000000..866943c
--- /dev/null
+++ b/preact/debug/src/internal.d.ts
@@ -0,0 +1,82 @@
+import { Component, PreactElement, VNode, Options } from '../../src/internal';
+
+export { Component, PreactElement, VNode, Options };
+
+export interface DevtoolsInjectOptions {
+ /** 1 = DEV, 0 = production */
+ bundleType: 1 | 0;
+ /** The devtools enable different features for different versions of react */
+ version: string;
+ /** Informative string, currently unused in the devtools */
+ rendererPackageName: string;
+ /** Find the root dom node of a vnode */
+ findHostInstanceByFiber(vnode: VNode): HTMLElement | null;
+ /** Find the closest vnode given a dom node */
+ findFiberByHostInstance(instance: HTMLElement): VNode | null;
+}
+
+export interface DevtoolsUpdater {
+ setState(objOrFn: any): void;
+ forceUpdate(): void;
+ setInState(path: Array<string | number>, value: any): void;
+ setInProps(path: Array<string | number>, value: any): void;
+ setInContext(): void;
+}
+
+export type NodeType = 'Composite' | 'Native' | 'Wrapper' | 'Text';
+
+export interface DevtoolData {
+ nodeType: NodeType;
+ // Component type
+ type: any;
+ name: string;
+ ref: any;
+ key: string | number;
+ updater: DevtoolsUpdater | null;
+ text: string | number | null;
+ state: any;
+ props: any;
+ children: VNode[] | string | number | null;
+ publicInstance: PreactElement | Text | Component;
+ memoizedInteractions: any[];
+
+ actualDuration: number;
+ actualStartTime: number;
+ treeBaseDuration: number;
+}
+
+export type EventType =
+ | 'unmount'
+ | 'rootCommitted'
+ | 'root'
+ | 'mount'
+ | 'update'
+ | 'updateProfileTimes';
+
+export interface DevtoolsEvent {
+ data?: DevtoolData;
+ internalInstance: VNode;
+ renderer: string;
+ type: EventType;
+}
+
+export interface DevtoolsHook {
+ _renderers: Record<string, any>;
+ _roots: Set<VNode>;
+ on(ev: string, listener: () => void): void;
+ emit(ev: string, data?: object): void;
+ helpers: Record<string, any>;
+ getFiberRoots(rendererId: string): Set<any>;
+ inject(config: DevtoolsInjectOptions): string;
+ onCommitFiberRoot(rendererId: string, root: VNode): void;
+ onCommitFiberUnmount(rendererId: string, vnode: VNode): void;
+}
+
+export interface DevtoolsWindow extends Window {
+ /**
+ * If the devtools extension is installed it will inject this object into
+ * the dom. This hook handles all communications between preact and the
+ * devtools panel.
+ */
+ __REACT_DEVTOOLS_GLOBAL_HOOK__?: DevtoolsHook;
+}
diff --git a/preact/debug/src/util.js b/preact/debug/src/util.js
new file mode 100644
index 0000000..7b7a5e1
--- /dev/null
+++ b/preact/debug/src/util.js
@@ -0,0 +1,11 @@
+/**
+ * Assign properties from `props` to `obj`
+ * @template O, P The obj and props types
+ * @param {O} obj The object to copy properties to
+ * @param {P} props The object to copy properties from
+ * @returns {O & P}
+ */
+export function assign(obj, props) {
+ for (let i in props) obj[i] = props[i];
+ return /** @type {O & P} */ (obj);
+}
diff --git a/preact/debug/test/browser/component-stack-2.test.js b/preact/debug/test/browser/component-stack-2.test.js
new file mode 100644
index 0000000..a9a75af
--- /dev/null
+++ b/preact/debug/test/browser/component-stack-2.test.js
@@ -0,0 +1,54 @@
+import { createElement, render, Component } from 'preact';
+import 'preact/debug';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+// This test is not part of component-stack.test.js to avoid it being
+// transpiled with '@babel/plugin-transform-react-jsx-source' enabled.
+
+describe('component stack', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ let errors = [];
+ let warnings = [];
+
+ beforeEach(() => {
+ scratch = setupScratch();
+
+ errors = [];
+ warnings = [];
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+ });
+
+ afterEach(() => {
+ console.error.restore();
+ console.warn.restore();
+ teardown(scratch);
+ });
+
+ it('should print a warning when "@babel/plugin-transform-react-jsx-source" is not installed', () => {
+ function Foo() {
+ return <Thrower />;
+ }
+
+ class Thrower extends Component {
+ constructor(props) {
+ super(props);
+ this.setState({ foo: 1 });
+ }
+
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+
+ expect(
+ warnings[0].indexOf('@babel/plugin-transform-react-jsx-source') > -1
+ ).to.equal(true);
+ });
+});
diff --git a/preact/debug/test/browser/component-stack.test.js b/preact/debug/test/browser/component-stack.test.js
new file mode 100644
index 0000000..87cd085
--- /dev/null
+++ b/preact/debug/test/browser/component-stack.test.js
@@ -0,0 +1,86 @@
+import { createElement, render, Component } from 'preact';
+import 'preact/debug';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+describe('component stack', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ let errors = [];
+ let warnings = [];
+
+ const getStack = arr => arr[0].split('\n\n')[1];
+
+ beforeEach(() => {
+ scratch = setupScratch();
+
+ errors = [];
+ warnings = [];
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+ });
+
+ afterEach(() => {
+ console.error.restore();
+ console.warn.restore();
+ teardown(scratch);
+ });
+
+ it('should print component stack', () => {
+ function Foo() {
+ return <Thrower />;
+ }
+
+ class Thrower extends Component {
+ constructor(props) {
+ super(props);
+ this.setState({ foo: 1 });
+ }
+
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+
+ let lines = getStack(warnings).split('\n');
+ expect(lines[0].indexOf('Thrower') > -1).to.equal(true);
+ expect(lines[1].indexOf('Foo') > -1).to.equal(true);
+ });
+
+ it('should only print owners', () => {
+ function Foo(props) {
+ return <div>{props.children}</div>;
+ }
+
+ function Bar() {
+ return (
+ <Foo>
+ <Thrower />
+ </Foo>
+ );
+ }
+
+ class Thrower extends Component {
+ render() {
+ return (
+ <table>
+ <td>
+ <tr>foo</tr>
+ </td>
+ </table>
+ );
+ }
+ }
+
+ render(<Bar />, scratch);
+
+ let lines = getStack(errors).split('\n');
+ expect(lines[0].indexOf('td') > -1).to.equal(true);
+ expect(lines[1].indexOf('Thrower') > -1).to.equal(true);
+ expect(lines[2].indexOf('Bar') > -1).to.equal(true);
+ });
+});
diff --git a/preact/debug/test/browser/debug-compat.test.js b/preact/debug/test/browser/debug-compat.test.js
new file mode 100644
index 0000000..aea131f
--- /dev/null
+++ b/preact/debug/test/browser/debug-compat.test.js
@@ -0,0 +1,81 @@
+import { createElement, render, createRef } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import './fakeDevTools';
+import 'preact/debug';
+import * as PropTypes from 'prop-types';
+
+// eslint-disable-next-line no-duplicate-imports
+import { resetPropWarnings } from 'preact/debug';
+import { forwardRef, createPortal } from 'preact/compat';
+
+const h = createElement;
+/** @jsx createElement */
+
+describe('debug compat', () => {
+ let scratch;
+ let root;
+ let errors = [];
+ let warnings = [];
+
+ beforeEach(() => {
+ errors = [];
+ warnings = [];
+ scratch = setupScratch();
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+
+ root = document.createElement('div');
+ document.body.appendChild(root);
+ });
+
+ afterEach(() => {
+ /** @type {*} */
+ (console.error).restore();
+ console.warn.restore();
+ teardown(scratch);
+
+ document.body.removeChild(root);
+ });
+
+ describe('portals', () => {
+ it('should not throw an invalid render argument for a portal.', () => {
+ function Foo(props) {
+ return <div>{createPortal(props.children, root)}</div>;
+ }
+ expect(() => render(<Foo>foobar</Foo>, scratch)).not.to.throw();
+ });
+ });
+
+ describe('PropTypes', () => {
+ beforeEach(() => {
+ resetPropWarnings();
+ });
+
+ it('should not fail if ref is passed to comp wrapped in forwardRef', () => {
+ // This test ensures compat with airbnb/prop-types-exact, mui exact prop types util, etc.
+
+ const Foo = forwardRef(function Foo(props, ref) {
+ return <h1 ref={ref}>{props.text}</h1>;
+ });
+
+ Foo.propTypes = {
+ text: PropTypes.string.isRequired,
+ ref(props) {
+ if ('ref' in props) {
+ throw new Error(
+ 'ref should not be passed to prop-types valiation!'
+ );
+ }
+ }
+ };
+
+ const ref = createRef();
+
+ render(<Foo ref={ref} text="123" />, scratch);
+
+ expect(console.error).not.been.called;
+
+ expect(ref.current).to.not.be.undefined;
+ });
+ });
+});
diff --git a/preact/debug/test/browser/debug-hooks.test.js b/preact/debug/test/browser/debug-hooks.test.js
new file mode 100644
index 0000000..84bc028
--- /dev/null
+++ b/preact/debug/test/browser/debug-hooks.test.js
@@ -0,0 +1,111 @@
+import { createElement, render, Component } from 'preact';
+import { useState, useEffect } from 'preact/hooks';
+import 'preact/debug';
+import { act } from 'preact/test-utils';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+describe('debug with hooks', () => {
+ let scratch;
+ let errors = [];
+ let warnings = [];
+
+ beforeEach(() => {
+ errors = [];
+ warnings = [];
+ scratch = setupScratch();
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+ });
+
+ afterEach(() => {
+ console.error.restore();
+ console.warn.restore();
+ teardown(scratch);
+ });
+
+ it('should throw an error when using a hook outside a render', () => {
+ class Foo extends Component {
+ componentWillMount() {
+ useState();
+ }
+
+ render() {
+ return this.props.children;
+ }
+ }
+
+ class App extends Component {
+ render() {
+ return <p>test</p>;
+ }
+ }
+ const fn = () =>
+ act(() =>
+ render(
+ <Foo>
+ <App />
+ </Foo>,
+ scratch
+ )
+ );
+ expect(fn).to.throw(/Hook can only be invoked from render/);
+ });
+
+ it('should throw an error when invoked outside of a component', () => {
+ function foo() {
+ useEffect(() => {}); // Pretend to use a hook
+ return <p>test</p>;
+ }
+
+ const fn = () =>
+ act(() => {
+ render(foo(), scratch);
+ });
+ expect(fn).to.throw(/Hook can only be invoked from render/);
+ });
+
+ it('should throw an error when invoked outside of a component before render', () => {
+ function Foo(props) {
+ useEffect(() => {}); // Pretend to use a hook
+ return props.children;
+ }
+
+ const fn = () =>
+ act(() => {
+ useState();
+ render(<Foo>Hello!</Foo>, scratch);
+ });
+ expect(fn).to.throw(/Hook can only be invoked from render/);
+ });
+
+ it('should throw an error when invoked outside of a component after render', () => {
+ function Foo(props) {
+ useEffect(() => {}); // Pretend to use a hook
+ return props.children;
+ }
+
+ const fn = () =>
+ act(() => {
+ render(<Foo>Hello!</Foo>, scratch);
+ useState();
+ });
+ expect(fn).to.throw(/Hook can only be invoked from render/);
+ });
+
+ it('should throw an error when invoked inside an effect callback', () => {
+ function Foo(props) {
+ useEffect(() => {
+ useState();
+ });
+ return props.children;
+ }
+
+ const fn = () =>
+ act(() => {
+ render(<Foo>Hello!</Foo>, scratch);
+ });
+ expect(fn).to.throw(/Hook can only be invoked from render/);
+ });
+});
diff --git a/preact/debug/test/browser/debug-suspense.test.js b/preact/debug/test/browser/debug-suspense.test.js
new file mode 100644
index 0000000..a436154
--- /dev/null
+++ b/preact/debug/test/browser/debug-suspense.test.js
@@ -0,0 +1,190 @@
+import { createElement, render, lazy, Suspense } from 'preact/compat';
+import 'preact/debug';
+import { setupRerender } from 'preact/test-utils';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml
+} from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+describe('debug with suspense', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+ let rerender;
+ let errors = [];
+ let warnings = [];
+
+ beforeEach(() => {
+ errors = [];
+ warnings = [];
+ scratch = setupScratch();
+ rerender = setupRerender();
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+ });
+
+ afterEach(() => {
+ console.error.restore();
+ console.warn.restore();
+ teardown(scratch);
+ });
+
+ it('should throw on missing <Suspense>', () => {
+ function Foo() {
+ throw Promise.resolve();
+ }
+
+ expect(() => render(<Foo />, scratch)).to.throw;
+ });
+
+ it('should throw an error when using lazy and missing Suspense', () => {
+ const Foo = () => <div>Foo</div>;
+ const LazyComp = lazy(
+ () => new Promise(resolve => resolve({ default: Foo }))
+ );
+ const fn = () => {
+ render(<LazyComp />, scratch);
+ };
+
+ expect(fn).to.throw(/Missing Suspense/gi);
+ });
+
+ describe('PropTypes', () => {
+ it('should validate propTypes inside lazy()', () => {
+ function Baz(props) {
+ return <h1>{props.unhappy}</h1>;
+ }
+
+ Baz.propTypes = {
+ unhappy: function alwaysThrows(obj, key) {
+ if (obj[key] === 'signal') throw Error('got prop inside lazy()');
+ }
+ };
+
+ const loader = Promise.resolve({ default: Baz });
+ const LazyBaz = lazy(() => loader);
+
+ const suspense = (
+ <Suspense fallback={<div>fallback...</div>}>
+ <LazyBaz unhappy="signal" />
+ </Suspense>
+ );
+ render(suspense, scratch);
+ rerender(); // render fallback
+
+ expect(console.error).to.not.be.called;
+ expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>');
+
+ return loader.then(() => {
+ rerender();
+ expect(errors.length).to.equal(1);
+ expect(errors[0].includes('got prop')).to.equal(true);
+ expect(serializeHtml(scratch)).to.equal('<h1>signal</h1>');
+ });
+ });
+
+ describe('warn for PropTypes on lazy()', () => {
+ it('should log the function name', () => {
+ const loader = Promise.resolve({
+ default: function MyLazyLoaded() {
+ return <div>Hi there</div>;
+ }
+ });
+ const FakeLazy = lazy(() => loader);
+ FakeLazy.propTypes = {};
+ const suspense = (
+ <Suspense fallback={<div>fallback...</div>}>
+ <FakeLazy />
+ </Suspense>
+ );
+ render(suspense, scratch);
+ rerender(); // Render fallback
+
+ expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>');
+
+ return loader.then(() => {
+ rerender();
+ expect(console.warn).to.be.calledTwice;
+ expect(warnings[1].includes('MyLazyLoaded')).to.equal(true);
+ expect(serializeHtml(scratch)).to.equal('<div>Hi there</div>');
+ });
+ });
+
+ it('should log the displayName', () => {
+ function MyLazyLoadedComponent() {
+ return <div>Hi there</div>;
+ }
+ MyLazyLoadedComponent.displayName = 'HelloLazy';
+ const loader = Promise.resolve({ default: MyLazyLoadedComponent });
+ const FakeLazy = lazy(() => loader);
+ FakeLazy.propTypes = {};
+ const suspense = (
+ <Suspense fallback={<div>fallback...</div>}>
+ <FakeLazy />
+ </Suspense>
+ );
+ render(suspense, scratch);
+ rerender(); // Render fallback
+
+ expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>');
+
+ return loader.then(() => {
+ rerender();
+ expect(console.warn).to.be.calledTwice;
+ expect(warnings[1].includes('HelloLazy')).to.equal(true);
+ expect(serializeHtml(scratch)).to.equal('<div>Hi there</div>');
+ });
+ });
+
+ it("should not log a component if lazy loader's Promise rejects", () => {
+ const loader = Promise.reject(new Error('Hey there'));
+ const FakeLazy = lazy(() => loader);
+ FakeLazy.propTypes = {};
+ render(
+ <Suspense fallback={<div>fallback...</div>}>
+ <FakeLazy />
+ </Suspense>,
+ scratch
+ );
+ rerender(); // Render fallback
+
+ expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>');
+
+ return loader.catch(() => {
+ try {
+ rerender();
+ } catch (e) {
+ // Ignore the loader's bubbling error
+ }
+
+ // Called once on initial render, and again when promise rejects
+ expect(console.warn).to.be.calledTwice;
+ });
+ });
+
+ it("should not log a component if lazy's loader throws", () => {
+ const FakeLazy = lazy(() => {
+ throw new Error('Hello');
+ });
+ FakeLazy.propTypes = {};
+ let error;
+ try {
+ render(
+ <Suspense fallback={<div>fallback...</div>}>
+ <FakeLazy />
+ </Suspense>,
+ scratch
+ );
+ } catch (e) {
+ error = e;
+ }
+
+ expect(console.warn).to.be.calledOnce;
+ expect(error).not.to.be.undefined;
+ expect(error.message).to.eql('Hello');
+ });
+ });
+ });
+});
diff --git a/preact/debug/test/browser/debug.options.test.js b/preact/debug/test/browser/debug.options.test.js
new file mode 100644
index 0000000..21d2c3f
--- /dev/null
+++ b/preact/debug/test/browser/debug.options.test.js
@@ -0,0 +1,135 @@
+import {
+ vnodeSpy,
+ rootSpy,
+ beforeDiffSpy,
+ hookSpy,
+ afterDiffSpy,
+ catchErrorSpy
+} from '../../../test/_util/optionSpies';
+
+import { createElement, render, Component } from 'preact';
+import { useState } from 'preact/hooks';
+import { setupRerender } from 'preact/test-utils';
+import 'preact/debug';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+describe('debug options', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ /** @type {(count: number) => void} */
+ let setCount;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ vnodeSpy.resetHistory();
+ rootSpy.resetHistory();
+ beforeDiffSpy.resetHistory();
+ hookSpy.resetHistory();
+ afterDiffSpy.resetHistory();
+ catchErrorSpy.resetHistory();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ class ClassApp extends Component {
+ constructor() {
+ super();
+ this.state = { count: 0 };
+ setCount = count => this.setState({ count });
+ }
+
+ render() {
+ return <div>{this.state.count}</div>;
+ }
+ }
+
+ it('should call old options on mount', () => {
+ render(<ClassApp />, scratch);
+
+ expect(vnodeSpy).to.have.been.called;
+ expect(rootSpy).to.have.been.called;
+ expect(beforeDiffSpy).to.have.been.called;
+ expect(afterDiffSpy).to.have.been.called;
+ });
+
+ it('should call old options on update', () => {
+ render(<ClassApp />, scratch);
+
+ setCount(1);
+ rerender();
+
+ expect(vnodeSpy).to.have.been.called;
+ expect(rootSpy).to.have.been.called;
+ expect(beforeDiffSpy).to.have.been.called;
+ expect(afterDiffSpy).to.have.been.called;
+ });
+
+ it('should call old options on unmount', () => {
+ render(<ClassApp />, scratch);
+ render(null, scratch);
+
+ expect(vnodeSpy).to.have.been.called;
+ expect(rootSpy).to.have.been.called;
+ expect(beforeDiffSpy).to.have.been.called;
+ expect(afterDiffSpy).to.have.been.called;
+ });
+
+ it('should call old hook options for hook components', () => {
+ function HookApp() {
+ const [count, realSetCount] = useState(0);
+ setCount = realSetCount;
+ return <div>{count}</div>;
+ }
+
+ render(<HookApp />, scratch);
+
+ expect(hookSpy).to.have.been.called;
+ });
+
+ it('should call old options on error', () => {
+ const e = new Error('test');
+ class ErrorApp extends Component {
+ constructor() {
+ super();
+ this.state = { error: true };
+ }
+ componentDidCatch() {
+ this.setState({ error: false });
+ }
+ render() {
+ return <Throw error={this.state.error} />;
+ }
+ }
+
+ function Throw({ error }) {
+ if (error) {
+ throw e;
+ } else {
+ return <div>no error</div>;
+ }
+ }
+
+ const clock = sinon.useFakeTimers();
+
+ render(<ErrorApp />, scratch);
+ rerender();
+
+ expect(catchErrorSpy).to.have.been.called;
+
+ // we expect to throw after setTimeout to trigger a window.onerror
+ // this is to ensure react compat (i.e. with next.js' dev overlay)
+ expect(() => clock.tick(0)).to.throw(e);
+
+ clock.restore();
+ });
+});
diff --git a/preact/debug/test/browser/debug.test.js b/preact/debug/test/browser/debug.test.js
new file mode 100644
index 0000000..65b3ab4
--- /dev/null
+++ b/preact/debug/test/browser/debug.test.js
@@ -0,0 +1,624 @@
+import { createElement, render, createRef, Component, Fragment } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml
+} from '../../../test/_util/helpers';
+import './fakeDevTools';
+import 'preact/debug';
+import * as PropTypes from 'prop-types';
+
+// eslint-disable-next-line no-duplicate-imports
+import { resetPropWarnings } from 'preact/debug';
+
+const h = createElement;
+/** @jsx createElement */
+
+describe('debug', () => {
+ let scratch;
+ let errors = [];
+ let warnings = [];
+
+ beforeEach(() => {
+ errors = [];
+ warnings = [];
+ scratch = setupScratch();
+ sinon.stub(console, 'error').callsFake(e => errors.push(e));
+ sinon.stub(console, 'warn').callsFake(w => warnings.push(w));
+ });
+
+ afterEach(() => {
+ /** @type {*} */
+ (console.error).restore();
+ console.warn.restore();
+ teardown(scratch);
+ });
+
+ it('should initialize devtools', () => {
+ expect(window.__PREACT_DEVTOOLS__.attachPreact).to.have.been.called;
+ });
+
+ it('should print an error on rendering on undefined parent', () => {
+ let fn = () => render(<div />, undefined);
+ expect(fn).to.throw(/render/);
+ });
+
+ it('should print an error on rendering on invalid parent', () => {
+ let fn = () => render(<div />, 6);
+ expect(fn).to.throw(/valid HTML node/);
+ expect(fn).to.throw(/<div/);
+ });
+
+ it('should print an error with (function) component name when available', () => {
+ const App = () => <div />;
+ let fn = () => render(<App />, 6);
+ expect(fn).to.throw(/<App/);
+ expect(fn).to.throw(/6/);
+
+ fn = () => render(<App />, {});
+ expect(fn).to.throw(/<App/);
+ expect(fn).to.throw(/[object Object]/);
+
+ fn = () => render(<Fragment />, 'badroot');
+ expect(fn).to.throw(/<Fragment/);
+ expect(fn).to.throw(/badroot/);
+ });
+
+ it('should print an error with (class) component name when available', () => {
+ class App extends Component {
+ render() {
+ return <div />;
+ }
+ }
+ let fn = () => render(<App />, 6);
+ expect(fn).to.throw(/<App/);
+ });
+
+ it('should print an error on undefined component', () => {
+ let fn = () => render(h(undefined), scratch);
+ expect(fn).to.throw(/createElement/);
+ });
+
+ it('should print an error on invalid object component', () => {
+ let fn = () => render(h({}), scratch);
+ expect(fn).to.throw(/createElement/);
+ });
+
+ it('should print an error when component is an array', () => {
+ let fn = () => render(h([<div />]), scratch);
+ expect(fn).to.throw(/createElement/);
+ });
+
+ it('should print an error on double jsx conversion', () => {
+ let Foo = <div />;
+ let fn = () => render(h(<Foo />), scratch);
+ expect(fn).to.throw(/JSX twice/);
+ });
+
+ it('should add __source to the vnode in debug mode.', () => {
+ const vnode = h('div', {
+ __source: {
+ fileName: 'div.jsx',
+ lineNumber: 3
+ }
+ });
+ expect(vnode.__source).to.deep.equal({
+ fileName: 'div.jsx',
+ lineNumber: 3
+ });
+ expect(vnode.props.__source).to.be.undefined;
+ });
+
+ it('should add __self to the vnode in debug mode.', () => {
+ const vnode = h('div', {
+ __self: {}
+ });
+ expect(vnode.__self).to.deep.equal({});
+ expect(vnode.props.__self).to.be.undefined;
+ });
+
+ it('should warn when accessing certain attributes', () => {
+ const vnode = h('div', null);
+
+ // Push into an array to avoid empty statements being dead code eliminated
+ const res = [];
+ res.push(vnode);
+ res.push(vnode.attributes);
+ expect(console.warn).to.be.calledOnce;
+ expect(console.warn.args[0]).to.match(/use vnode.props/);
+ res.push(vnode.nodeName);
+ expect(console.warn).to.be.calledTwice;
+ expect(console.warn.args[1]).to.match(/use vnode.type/);
+ res.push(vnode.children);
+ expect(console.warn).to.be.calledThrice;
+ expect(console.warn.args[2]).to.match(/use vnode.props.children/);
+
+ // Should only warn once
+ res.push(vnode.attributes);
+ expect(console.warn).to.be.calledThrice;
+ res.push(vnode.nodeName);
+ expect(console.warn).to.be.calledThrice;
+ res.push(vnode.children);
+ expect(console.warn).to.be.calledThrice;
+
+ vnode.attributes = {};
+ expect(console.warn.args[3]).to.match(/use vnode.props/);
+ vnode.nodeName = '';
+ expect(console.warn.args[4]).to.match(/use vnode.type/);
+ vnode.children = [];
+ expect(console.warn.args[5]).to.match(/use vnode.props.children/);
+
+ // Should only warn once
+ vnode.attributes = {};
+ expect(console.warn.args.length).to.equal(6);
+ vnode.nodeName = '';
+ expect(console.warn.args.length).to.equal(6);
+ vnode.children = [];
+ expect(console.warn.args.length).to.equal(6);
+
+ // Mark res as used, otherwise it will be dead code eliminated
+ expect(res.length).to.equal(7);
+ });
+
+ it('should warn when calling setState inside the constructor', () => {
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.setState({ foo: true });
+ }
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(console.warn).to.be.calledOnce;
+ expect(console.warn.args[0]).to.match(/no-op/);
+ });
+
+ it('should NOT warn when calling setState inside the cWM', () => {
+ class Foo extends Component {
+ componentWillMount() {
+ this.setState({ foo: true });
+ }
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(console.warn).to.not.be.called;
+ });
+
+ it('should warn when calling setState on an unmounted Component', () => {
+ let setState;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ setState = () => this.setState({ foo: true });
+ }
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(console.warn).to.not.be.called;
+
+ render(null, scratch);
+
+ setState();
+ expect(console.warn).to.be.calledOnce;
+ expect(console.warn.args[0]).to.match(/no-op/);
+ });
+
+ it('should warn when calling forceUpdate inside the constructor', () => {
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.forceUpdate();
+ }
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(console.warn).to.be.calledOnce;
+ expect(console.warn.args[0]).to.match(/no-op/);
+ });
+
+ it('should warn when calling forceUpdate on an unmounted Component', () => {
+ let forceUpdate;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ forceUpdate = () => this.forceUpdate();
+ }
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ forceUpdate();
+ expect(console.warn).to.not.be.called;
+
+ render(null, scratch);
+
+ forceUpdate();
+ expect(console.warn).to.be.calledOnce;
+ expect(console.warn.args[0]).to.match(/no-op/);
+ });
+
+ it('should print an error when child is a plain object', () => {
+ let fn = () => render(<div>{{}}</div>, scratch);
+ expect(fn).to.throw(/not valid/);
+ });
+
+ it('should print an error on invalid refs', () => {
+ let fn = () => render(<div ref="a" />, scratch);
+ expect(fn).to.throw(/createRef/);
+ });
+
+ it('should not print for null as a handler', () => {
+ let fn = () => render(<div onclick={null} />, scratch);
+ expect(fn).not.to.throw();
+ });
+
+ it('should not print for undefined as a handler', () => {
+ let fn = () => render(<div onclick={undefined} />, scratch);
+ expect(fn).not.to.throw();
+ });
+
+ it('should not print for attributes starting with on for Components', () => {
+ const Comp = () => <p>online</p>;
+ let fn = () => render(<Comp online={false} />, scratch);
+ expect(fn).not.to.throw();
+ });
+
+ it('should print an error on invalid handler', () => {
+ let fn = () => render(<div onclick="a" />, scratch);
+ expect(fn).to.throw(/"onclick" property should be a function/);
+ });
+
+ it('should NOT print an error on valid refs', () => {
+ let noop = () => {};
+ render(<div ref={noop} />, scratch);
+
+ let ref = createRef();
+ render(<div ref={ref} />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ describe('duplicate keys', () => {
+ const List = props => <ul>{props.children}</ul>;
+ const ListItem = props => <li>{props.children}</li>;
+
+ it('should print an error on duplicate keys with DOM nodes', () => {
+ render(
+ <div>
+ <span key="a" />
+ <span key="a" />
+ </div>,
+ scratch
+ );
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should allow distinct object keys', () => {
+ const A = { is: 'A' };
+ const B = { is: 'B' };
+ render(
+ <div>
+ <span key={A} />
+ <span key={B} />
+ </div>,
+ scratch
+ );
+ expect(console.error).not.to.be.called;
+ });
+
+ it('should print an error for duplicate object keys', () => {
+ const A = { is: 'A' };
+ render(
+ <div>
+ <span key={A} />
+ <span key={A} />
+ </div>,
+ scratch
+ );
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should print an error on duplicate keys with Components', () => {
+ function App() {
+ return (
+ <List>
+ <ListItem key="a">a</ListItem>
+ <ListItem key="b">b</ListItem>
+ <ListItem key="b">d</ListItem>
+ <ListItem key="d">d</ListItem>
+ </List>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should print an error on duplicate keys with Fragments', () => {
+ function App() {
+ return (
+ <Fragment>
+ <List key="list">
+ <ListItem key="a">a</ListItem>
+ <ListItem key="b">b</ListItem>
+ <Fragment key="b">
+ {/* Should be okay to duplicate keys since these are inside a Fragment */}
+ <ListItem key="a">c</ListItem>
+ <ListItem key="b">d</ListItem>
+ <ListItem key="c">e</ListItem>
+ </Fragment>
+ <ListItem key="f">f</ListItem>
+ </List>
+ <div key="list">sibling</div>
+ </Fragment>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(console.error).to.be.calledTwice;
+ });
+ });
+
+ describe('table markup', () => {
+ it('missing <tbody>/<thead>/<tfoot>/<table>', () => {
+ const Table = () => (
+ <tr>
+ <td>hi</td>
+ </tr>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <table> with <thead>', () => {
+ const Table = () => (
+ <thead>
+ <tr>
+ <td>hi</td>
+ </tr>
+ </thead>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <table> with <tbody>', () => {
+ const Table = () => (
+ <tbody>
+ <tr>
+ <td>hi</td>
+ </tr>
+ </tbody>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <table> with <tfoot>', () => {
+ const Table = () => (
+ <tfoot>
+ <tr>
+ <td>hi</td>
+ </tr>
+ </tfoot>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <tr>', () => {
+ const Table = () => (
+ <table>
+ <tbody>
+ <td>Hi</td>
+ </tbody>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <tr> with td component', () => {
+ const Cell = ({ children }) => <td>{children}</td>;
+ const Table = () => (
+ <table>
+ <tbody>
+ <Cell>Hi</Cell>
+ </tbody>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('missing <tr> with th component', () => {
+ const Cell = ({ children }) => <th>{children}</th>;
+ const Table = () => (
+ <table>
+ <tbody>
+ <Cell>Hi</Cell>
+ </tbody>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('Should accept <td> instead of <th> in <thead>', () => {
+ const Table = () => (
+ <table>
+ <thead>
+ <tr>
+ <td>Hi</td>
+ </tr>
+ </thead>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ it('Accepts well formed table with TD components', () => {
+ const Cell = ({ children }) => <td>{children}</td>;
+ const Table = () => (
+ <table>
+ <thead>
+ <tr>
+ <th>Head</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Body</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <Cell>Body</Cell>
+ </tr>
+ </tfoot>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ it('Accepts well formed table', () => {
+ const Table = () => (
+ <table>
+ <thead>
+ <tr>
+ <th>Head</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Body</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>Body</td>
+ </tr>
+ </tfoot>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+
+ it('Accepts minimal well formed table', () => {
+ const Table = () => (
+ <table>
+ <tr>
+ <th>Head</th>
+ </tr>
+ <tr>
+ <td>Body</td>
+ </tr>
+ </table>
+ );
+ render(<Table />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+ });
+
+ describe('PropTypes', () => {
+ beforeEach(() => {
+ resetPropWarnings();
+ });
+
+ it("should fail if props don't match prop-types", () => {
+ function Foo(props) {
+ return <h1>{props.text}</h1>;
+ }
+
+ Foo.propTypes = {
+ text: PropTypes.string.isRequired
+ };
+
+ render(<Foo text={123} />, scratch);
+
+ expect(console.error).to.be.calledOnce;
+
+ // The message here may change when the "prop-types" library is updated,
+ // but we check it exactly to make sure all parameters were supplied
+ // correctly.
+ expect(console.error).to.have.been.calledOnceWith(
+ sinon.match(
+ /^Failed prop type: Invalid prop `text` of type `number` supplied to `Foo`, expected `string`\.\n {2}in Foo \(at (.*)[/\\]debug[/\\]test[/\\]browser[/\\]debug\.test\.js:[0-9]+\)$/m
+ )
+ );
+ });
+
+ it('should only log a given prop type error once', () => {
+ function Foo(props) {
+ return <h1>{props.text}</h1>;
+ }
+
+ Foo.propTypes = {
+ text: PropTypes.string.isRequired,
+ count: PropTypes.number
+ };
+
+ // Trigger the same error twice. The error should only be logged
+ // once.
+ render(<Foo text={123} />, scratch);
+ render(<Foo text={123} />, scratch);
+
+ expect(console.error).to.be.calledOnce;
+
+ // Trigger a different error. This should result in a new log
+ // message.
+ console.error.resetHistory();
+ render(<Foo text="ok" count="123" />, scratch);
+ expect(console.error).to.be.calledOnce;
+ });
+
+ it('should render with error logged when validator gets signal and throws exception', () => {
+ function Baz(props) {
+ return <h1>{props.unhappy}</h1>;
+ }
+
+ Baz.propTypes = {
+ unhappy: function alwaysThrows(obj, key) {
+ if (obj[key] === 'signal') throw Error('got prop');
+ }
+ };
+
+ render(<Baz unhappy={'signal'} />, scratch);
+
+ expect(console.error).to.be.calledOnce;
+ expect(errors[0].includes('got prop')).to.equal(true);
+ expect(serializeHtml(scratch)).to.equal('<h1>signal</h1>');
+ });
+
+ it('should not print to console when types are correct', () => {
+ function Bar(props) {
+ return <h1>{props.text}</h1>;
+ }
+
+ Bar.propTypes = {
+ text: PropTypes.string.isRequired
+ };
+
+ render(<Bar text="foo" />, scratch);
+ expect(console.error).to.not.be.called;
+ });
+ });
+});
diff --git a/preact/debug/test/browser/fakeDevTools.js b/preact/debug/test/browser/fakeDevTools.js
new file mode 100644
index 0000000..e611df3
--- /dev/null
+++ b/preact/debug/test/browser/fakeDevTools.js
@@ -0,0 +1 @@
+window.__PREACT_DEVTOOLS__ = { attachPreact: sinon.spy() };
diff --git a/preact/debug/test/browser/serializeVNode.test.js b/preact/debug/test/browser/serializeVNode.test.js
new file mode 100644
index 0000000..f8c8515
--- /dev/null
+++ b/preact/debug/test/browser/serializeVNode.test.js
@@ -0,0 +1,66 @@
+import { createElement, Component } from 'preact';
+import { serializeVNode } from '../../src/debug';
+
+/** @jsx createElement */
+
+describe('serializeVNode', () => {
+ it("should prefer a function component's displayName", () => {
+ function Foo() {
+ return <div />;
+ }
+ Foo.displayName = 'Bar';
+
+ expect(serializeVNode(<Foo />)).to.equal('<Bar />');
+ });
+
+ it("should prefer a class component's displayName", () => {
+ class Bar extends Component {
+ render() {
+ return <div />;
+ }
+ }
+ Bar.displayName = 'Foo';
+
+ expect(serializeVNode(<Bar />)).to.equal('<Foo />');
+ });
+
+ it('should serialize vnodes without children', () => {
+ expect(serializeVNode(<br />)).to.equal('<br />');
+ });
+
+ it('should serialize vnodes with children', () => {
+ expect(serializeVNode(<div>Hello World</div>)).to.equal('<div>..</div>');
+ });
+
+ it('should serialize components', () => {
+ function Foo() {
+ return <div />;
+ }
+ expect(serializeVNode(<Foo />)).to.equal('<Foo />');
+ });
+
+ it('should serialize props', () => {
+ expect(serializeVNode(<div class="foo" />)).to.equal('<div class="foo" />');
+
+ // Ensure that we have a predictable function name. Our test runner
+ // creates an all inclusive bundle per file and the identifier
+ // "noop" may have already been used.
+ // eslint-disable-next-line func-style
+ let noop = function noopFn() {};
+ expect(serializeVNode(<div onClick={noop} />)).to.equal(
+ '<div onClick="function noopFn() {}" />'
+ );
+
+ function Foo(props) {
+ return props.foo;
+ }
+
+ expect(serializeVNode(<Foo foo={[1, 2, 3]} />)).to.equal(
+ '<Foo foo="1,2,3" />'
+ );
+
+ expect(serializeVNode(<div prop={Object.create(null)} />)).to.equal(
+ '<div prop="[object Object]" />'
+ );
+ });
+});
diff --git a/preact/demo/contenteditable.js b/preact/demo/contenteditable.js
new file mode 100644
index 0000000..4e913ba
--- /dev/null
+++ b/preact/demo/contenteditable.js
@@ -0,0 +1,25 @@
+import { createElement } from 'preact';
+import { useState } from 'preact/hooks';
+
+export default function Contenteditable() {
+ const [value, setValue] = useState("Hey there<br />I'm editable!");
+
+ return (
+ <div>
+ <div>
+ <button onClick={() => setValue('')}>Clear!</button>
+ </div>
+ <div
+ style={{
+ border: '1px solid gray',
+ padding: '8px',
+ margin: '8px 0',
+ background: 'white'
+ }}
+ contentEditable
+ onInput={e => setValue(e.currentTarget.innerHTML)}
+ dangerouslySetInnerHTML={{ __html: value }}
+ />
+ </div>
+ );
+}
diff --git a/preact/demo/context.js b/preact/demo/context.js
new file mode 100644
index 0000000..3fe3bc0
--- /dev/null
+++ b/preact/demo/context.js
@@ -0,0 +1,69 @@
+// eslint-disable-next-line no-unused-vars
+import { createElement, Component, createContext, Fragment } from 'preact';
+const { Provider, Consumer } = createContext();
+
+class ThemeProvider extends Component {
+ state = {
+ value: this.props.value
+ };
+
+ onClick = () => {
+ this.setState(prev => ({
+ value:
+ prev.value === this.props.value ? this.props.next : this.props.value
+ }));
+ };
+
+ render() {
+ return (
+ <div>
+ <button onClick={this.onClick}>Toggle</button>
+ <Provider value={this.state.value}>{this.props.children}</Provider>
+ </div>
+ );
+ }
+}
+
+class Child extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return (
+ <>
+ <p>(blocked update)</p>
+ {this.props.children}
+ </>
+ );
+ }
+}
+
+export default class ContextDemo extends Component {
+ render() {
+ return (
+ <ThemeProvider value="blue" next="red">
+ <Child>
+ <Consumer>
+ {data => (
+ <div>
+ <p>
+ current theme: <b>{data}</b>
+ </p>
+ <ThemeProvider value="black" next="white">
+ <Consumer>
+ {data => (
+ <p>
+ current sub theme: <b>{data}</b>
+ </p>
+ )}
+ </Consumer>
+ </ThemeProvider>
+ </div>
+ )}
+ </Consumer>
+ </Child>
+ </ThemeProvider>
+ );
+ }
+}
diff --git a/preact/demo/devtools.js b/preact/demo/devtools.js
new file mode 100644
index 0000000..0484582
--- /dev/null
+++ b/preact/demo/devtools.js
@@ -0,0 +1,42 @@
+// eslint-disable-next-line no-unused-vars
+import {
+ createElement,
+ Component,
+ memo,
+ Fragment,
+ Suspense,
+ lazy
+} from 'react';
+
+function Foo() {
+ return <div>I'm memoed</div>;
+}
+
+function LazyComp() {
+ return <div>I'm (fake) lazy loaded</div>;
+}
+
+const Lazy = lazy(() => Promise.resolve({ default: LazyComp }));
+
+const Memoed = memo(Foo);
+
+export default class DevtoolsDemo extends Component {
+ render() {
+ return (
+ <div>
+ <h1>memo()</h1>
+ <p>
+ <b>functional component:</b>
+ </p>
+ <Memoed />
+ <h1>lazy()</h1>
+ <p>
+ <b>functional component:</b>
+ </p>
+ <Suspense fallback={<div>Loading (fake) lazy loaded component...</div>}>
+ <Lazy />
+ </Suspense>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/fragments.js b/preact/demo/fragments.js
new file mode 100644
index 0000000..b713860
--- /dev/null
+++ b/preact/demo/fragments.js
@@ -0,0 +1,26 @@
+import { createElement, Component, Fragment } from 'preact';
+
+export default class extends Component {
+ state = { number: 0 };
+
+ componentDidMount() {
+ setInterval(_ => this.updateChildren(), 1000);
+ }
+
+ updateChildren() {
+ this.setState(state => ({ number: state.number + 1 }));
+ }
+
+ render(props, state) {
+ return (
+ <div>
+ <div>{state.number}</div>
+ <>
+ <div>one</div>
+ <div>{state.number}</div>
+ <div>three</div>
+ </>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/index.js b/preact/demo/index.js
new file mode 100644
index 0000000..72c58ee
--- /dev/null
+++ b/preact/demo/index.js
@@ -0,0 +1,187 @@
+import { createElement, render, Component, Fragment } from 'preact';
+// import renderToString from 'preact-render-to-string';
+import './style.scss';
+import { Router, Link } from 'preact-router';
+import Pythagoras from './pythagoras';
+import Spiral from './spiral';
+import Reorder from './reorder';
+import Todo from './todo';
+import Fragments from './fragments';
+import Context from './context';
+import installLogger from './logger';
+import ProfilerDemo from './profiler';
+import KeyBug from './key_bug';
+import StateOrderBug from './stateOrderBug';
+import PeopleBrowser from './people';
+import StyledComp from './styled-components';
+import { initDevTools } from 'preact/devtools/src/devtools';
+import { initDebug } from 'preact/debug/src/debug';
+import DevtoolsDemo from './devtools';
+import SuspenseDemo from './suspense';
+import Redux from './redux';
+import TextFields from './textFields';
+import ReduxBug from './reduxUpdate';
+import SuspenseRouterBug from './suspense-router';
+import NestedSuspenseBug from './nested-suspense';
+import Contenteditable from './contenteditable';
+import { MobXDemo } from './mobx';
+
+let isBenchmark = /(\/spiral|\/pythagoras|[#&]bench)/g.test(
+ window.location.href
+);
+if (!isBenchmark) {
+ // eslint-disable-next-line no-console
+ console.log('Enabling devtools and debug');
+ initDevTools();
+ initDebug();
+}
+
+// mobx-state-tree fix
+window.setImmediate = setTimeout;
+
+class Home extends Component {
+ render() {
+ return (
+ <div>
+ <h1>Hello</h1>
+ </div>
+ );
+ }
+}
+
+class DevtoolsWarning extends Component {
+ onClick = () => {
+ window.location.reload();
+ };
+
+ render() {
+ return (
+ <button onClick={this.onClick}>
+ Start Benchmark (disables devtools)
+ </button>
+ );
+ }
+}
+
+class App extends Component {
+ render({ url }) {
+ return (
+ <div class="app">
+ <header>
+ <nav>
+ <Link href="/" activeClassName="active">
+ Home
+ </Link>
+ <Link href="/reorder" activeClassName="active">
+ Reorder
+ </Link>
+ <Link href="/spiral" activeClassName="active">
+ Spiral
+ </Link>
+ <Link href="/pythagoras" activeClassName="active">
+ Pythagoras
+ </Link>
+ <Link href="/todo" activeClassName="active">
+ ToDo
+ </Link>
+ <Link href="/fragments" activeClassName="active">
+ Fragments
+ </Link>
+ <Link href="/key_bug" activeClassName="active">
+ Key Bug
+ </Link>
+ <Link href="/profiler" activeClassName="active">
+ Profiler
+ </Link>
+ <Link href="/context" activeClassName="active">
+ Context
+ </Link>
+ <Link href="/devtools" activeClassName="active">
+ Devtools
+ </Link>
+ <Link href="/empty-fragment" activeClassName="active">
+ Empty Fragment
+ </Link>
+ <Link href="/people" activeClassName="active">
+ People Browser
+ </Link>
+ <Link href="/state-order" activeClassName="active">
+ State Order
+ </Link>
+ <Link href="/styled-components" activeClassName="active">
+ Styled Components
+ </Link>
+ <Link href="/redux" activeClassName="active">
+ Redux
+ </Link>
+ <Link href="/mobx" activeClassName="active">
+ MobX
+ </Link>
+ <Link href="/suspense" activeClassName="active">
+ Suspense / lazy
+ </Link>
+ <Link href="/textfields" activeClassName="active">
+ Textfields
+ </Link>
+ <Link href="/reduxBug/1" activeClassName="active">
+ Redux Bug
+ </Link>
+ <Link href="/suspense-router" activeClassName="active">
+ Suspense Router Bug
+ </Link>
+ <Link href="/nested-suspense" activeClassName="active">
+ Nested Suspense Bug
+ </Link>
+ <Link href="/contenteditable" activeClassName="active">
+ contenteditable
+ </Link>
+ </nav>
+ </header>
+ <main>
+ <Router url={url}>
+ <Home path="/" />
+ <StateOrderBug path="/state-order" />
+ <Reorder path="/reorder" />
+ <div path="/spiral">
+ {!isBenchmark ? <DevtoolsWarning /> : <Spiral />}
+ </div>
+ <div path="/pythagoras">
+ {!isBenchmark ? <DevtoolsWarning /> : <Pythagoras />}
+ </div>
+ <Todo path="/todo" />
+ <Fragments path="/fragments" />
+ <ProfilerDemo path="/profiler" />
+ <KeyBug path="/key_bug" />
+ <Context path="/context" />
+ <DevtoolsDemo path="/devtools" />
+ <SuspenseDemo path="/suspense" />
+ <EmptyFragment path="/empty-fragment" />
+ <PeopleBrowser path="/people/:user?" />
+ <StyledComp path="/styled-components" />
+ <Redux path="/redux" />
+ <MobXDemo path="/mobx" />
+ <TextFields path="/textfields" />
+ <ReduxBug path="/reduxBug/:start" />
+ <SuspenseRouterBug path="/suspense-router" />
+ <NestedSuspenseBug path="/nested-suspense" />
+ <Contenteditable path="/contenteditable" />
+ </Router>
+ </main>
+ </div>
+ );
+ }
+}
+
+function EmptyFragment() {
+ return <Fragment />;
+}
+
+// document.body.innerHTML = renderToString(<App url={location.href.match(/[#&]ssr/) ? undefined : '/'} />);
+// document.body.firstChild.setAttribute('is-ssr', 'true');
+
+installLogger(
+ String(localStorage.LOG) === 'true' || location.href.match(/logger/),
+ String(localStorage.CONSOLE) === 'true' || location.href.match(/console/)
+);
+
+render(<App />, document.body);
diff --git a/preact/demo/key_bug.js b/preact/demo/key_bug.js
new file mode 100644
index 0000000..0ccb1a6
--- /dev/null
+++ b/preact/demo/key_bug.js
@@ -0,0 +1,32 @@
+import { createElement, Component } from 'preact';
+
+function Foo(props) {
+ return <div>This is: {props.children}</div>;
+}
+
+export default class KeyBug extends Component {
+ constructor() {
+ super();
+ this.onClick = this.onClick.bind(this);
+ this.state = { active: false };
+ }
+
+ onClick() {
+ this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.active && <Foo>foo</Foo>}
+ <h1>Hello World</h1>
+ <br />
+ <Foo>
+ bar <Foo>bar</Foo>
+ </Foo>
+ <br />
+ <button onClick={this.onClick}>Toggle</button>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/list.js b/preact/demo/list.js
new file mode 100644
index 0000000..2ef968c
--- /dev/null
+++ b/preact/demo/list.js
@@ -0,0 +1,63 @@
+import { h, render } from 'preact';
+import htm from 'htm';
+import './style.css';
+
+const html = htm.bind(h);
+const createRoot = parent => ({
+ render: v => render(v, parent)
+});
+
+function List({ items, renders, useKeys, useCounts, update }) {
+ const toggleKeys = () => update({ useKeys: !useKeys });
+ const toggleCounts = () => update({ useCounts: !useCounts });
+ const swap = () => {
+ const u = { items: items.slice() };
+ u.items[1] = items[8];
+ u.items[8] = items[1];
+ update(u);
+ };
+ return html`
+ <div>
+ <button onClick=${update}>Re-render</button>
+ <button onClick=${swap}>Swap 2 & 8</button>
+ <label>
+ <input type="checkbox" checked=${useKeys} onClick=${toggleKeys} />
+ Use Keys
+ </label>
+ <label>
+ <input type="checkbox" checked=${useCounts} onClick=${toggleCounts} />
+ Counts
+ </label>
+ <ul class="list">
+ ${items.map(
+ (item, i) => html`
+ <li
+ class=${i % 2 ? 'odd' : 'even'}
+ key=${useKeys ? item.name : undefined}
+ >
+ ${item.name} ${useCounts ? ` (${renders} renders)` : ''}
+ </li>
+ `
+ )}
+ </ul>
+ </div>
+ `;
+}
+
+const root = createRoot(document.body);
+
+let data = {
+ items: new Array(1000).fill(null).map((x, i) => ({ name: `Item ${i + 1}` })),
+ renders: 0,
+ useKeys: false,
+ useCounts: false
+};
+
+function update(partial) {
+ if (partial) Object.assign(data, partial);
+ data.renders++;
+ data.update = update;
+ root.render(List(data));
+}
+
+update();
diff --git a/preact/demo/logger.js b/preact/demo/logger.js
new file mode 100644
index 0000000..59df9b9
--- /dev/null
+++ b/preact/demo/logger.js
@@ -0,0 +1,170 @@
+export default function logger(logStats, logConsole) {
+ if (!logStats && !logConsole) {
+ return;
+ }
+
+ const consoleBuffer = new ConsoleBuffer();
+
+ let calls = {};
+ let lock = true;
+
+ function serialize(obj) {
+ if (obj instanceof Text) return '#text';
+ if (obj instanceof Element) return `<${obj.localName}>`;
+ if (obj === document) return 'document';
+ return Object.prototype.toString.call(obj).replace(/(^\[object |\]$)/g, '');
+ }
+
+ function count(key) {
+ if (lock === true) return;
+ calls[key] = (calls[key] || 0) + 1;
+
+ if (logConsole) {
+ consoleBuffer.log(key);
+ }
+ }
+
+ function logCall(obj, method, name) {
+ let old = obj[method];
+ obj[method] = function() {
+ let c = '';
+ for (let i = 0; i < arguments.length; i++) {
+ if (c) c += ', ';
+ c += serialize(arguments[i]);
+ }
+ count(`${serialize(this)}.${method}(${c})`);
+ return old.apply(this, arguments);
+ };
+ }
+
+ logCall(document, 'createElement');
+ logCall(document, 'createElementNS');
+ logCall(Element.prototype, 'remove');
+ logCall(Element.prototype, 'appendChild');
+ logCall(Element.prototype, 'removeChild');
+ logCall(Element.prototype, 'insertBefore');
+ logCall(Element.prototype, 'replaceChild');
+ logCall(Element.prototype, 'setAttribute');
+ logCall(Element.prototype, 'setAttributeNS');
+ logCall(Element.prototype, 'removeAttribute');
+ logCall(Element.prototype, 'removeAttributeNS');
+ let d =
+ Object.getOwnPropertyDescriptor(CharacterData.prototype, 'data') ||
+ Object.getOwnPropertyDescriptor(Node.prototype, 'data');
+ Object.defineProperty(Text.prototype, 'data', {
+ get() {
+ let value = d.get.call(this);
+ count(`get #text.data`);
+ return value;
+ },
+ set(v) {
+ count(`set #text.data`);
+ return d.set.call(this, v);
+ }
+ });
+
+ let root;
+ function setup() {
+ if (!logStats) return;
+
+ lock = true;
+ root = document.createElement('table');
+ root.style.cssText =
+ 'position: fixed; right: 0; top: 0; z-index:999; background: #000; font-size: 12px; color: #FFF; opacity: 0.9; white-space: nowrap;';
+ let header = document.createElement('thead');
+ header.innerHTML =
+ '<tr><td colspan="2">Stats <button id="clear-logs">clear</button></td></tr>';
+ root.tableBody = document.createElement('tbody');
+ root.appendChild(root.tableBody);
+ root.appendChild(header);
+ document.documentElement.appendChild(root);
+ let btn = document.getElementById('clear-logs');
+ btn.addEventListener('click', () => {
+ for (let key in calls) {
+ calls[key] = 0;
+ }
+ });
+ lock = false;
+ }
+
+ let rows = {};
+ function createRow(id) {
+ let row = document.createElement('tr');
+ row.key = document.createElement('td');
+ row.key.textContent = id;
+ row.appendChild(row.key);
+ row.value = document.createElement('td');
+ row.value.textContent = ' ';
+ row.appendChild(row.value);
+ root.tableBody.appendChild(row);
+ return (rows[id] = row);
+ }
+
+ function insertInto(parent) {
+ parent.appendChild(root);
+ }
+
+ function remove() {
+ clearInterval(updateTimer);
+ }
+
+ function update() {
+ if (!logStats) return;
+
+ lock = true;
+ for (let i in calls) {
+ if (calls.hasOwnProperty(i)) {
+ let row = rows[i] || createRow(i);
+ row.value.firstChild.nodeValue = calls[i];
+ }
+ }
+ lock = false;
+ }
+
+ let updateTimer = setInterval(update, 50);
+
+ setup();
+ lock = false;
+ return { insertInto, update, remove };
+}
+
+/**
+ * Logging to the console significantly affects performance.
+ * Buffer calls to console and replay them at the end of the
+ * current stack
+ * @extends {Console}
+ */
+class ConsoleBuffer {
+ constructor() {
+ /** @type {Array<[string, any[]]>} */
+ this.buffer = [];
+ this.deferred = null;
+
+ for (let methodName of Object.keys(console)) {
+ this[methodName] = this.proxy(methodName);
+ }
+ }
+
+ proxy(methodName) {
+ return (...args) => {
+ this.buffer.push([methodName, args]);
+ this.deferFlush();
+ };
+ }
+
+ deferFlush() {
+ if (this.deferred == null) {
+ this.deferred = Promise.resolve()
+ .then(() => this.flush())
+ .then(() => (this.deferred = null));
+ }
+ }
+
+ flush() {
+ let method;
+ while ((method = this.buffer.shift())) {
+ let [name, args] = method;
+ console[name](...args);
+ }
+ }
+}
diff --git a/preact/demo/mobx.js b/preact/demo/mobx.js
new file mode 100644
index 0000000..8e4159f
--- /dev/null
+++ b/preact/demo/mobx.js
@@ -0,0 +1,75 @@
+import React, { createElement, forwardRef, useRef, useState } from 'react';
+import { decorate, observable } from 'mobx';
+import { observer, useObserver } from 'mobx-react';
+import 'mobx-react-lite/batchingForReactDom';
+
+class Todo {
+ constructor() {
+ this.id = Math.random();
+ this.title = 'initial';
+ this.finished = false;
+ }
+}
+decorate(Todo, {
+ title: observable,
+ finished: observable
+});
+
+const Forward = observer(
+ // eslint-disable-next-line react/display-name
+ forwardRef(({ todo }, ref) => {
+ return (
+ <p ref={ref}>
+ Forward: "{todo.title}" {'' + todo.finished}
+ </p>
+ );
+ })
+);
+
+const todo = new Todo();
+
+const TodoView = observer(({ todo }) => {
+ return (
+ <p>
+ Todo View: "{todo.title}" {'' + todo.finished}
+ </p>
+ );
+});
+
+const HookView = ({ todo }) => {
+ return useObserver(() => {
+ return (
+ <p>
+ Todo View: "{todo.title}" {'' + todo.finished}
+ </p>
+ );
+ });
+};
+
+export function MobXDemo() {
+ const ref = useRef(null);
+ let [v, set] = useState(0);
+
+ const success = ref.current && ref.current.nodeName === 'P';
+
+ return (
+ <div>
+ <input
+ type="text"
+ placeholder="type here..."
+ onInput={e => {
+ todo.title = e.target.value;
+ set(v + 1);
+ }}
+ />
+ <p>
+ <b style={`color: ${success ? 'green' : 'red'}`}>
+ {success ? 'SUCCESS' : 'FAIL'}
+ </b>
+ </p>
+ <TodoView todo={todo} />
+ <Forward todo={todo} ref={ref} />
+ <HookView todo={todo} />
+ </div>
+ );
+}
diff --git a/preact/demo/nested-suspense/addnewcomponent.js b/preact/demo/nested-suspense/addnewcomponent.js
new file mode 100644
index 0000000..e3e4695
--- /dev/null
+++ b/preact/demo/nested-suspense/addnewcomponent.js
@@ -0,0 +1,5 @@
+import { createElement } from 'react';
+
+export default function AddNewComponent({ appearance }) {
+ return <div>AddNewComponent (component #{appearance})</div>;
+}
diff --git a/preact/demo/nested-suspense/component-container.js b/preact/demo/nested-suspense/component-container.js
new file mode 100644
index 0000000..b1da87b
--- /dev/null
+++ b/preact/demo/nested-suspense/component-container.js
@@ -0,0 +1,17 @@
+import { createElement, lazy } from 'react';
+
+const pause = timeout =>
+ new Promise(d => setTimeout(d, timeout), console.log(timeout));
+
+const SubComponent = lazy(() =>
+ pause(Math.random() * 1000).then(() => import('./subcomponent.js'))
+);
+
+export default function ComponentContainer({ appearance }) {
+ return (
+ <div>
+ GenerateComponents (component #{appearance})
+ <SubComponent />
+ </div>
+ );
+}
diff --git a/preact/demo/nested-suspense/dropzone.js b/preact/demo/nested-suspense/dropzone.js
new file mode 100644
index 0000000..c4a28b4
--- /dev/null
+++ b/preact/demo/nested-suspense/dropzone.js
@@ -0,0 +1,5 @@
+import { createElement } from 'react';
+
+export default function DropZone({ appearance }) {
+ return <div>DropZone (component #{appearance})</div>;
+}
diff --git a/preact/demo/nested-suspense/editor.js b/preact/demo/nested-suspense/editor.js
new file mode 100644
index 0000000..253d130
--- /dev/null
+++ b/preact/demo/nested-suspense/editor.js
@@ -0,0 +1,5 @@
+import { createElement } from 'react';
+
+export default function Editor({ children }) {
+ return <div className="Editor">{children}</div>;
+}
diff --git a/preact/demo/nested-suspense/index.js b/preact/demo/nested-suspense/index.js
new file mode 100644
index 0000000..6c525b3
--- /dev/null
+++ b/preact/demo/nested-suspense/index.js
@@ -0,0 +1,69 @@
+import { createElement, Suspense, lazy, Component } from 'react';
+
+const Loading = function() {
+ return <div>Loading...</div>;
+};
+const Error = function({ resetState }) {
+ return (
+ <div>
+ Error!&nbsp;
+ <a onClick={resetState} href="#">
+ Reset app
+ </a>
+ </div>
+ );
+};
+
+const pause = timeout =>
+ new Promise(d => setTimeout(d, timeout), console.log(timeout));
+
+const DropZone = lazy(() =>
+ pause(Math.random() * 1000).then(() => import('./dropzone.js'))
+);
+const Editor = lazy(() =>
+ pause(Math.random() * 1000).then(() => import('./editor.js'))
+);
+const AddNewComponent = lazy(() =>
+ pause(Math.random() * 1000).then(() => import('./addnewcomponent.js'))
+);
+const GenerateComponents = lazy(() =>
+ pause(Math.random() * 1000).then(() => import('./component-container.js'))
+);
+
+export default class App extends Component {
+ state = { hasError: false };
+
+ static getDerivedStateFromError(error) {
+ // Update state so the next render will show the fallback UI.
+ console.warn(error);
+ return { hasError: true };
+ }
+
+ render() {
+ return this.state.hasError ? (
+ <Error resetState={() => this.setState({ hasError: false })} />
+ ) : (
+ <Suspense fallback={<Loading />}>
+ <DropZone appearance={0} />
+ <Editor title="APP_TITLE">
+ <main>
+ <Suspense fallback={<Loading />}>
+ <GenerateComponents appearance={1} />
+ </Suspense>
+ <AddNewComponent appearance={2} />
+ </main>
+ <aside>
+ <section>
+ <Suspense fallback={<Loading />}>
+ <GenerateComponents appearance={3} />
+ </Suspense>
+ <AddNewComponent appearance={4} />
+ </section>
+ </aside>
+ </Editor>
+
+ <footer>Footer here</footer>
+ </Suspense>
+ );
+ }
+}
diff --git a/preact/demo/nested-suspense/subcomponent.js b/preact/demo/nested-suspense/subcomponent.js
new file mode 100644
index 0000000..74d6d1d
--- /dev/null
+++ b/preact/demo/nested-suspense/subcomponent.js
@@ -0,0 +1,5 @@
+import { createElement } from 'react';
+
+export default function SubComponent({ onClick }) {
+ return <div>Lazy loaded sub component</div>;
+}
diff --git a/preact/demo/old.js.bak b/preact/demo/old.js.bak
new file mode 100644
index 0000000..7f2b7c0
--- /dev/null
+++ b/preact/demo/old.js.bak
@@ -0,0 +1,103 @@
+
+// function createRoot(title) {
+// let div = document.createElement('div');
+// let h2 = document.createElement('h2');
+// h2.textContent = title;
+// div.appendChild(h2);
+// document.body.appendChild(div);
+// return div;
+// }
+
+
+/*
+function logCall(obj, method, name) {
+ let old = obj[method];
+ obj[method] = function(...args) {
+ console.log(`<${this.localName}>.`+(name || `${method}(${args})`));
+ return old.apply(this, args);
+ };
+}
+
+logCall(HTMLElement.prototype, 'appendChild');
+logCall(HTMLElement.prototype, 'removeChild');
+logCall(HTMLElement.prototype, 'insertBefore');
+logCall(HTMLElement.prototype, 'replaceChild');
+logCall(HTMLElement.prototype, 'setAttribute');
+logCall(HTMLElement.prototype, 'removeAttribute');
+let d = Object.getOwnPropertyDescriptor(Node.prototype, 'nodeValue');
+Object.defineProperty(Text.prototype, 'nodeValue', {
+ get() {
+ let value = d.get.call(this);
+ console.log('get Text#nodeValue: ', value);
+ return value;
+ },
+ set(v) {
+ console.log('set Text#nodeValue', v);
+ return d.set.call(this, v);
+ }
+});
+
+
+render((
+ <div>
+ <h4>This is a test.</h4>
+ <Foo />
+ <time>...</time>
+ </div>
+), createRoot('Stateful component update demo:'));
+
+
+class Foo extends Component {
+ componentDidMount() {
+ console.log('mounted');
+ this.timer = setInterval( () => {
+ this.setState({ time: Date.now() });
+ }, 5000);
+ }
+ componentWillUnmount() {
+ clearInterval(this.timer);
+ }
+ render(props, state, context) {
+ // console.log('rendering', props, state, context);
+ return <time>test: {state.time}</time>
+ }
+}
+
+
+render((
+ <div>
+ <h4>This is a test.</h4>
+ <Foo />
+ <time>...</time>
+ </div>
+), createRoot('Stateful component update demo:'));
+
+
+let items = [];
+let count = 0;
+let three = createRoot('Top-level render demo:');
+
+setInterval( () => {
+ if (count++ %20 < 10 ) {
+ items.push(<li key={count} style={{
+ position: 'relative',
+ transition: 'all 200ms ease',
+ paddingLeft: items.length*20 +'px'
+ }}>item #{items.length}</li>);
+ }
+ else {
+ items.shift();
+ }
+
+ render((
+ <div>
+ <h4>This is a test.</h4>
+ <time>{Date.now()}</time>
+ <ul>{items}</ul>
+ </div>
+ ), three);
+}, 5000);
+
+// Mount the top-level component to the DOM:
+render(<Main />, document.body);
+*/
diff --git a/preact/demo/package.json b/preact/demo/package.json
new file mode 100644
index 0000000..21cfb36
--- /dev/null
+++ b/preact/demo/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "demo",
+ "main": "index.js",
+ "scripts": {
+ "start": "webpack-dev-server --inline"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.0.0-beta.55",
+ "@babel/plugin-proposal-class-properties": "^7.0.0-beta.55",
+ "@babel/plugin-proposal-decorators": "^7.4.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.2.0",
+ "@babel/plugin-transform-react-constant-elements": "^7.0.0-beta.55",
+ "@babel/plugin-transform-react-jsx": "^7.0.0-beta.55",
+ "@babel/plugin-transform-runtime": "^7.4.0",
+ "@babel/preset-env": "^7.0.0-beta.55",
+ "@babel/preset-react": "^7.0.0-beta.55",
+ "@babel/preset-typescript": "^7.3.3",
+ "babel-loader": "^8.0.0-beta.0",
+ "css-loader": "2.1.1",
+ "html-webpack-plugin": "3.2.0",
+ "node-sass": "^4.12.0",
+ "sass-loader": "7.1.0",
+ "style-loader": "0.23.1",
+ "webpack": "4.33.0",
+ "webpack-cli": "^3.3.4",
+ "webpack-dev-server": "^3.7.1"
+ },
+ "dependencies": {
+ "@material-ui/core": "4.9.5",
+ "d3-scale": "^1.0.7",
+ "d3-selection": "^1.2.0",
+ "htm": "2.1.1",
+ "mobx": "^5.15.4",
+ "mobx-react": "^6.2.2",
+ "mobx-state-tree": "^3.16.0",
+ "preact-render-to-string": "^5.0.2",
+ "preact-router": "^3.0.0",
+ "react-redux": "^7.1.0",
+ "react-router": "^5.0.1",
+ "react-router-dom": "^5.0.1",
+ "redux": "^4.0.1",
+ "styled-components": "^4.2.0"
+ }
+}
diff --git a/preact/demo/people/Readme.md b/preact/demo/people/Readme.md
new file mode 100644
index 0000000..c18a1cb
--- /dev/null
+++ b/preact/demo/people/Readme.md
@@ -0,0 +1,3 @@
+# People demo page
+
+This section of our demo was originally made by [phaux](https://github.com/phaux) in the [web-app-boilerplate](https://github.com/phaux/web-app-boilerplate) repo. It has been slightly modified from it's original to better work inside of our demo app
diff --git a/preact/demo/people/index.tsx b/preact/demo/people/index.tsx
new file mode 100644
index 0000000..0e728ab
--- /dev/null
+++ b/preact/demo/people/index.tsx
@@ -0,0 +1,59 @@
+import { observer } from 'mobx-react';
+import { Component, h } from 'preact';
+import { Profile } from './profile';
+import { Link, Route, Router } from './router';
+import { store } from './store';
+
+import './styles/index.scss';
+
+@observer
+export default class App extends Component {
+ componentDidMount() {
+ store.loadUsers().catch(console.error);
+ }
+
+ render() {
+ return (
+ <Router>
+ <div id="people-app">
+ <nav>
+ <div style={{ margin: 16, textAlign: 'center' }}>
+ Sort by{' '}
+ <select
+ value={store.usersOrder}
+ onChange={(ev: any) => {
+ store.setUsersOrder(ev.target.value);
+ }}
+ >
+ <option value="name">Name</option>
+ <option value="id">ID</option>
+ </select>
+ </div>
+ <ul>
+ {store.getSortedUsers().map((user, i) => (
+ <li
+ key={user.id}
+ style={{
+ animationDelay: `${i * 20}ms`,
+ top: `calc(var(--menu-item-height) * ${i})`,
+ transitionDelay: `${i * 20}ms`
+ }}
+ >
+ <Link href={`people/${user.id}`} active>
+ <img class="avatar" src={user.picture.large} />
+ {user.name.first} {user.name.last}
+ </Link>
+ </li>
+ ))}
+ </ul>
+ </nav>
+ <section id="people-main">
+ <Route match="people">
+ <Route match="*" component={Profile} />
+ </Route>
+ </section>
+ </div>
+ </Router>
+ );
+ }
+}
diff --git a/preact/demo/people/profile.tsx b/preact/demo/people/profile.tsx
new file mode 100644
index 0000000..e1f44ea
--- /dev/null
+++ b/preact/demo/people/profile.tsx
@@ -0,0 +1,59 @@
+import { computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { Component, h } from 'preact';
+import { RouteChildProps } from './router';
+import { store } from './store';
+
+export type ProfileProps = RouteChildProps;
+@observer
+export class Profile extends Component<ProfileProps> {
+ @observable id = '';
+ @observable busy = false;
+
+ componentDidMount() {
+ this.id = this.props.route;
+ }
+
+ componentWillReceiveProps(props: ProfileProps) {
+ this.id = props.route;
+ }
+
+ render() {
+ const user = this.user;
+ if (user == null) return null;
+ return (
+ <div class="profile">
+ <img class="avatar" src={user.picture.large} />
+ <h2>
+ {user.name.first} {user.name.last}
+ </h2>
+ <div class="details">
+ <p>
+ {user.gender === 'female' ? '👩' : '👨'} {user.id}
+ </p>
+ <p>🖂 {user.email}</p>
+ </div>
+ <p>
+ <button
+ class={this.busy ? 'secondary busy' : 'secondary'}
+ disabled={this.busy}
+ onClick={this.remove}
+ >
+ Remove contact
+ </button>
+ </p>
+ </div>
+ );
+ }
+
+ @computed get user() {
+ return store.users.find(u => u.id === this.id);
+ }
+
+ remove = async () => {
+ this.busy = true;
+ await new Promise<void>(cb => setTimeout(cb, 1500));
+ store.deleteUser(this.id);
+ this.busy = false;
+ };
+}
diff --git a/preact/demo/people/router.tsx b/preact/demo/people/router.tsx
new file mode 100644
index 0000000..56fc420
--- /dev/null
+++ b/preact/demo/people/router.tsx
@@ -0,0 +1,153 @@
+import {
+ ComponentChild,
+ ComponentFactory,
+ createContext,
+ FunctionalComponent,
+ h,
+ JSX
+} from 'preact';
+import {
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useState
+} from 'preact/hooks';
+
+export type RouterData = {
+ match: string[];
+ path: string[];
+ navigate(path: string): void;
+};
+
+const RouterContext = createContext<RouterData>({
+ match: [],
+ path: [],
+ navigate() {}
+});
+export const useRouter = () => useContext(RouterContext);
+
+const useLocation = (cb: () => void) => {
+ useEffect(() => {
+ window.addEventListener('popstate', cb);
+ return () => {
+ window.removeEventListener('popstate', cb);
+ };
+ }, [cb]);
+};
+
+export const Router: FunctionalComponent = props => {
+ const [path, setPath] = useState(location.pathname);
+
+ const update = useCallback(() => {
+ setPath(location.pathname);
+ }, [setPath]);
+
+ useLocation(update);
+
+ const navigate = useCallback(
+ (path: string) => {
+ history.pushState(null, '', path);
+ update();
+ },
+ [update]
+ );
+
+ const router = useMemo<RouterData>(
+ () => ({
+ match: [],
+ navigate,
+ path: path.split('/').filter(Boolean)
+ }),
+ [navigate, path]
+ );
+
+ return <RouterContext.Provider children={props.children} value={router} />;
+};
+
+export type RouteChildProps = { route: string };
+export type RouteProps = {
+ component?: ComponentFactory<RouteChildProps>;
+ match: string;
+ render?(route: string): ComponentChild;
+};
+export const Route: FunctionalComponent<RouteProps> = props => {
+ const router = useRouter();
+ const [dir, ...subpath] = router.path;
+
+ if (dir == null) return null;
+ if (props.match !== '*' && dir !== props.match) return null;
+
+ const children = useMemo(() => {
+ if (props.component) return <props.component key={dir} route={dir} />;
+ if (props.render) return props.render(dir);
+ return props.children;
+ }, [props.component, props.render, props.children, dir]);
+
+ const innerRouter = useMemo<RouterData>(
+ () => ({
+ ...router,
+ match: [...router.match, dir],
+ path: subpath
+ }),
+ [router.match, dir, subpath.join('/')]
+ );
+
+ return <RouterContext.Provider children={children} value={innerRouter} />;
+};
+
+export type LinkProps = JSX.HTMLAttributes & {
+ active?: boolean | string;
+};
+export const Link: FunctionalComponent<LinkProps> = props => {
+ const router = useRouter();
+
+ const classProps = [props.class, props.className];
+ const originalClasses = useMemo(() => {
+ const classes = [];
+ for (const prop of classProps) if (prop) classes.push(...prop.split(/\s+/));
+ return classes;
+ }, classProps);
+
+ const activeClass = useMemo(() => {
+ if (!props.active || props.href == null) return undefined;
+ const href = props.href.split('/').filter(Boolean);
+ const path =
+ props.href[0] === '/' ? [...router.match, ...router.path] : router.path;
+ const isMatch = href.every((dir, i) => dir === path[i]);
+ if (isMatch) return props.active === true ? 'active' : props.active;
+ }, [originalClasses, props.active, props.href, router.match, router.path]);
+
+ const classes =
+ activeClass == null ? originalClasses : [...originalClasses, activeClass];
+
+ const getHref = useCallback(() => {
+ if (props.href == null || props.href[0] === '/') return props.href;
+ const path = props.href.split('/').filter(Boolean);
+ return '/' + [...router.match, ...path].join('/');
+ }, [router.match, props.href]);
+
+ const handleClick = useCallback(
+ (ev: MouseEvent) => {
+ const href = getHref();
+ if (props.onClick != null) props.onClick(ev);
+ if (ev.defaultPrevented) return;
+ if (href == null) return;
+ if (ev.button !== 0) return;
+ if (props.target != null && props.target !== '_self') return;
+ if (ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey) return;
+ ev.preventDefault();
+ router.navigate(href);
+ },
+ [getHref, router.navigate, props.onClick, props.target]
+ );
+
+ return (
+ <a
+ {...props}
+ class={classes.join(' ')}
+ href={getHref()}
+ onClick={handleClick}
+ />
+ );
+};
diff --git a/preact/demo/people/store.ts b/preact/demo/people/store.ts
new file mode 100644
index 0000000..1967afd
--- /dev/null
+++ b/preact/demo/people/store.ts
@@ -0,0 +1,83 @@
+import { flow, Instance, types } from 'mobx-state-tree';
+
+const cmp = <T, U>(fn: (x: T) => U) => (a: T, b: T): number =>
+ fn(a) > fn(b) ? 1 : -1;
+
+const User = types.model({
+ email: types.string,
+ gender: types.enumeration(['male', 'female']),
+ id: types.identifier,
+ name: types.model({
+ first: types.string,
+ last: types.string
+ }),
+ picture: types.model({
+ large: types.string
+ })
+});
+
+const Store = types
+ .model({
+ users: types.array(User),
+ usersOrder: types.enumeration(['name', 'id'])
+ })
+ .views(self => ({
+ getSortedUsers() {
+ if (self.usersOrder === 'name')
+ return self.users.slice().sort(cmp(x => x.name.first));
+ if (self.usersOrder === 'id')
+ return self.users.slice().sort(cmp(x => x.id));
+ throw Error(`Unknown ordering ${self.usersOrder}`);
+ }
+ }))
+ .actions(self => ({
+ addUser: flow<unknown, []>(function*() {
+ const data = yield fetch('https://randomuser.me/api?results=1')
+ .then(res => res.json())
+ .then(data =>
+ data.results.map((user: any) => ({
+ ...user,
+ id: user.login.username
+ }))
+ );
+ self.users.push(...data);
+ }),
+ loadUsers: flow<unknown, []>(function*() {
+ const data = yield fetch(
+ `https://randomuser.me/api?seed=${12321}&results=12`
+ )
+ .then(res => res.json())
+ .then(data =>
+ data.results.map((user: any) => ({
+ ...user,
+ id: user.login.username
+ }))
+ );
+ self.users.replace(data);
+ }),
+ deleteUser(id: string) {
+ const user = self.users.find(u => u.id === id);
+ if (user != null) self.users.remove(user);
+ },
+ setUsersOrder(order: 'name' | 'id') {
+ self.usersOrder = order;
+ }
+ }));
+
+export type StoreType = Instance<typeof Store>;
+export const store = Store.create({
+ usersOrder: 'name',
+ users: []
+});
+
+// const { Provider, Consumer } = createContext<StoreType>(undefined as any)
+
+// export const StoreProvider: FunctionalComponent = props => {
+// const store = Store.create({})
+// return <Provider value={store} children={props.children} />
+// }
+
+// export type StoreProps = {store: StoreType}
+// export function injectStore<T>(Child: AnyComponent<T & StoreProps>): FunctionalComponent<T> {
+// return props => <Consumer render={store => <Child {...props} store={store}/>}/>
+// }
diff --git a/preact/demo/people/styles/animations.scss b/preact/demo/people/styles/animations.scss
new file mode 100644
index 0000000..c7ce8cb
--- /dev/null
+++ b/preact/demo/people/styles/animations.scss
@@ -0,0 +1,34 @@
+@keyframes popup {
+ from {
+ box-shadow: 0 0 0 black;
+ opacity: 0;
+ transform: scale(0.9);
+ }
+ to {
+ box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5);
+ opacity: 1;
+ transform: none;
+ }
+}
+
+@keyframes zoom {
+ from {
+ opacity: 0;
+ transform: scale(0.8);
+ }
+ to {
+ opacity: 1;
+ transform: none;
+ }
+}
+
+@keyframes appear-from-left {
+ from {
+ opacity: 0;
+ transform: translateX(-25px);
+ }
+ to {
+ opacity: 1;
+ transform: none;
+ }
+}
diff --git a/preact/demo/people/styles/app.scss b/preact/demo/people/styles/app.scss
new file mode 100644
index 0000000..4473f9e
--- /dev/null
+++ b/preact/demo/people/styles/app.scss
@@ -0,0 +1,100 @@
+#people-app {
+ position: relative;
+ overflow: hidden;
+ min-height: 100vh;
+ animation: popup 300ms cubic-bezier(0.3, 0.7, 0.3, 1) forwards;
+ background: var(--app-background);
+ --menu-width: 260px;
+ --menu-item-height: 50px;
+
+ @media (min-width: 1280px) {
+ max-width: 1280px;
+ min-height: calc(100vh - 64px);
+ margin: 32px auto;
+ border-radius: 10px;
+ }
+
+ > nav {
+ position: absolute;
+ display: flow-root;
+ width: var(--menu-width);
+ height: 100%;
+ background-color: var(--app-background-secondary);
+ overflow-x: hidden;
+ overflow-y: auto;
+ }
+
+ > nav h4 {
+ padding-left: 16px;
+ font-weight: normal;
+ text-transform: uppercase;
+ }
+
+ > nav ul {
+ position: relative;
+ }
+
+ > nav li {
+ position: absolute;
+ width: 100%;
+ animation: zoom 200ms forwards;
+ opacity: 0;
+ transition: top 200ms;
+ }
+
+ > nav li > a {
+ position: relative;
+ display: flex;
+ overflow: hidden;
+ flex-flow: row;
+ align-items: center;
+ margin-left: 16px;
+ border-right: 2px solid transparent;
+ border-bottom-left-radius: 48px;
+ border-top-left-radius: 48px;
+ text-transform: capitalize;
+ transition: border 500ms;
+ }
+
+ > nav li > a:hover {
+ background-color: var(--app-highlight);
+ }
+
+ > nav li > a::after {
+ position: absolute;
+ top: 0;
+ right: -2px;
+ bottom: 0;
+ left: 0;
+ background-image: radial-gradient(
+ circle,
+ var(--app-ripple) 1%,
+ transparent 1%
+ );
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 10000%;
+ content: '';
+ opacity: 0;
+ transition: opacity 700ms, background 300ms;
+ }
+
+ > nav li > a:active::after {
+ background-size: 100%;
+ opacity: 0.5;
+ transition: none;
+ }
+
+ > nav li > a.active {
+ border-color: var(--app-primary);
+ background-color: var(--app-highlight);
+ }
+
+ > nav li > a > * {
+ margin: 8px;
+ }
+
+ #people-main {
+ padding-left: var(--menu-width);
+ }
+}
diff --git a/preact/demo/people/styles/avatar.scss b/preact/demo/people/styles/avatar.scss
new file mode 100644
index 0000000..437c6c4
--- /dev/null
+++ b/preact/demo/people/styles/avatar.scss
@@ -0,0 +1,16 @@
+#people-app {
+ .avatar {
+ display: inline-block;
+ overflow: hidden;
+ width: var(--avatar-size, 32px);
+ height: var(--avatar-size, 32px);
+ background-color: var(--avatar-color, var(--app-primary));
+ border-radius: 50%;
+ font-size: calc(var(--avatar-size, 32px) * 0.5);
+ line-height: var(--avatar-size, 32px);
+ object-fit: cover;
+ text-align: center;
+ text-transform: uppercase;
+ white-space: nowrap;
+ }
+}
diff --git a/preact/demo/people/styles/button.scss b/preact/demo/people/styles/button.scss
new file mode 100644
index 0000000..ce43138
--- /dev/null
+++ b/preact/demo/people/styles/button.scss
@@ -0,0 +1,115 @@
+#people-app {
+ button {
+ position: relative;
+ overflow: hidden;
+ min-width: 36px;
+ height: 36px;
+ padding: 0 16px;
+ border: none;
+ background-color: transparent;
+ border-radius: 4px;
+ color: var(--app-text);
+ font-family: 'Montserrat', sans-serif;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ transition: background 300ms, color 200ms;
+ white-space: nowrap;
+ }
+
+ button::before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: var(--app-ripple);
+ content: '';
+ opacity: 0;
+ transition: opacity 200ms;
+ }
+
+ button:hover:not(:disabled)::before {
+ opacity: 0.3;
+ transition: opacity 100ms;
+ }
+
+ button:active:not(:disabled)::before {
+ opacity: 0.7;
+ transition: none;
+ }
+
+ button::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-image: radial-gradient(
+ circle,
+ var(--app-ripple) 1%,
+ transparent 1%
+ );
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 20000%;
+ content: '';
+ opacity: 0;
+ transition: opacity 700ms, background 400ms;
+ }
+
+ button:active:not(:disabled)::after {
+ background-size: 100%;
+ opacity: 1;
+ transition: none;
+ }
+
+ button.primary {
+ background-color: var(--app-primary);
+ box-shadow: 0 2px 6px var(--app-shadow);
+ }
+
+ button.secondary {
+ background-color: var(--app-secondary);
+ box-shadow: 0 2px 6px var(--app-shadow);
+ }
+
+ button:disabled {
+ color: var(--app-text-secondary);
+ }
+
+ button.busy {
+ animation: stripes 500ms linear infinite;
+ background-image: repeating-linear-gradient(
+ 45deg,
+ var(--app-shadow) 0%,
+ var(--app-shadow) 25%,
+ transparent 25%,
+ transparent 50%,
+ var(--app-shadow) 50%,
+ var(--app-shadow) 75%,
+ transparent 75%,
+ transparent 100%
+ );
+ color: var(--app-text);
+ /* letter-spacing: -.7em; */
+ }
+
+ button:disabled:not(.primary):not(.secondary).busy,
+ button:disabled.primary:not(.busy),
+ button:disabled.secondary:not(.busy) {
+ background-color: var(--app-background-disabled);
+ }
+
+ @keyframes stripes {
+ from {
+ background-position-x: 0;
+ background-size: 16px 16px;
+ }
+ to {
+ background-position-x: 16px;
+ background-size: 16px 16px;
+ }
+ }
+}
diff --git a/preact/demo/people/styles/index.scss b/preact/demo/people/styles/index.scss
new file mode 100644
index 0000000..80b342e
--- /dev/null
+++ b/preact/demo/people/styles/index.scss
@@ -0,0 +1,168 @@
+@import 'app.scss';
+@import 'animations.scss';
+@import 'avatar.scss';
+@import 'profile.scss';
+@import 'button.scss';
+
+// :root {
+#people-app {
+ --app-background: #2f2b43;
+ --app-background-secondary: #353249;
+ --app-background-disabled: #555366;
+ --app-highlight: rgba(255, 255, 255, 0.1);
+ --app-ripple: rgba(255, 255, 255, 0.5);
+ --app-shadow: rgba(0, 0, 0, 0.15);
+ --app-text: #fff;
+ --app-text-secondary: #807e97;
+ --app-primary: #ff0087;
+ --app-secondary: #4d7cfe;
+ --app-tertiary: #00ec97;
+ --app-danger: #f3c835;
+ --spinner-size: 200px;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+// body {
+#people-app {
+ // display: flow-root;
+ // overflow: auto;
+ // min-height: 100vh;
+ // margin: 0;
+ // animation: background-light 5s ease-out forwards;
+ // /* very fancy background */
+ // background: radial-gradient(
+ // circle 15px at 150px 90vh,
+ // rgba(255, 255, 255, 0.35),
+ // rgba(255, 255, 255, 0.35) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 9px at 60px 50vh,
+ // rgba(255, 255, 255, 0.55),
+ // rgba(255, 255, 255, 0.55) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 19px at 40vw 70px,
+ // rgba(255, 255, 255, 0.3),
+ // rgba(255, 255, 255, 0.3) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 12px at 80vw 80px,
+ // rgba(255, 255, 255, 0.4),
+ // rgba(255, 255, 255, 0.4) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 7px at 55vw calc(100vh - 95px),
+ // rgba(255, 255, 255, 0.6),
+ // rgba(255, 255, 255, 0.6) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 14px at 25vw calc(100vh - 35px),
+ // rgba(255, 255, 255, 0.4),
+ // rgba(255, 255, 255, 0.4) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 11px at calc(100vw - 95px) 55vh,
+ // rgba(255, 255, 255, 0.45),
+ // rgba(255, 255, 255, 0.45) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 13px at calc(100vw - 35px) 85vh,
+ // rgba(255, 255, 255, 0.4),
+ // rgba(255, 255, 255, 0.4) 90%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 50vw at 0 -25%,
+ // rgba(255, 255, 255, 0.07),
+ // rgba(255, 255, 255, 0.07) 100%,
+ // transparent
+ // ),
+ // radial-gradient(
+ // circle 80vw at top left,
+ // rgba(255, 255, 255, 0.07),
+ // rgba(255, 255, 255, 0.07) 100%,
+ // transparent
+ // ),
+ // radial-gradient(circle at bottom right, #ef2fb8, transparent),
+ // radial-gradient(circle at top right, #c45af3, transparent),
+ // linear-gradient(#ee66ca, #ff47a6);
+ color: var(--app-text);
+ font-family: 'Montserrat', sans-serif;
+}
+
+#people-app {
+ .spinner {
+ position: absolute;
+ top: 200px;
+ left: calc(50% - var(--spinner-size) / 2);
+ width: var(--spinner-size);
+ height: var(--spinner-size);
+ animation: zoom 250ms 500ms forwards ease-out;
+ opacity: 0;
+ transition: opacity 200ms, transform 200ms ease-in;
+ }
+
+ .spinner.exit {
+ opacity: 0;
+ transform: scale(0.5);
+ }
+
+ .spinner::before,
+ .spinner::after {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: calc(var(--spinner-size) / 3);
+ height: calc(var(--spinner-size) / 3);
+ animation: spinner 2s infinite ease-in-out;
+ background-color: rgba(255, 255, 255, 0.6);
+ content: '';
+ }
+
+ .spinner::after {
+ animation-delay: -1s;
+ }
+
+ @keyframes spinner {
+ 25% {
+ transform: translateX(calc(var(--spinner-size) / 3 * 2 - 1px))
+ rotate(-90deg) scale(0.5);
+ }
+ 50% {
+ transform: translateX(calc(var(--spinner-size) / 3 * 2 - 1px))
+ translateY(calc(var(--spinner-size) / 3 * 2 - 1px)) rotate(-179deg);
+ }
+ 50.1% {
+ transform: translateX(calc(var(--spinner-size) / 3 * 2 - 1px))
+ translateY(calc(var(--spinner-size) / 3 * 2 - 1px)) rotate(-180deg);
+ }
+ 75% {
+ transform: translateX(0) translateY(calc(var(--spinner-size) / 3 * 2 - 1px))
+ rotate(-270deg) scale(0.5);
+ }
+ 100% {
+ transform: rotate(-360deg);
+ }
+ }
+
+ ul,
+ ol {
+ padding-left: 0;
+ list-style: none;
+ }
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ }
+}
diff --git a/preact/demo/people/styles/profile.scss b/preact/demo/people/styles/profile.scss
new file mode 100644
index 0000000..f74b760
--- /dev/null
+++ b/preact/demo/people/styles/profile.scss
@@ -0,0 +1,26 @@
+#people-app {
+ .profile {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ margin: 32px 0;
+ animation: appear-from-left 0.5s forwards;
+ --avatar-size: 80px;
+ }
+
+ .profile h2 {
+ text-transform: capitalize;
+ }
+
+ .profile .details {
+ display: flex;
+ flex-flow: column;
+ align-items: stretch;
+ margin: 16px auto;
+ }
+
+ .profile .details p {
+ margin-top: 8px;
+ margin-bottom: 8px;
+ }
+}
diff --git a/preact/demo/preact.js b/preact/demo/preact.js
new file mode 100644
index 0000000..9b053e0
--- /dev/null
+++ b/preact/demo/preact.js
@@ -0,0 +1,39 @@
+import {
+ options,
+ createElement,
+ cloneElement,
+ Component as CevicheComponent,
+ render
+} from 'preact';
+
+options.vnode = vnode => {
+ vnode.nodeName = vnode.type;
+ vnode.attributes = vnode.props;
+ vnode.children = vnode._children || [].concat(vnode.props.children || []);
+};
+
+function asArray(arr) {
+ return Array.isArray(arr) ? arr : [arr];
+}
+
+function normalize(obj) {
+ if (Array.isArray(obj)) {
+ return obj.map(normalize);
+ }
+ if ('type' in obj && !('attributes' in obj)) {
+ obj.attributes = obj.props;
+ }
+ return obj;
+}
+
+export function Component(props, context) {
+ CevicheComponent.call(this, props, context);
+ const render = this.render;
+ this.render = function(props, state, context) {
+ if (props.children) props.children = asArray(normalize(props.children));
+ return render.call(this, props, state, context);
+ };
+}
+Component.prototype = new CevicheComponent();
+
+export { createElement, createElement as h, cloneElement, render };
diff --git a/preact/demo/profiler.js b/preact/demo/profiler.js
new file mode 100644
index 0000000..bb44269
--- /dev/null
+++ b/preact/demo/profiler.js
@@ -0,0 +1,88 @@
+import { createElement, Component, options } from 'preact';
+
+function getPrimes(max) {
+ let sieve = [],
+ i,
+ j,
+ primes = [];
+ for (i = 2; i <= max; ++i) {
+ if (!sieve[i]) {
+ // i has not been marked -- it is prime
+ primes.push(i);
+ for (j = i << 1; j <= max; j += i) {
+ sieve[j] = true;
+ }
+ }
+ }
+ return primes.join('');
+}
+
+function Foo(props) {
+ return <div>{props.children}</div>;
+}
+
+function Bar() {
+ getPrimes(10000);
+ return (
+ <div>
+ <span>...yet another component</span>
+ </div>
+ );
+}
+
+function PrimeNumber(props) {
+ // Slow down rendering of this component
+ getPrimes(10);
+
+ return (
+ <div>
+ <span>I'm a slow component</span>
+ <br />
+ {props.children}
+ </div>
+ );
+}
+
+export default class ProfilerDemo extends Component {
+ constructor() {
+ super();
+ this.onClick = this.onClick.bind(this);
+ this.state = { counter: 0 };
+ }
+
+ componentDidMount() {
+ options._diff = vnode => (vnode.startTime = performance.now());
+ options.diffed = vnode => (vnode.endTime = performance.now());
+ }
+
+ componentWillUnmount() {
+ delete options._diff;
+ delete options.diffed;
+ }
+
+ onClick() {
+ this.setState(prev => ({ counter: ++prev.counter }));
+ }
+
+ render() {
+ return (
+ <div class="foo">
+ <h1>⚛ Preact</h1>
+ <p>
+ <b>Devtools Profiler integration 🕒</b>
+ </p>
+ <Foo>
+ <PrimeNumber>
+ <Foo>I'm a fast component</Foo>
+ <Bar />
+ </PrimeNumber>
+ </Foo>
+ <Foo>I'm the fastest component 🎉</Foo>
+ <span>Counter: {this.state.counter}</span>
+ <br />
+ <br />
+ <button onClick={this.onClick}>Force re-render</button>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/pythagoras/index.js b/preact/demo/pythagoras/index.js
new file mode 100644
index 0000000..470e304
--- /dev/null
+++ b/preact/demo/pythagoras/index.js
@@ -0,0 +1,86 @@
+import { createElement, Component } from 'preact';
+import { select as d3select, mouse as d3mouse } from 'd3-selection';
+import { scaleLinear } from 'd3-scale';
+import Pythagoras from './pythagoras';
+
+export default class PythagorasDemo extends Component {
+ svg = {
+ width: 1280,
+ height: 600
+ };
+
+ state = {
+ currentMax: 0,
+ baseW: 80,
+ heightFactor: 0,
+ lean: 0
+ };
+
+ realMax = 11;
+
+ svgRef = c => {
+ this.svgElement = c;
+ };
+
+ scaleFactor = scaleLinear()
+ .domain([this.svg.height, 0])
+ .range([0, 0.8]);
+
+ scaleLean = scaleLinear()
+ .domain([0, this.svg.width / 2, this.svg.width])
+ .range([0.5, 0, -0.5]);
+
+ onMouseMove = event => {
+ let [x, y] = d3mouse(this.svgElement);
+
+ this.setState({
+ heightFactor: this.scaleFactor(y),
+ lean: this.scaleLean(x)
+ });
+ };
+
+ restart = () => {
+ this.setState({ currentMax: 0 });
+ this.next();
+ };
+
+ next = () => {
+ let { currentMax } = this.state;
+
+ if (currentMax < this.realMax) {
+ this.setState({ currentMax: currentMax + 1 });
+ this.timer = setTimeout(this.next, 500);
+ }
+ };
+
+ componentDidMount() {
+ this.selected = d3select(this.svgElement).on('mousemove', this.onMouseMove);
+ this.next();
+ }
+
+ componentWillUnmount() {
+ this.selected.on('mousemove', null);
+ clearTimeout(this.timer);
+ }
+
+ render({}, { currentMax, baseW, heightFactor, lean }) {
+ let { width, height } = this.svg;
+
+ return (
+ <div class="App">
+ <svg width={width} height={height} ref={this.svgRef}>
+ <Pythagoras
+ w={baseW}
+ h={baseW}
+ heightFactor={heightFactor}
+ lean={lean}
+ x={width / 2 - 40}
+ y={height - baseW}
+ lvl={0}
+ maxlvl={currentMax}
+ />
+ </svg>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/pythagoras/pythagoras.js b/preact/demo/pythagoras/pythagoras.js
new file mode 100644
index 0000000..bbe3c65
--- /dev/null
+++ b/preact/demo/pythagoras/pythagoras.js
@@ -0,0 +1,97 @@
+import { interpolateViridis } from 'd3-scale';
+import { createElement } from 'preact';
+
+Math.deg = function(radians) {
+ return radians * (180 / Math.PI);
+};
+
+const memoizedCalc = (function() {
+ const memo = {};
+
+ const key = ({ w, heightFactor, lean }) => `${w}-${heightFactor}-${lean}`;
+
+ return args => {
+ let memoKey = key(args);
+
+ if (memo[memoKey]) {
+ return memo[memoKey];
+ }
+
+ let { w, heightFactor, lean } = args;
+ let trigH = heightFactor * w;
+
+ let result = {
+ nextRight: Math.sqrt(trigH ** 2 + (w * (0.5 + lean)) ** 2),
+ nextLeft: Math.sqrt(trigH ** 2 + (w * (0.5 - lean)) ** 2),
+ A: Math.deg(Math.atan(trigH / ((0.5 - lean) * w))),
+ B: Math.deg(Math.atan(trigH / ((0.5 + lean) * w)))
+ };
+
+ memo[memoKey] = result;
+ return result;
+ };
+})();
+
+export default function Pythagoras({
+ w,
+ x,
+ y,
+ heightFactor,
+ lean,
+ left,
+ right,
+ lvl,
+ maxlvl
+}) {
+ if (lvl >= maxlvl || w < 1) {
+ return null;
+ }
+
+ const { nextRight, nextLeft, A, B } = memoizedCalc({
+ w,
+ heightFactor,
+ lean
+ });
+
+ let rotate = '';
+
+ if (left) {
+ rotate = `rotate(${-A} 0 ${w})`;
+ } else if (right) {
+ rotate = `rotate(${B} ${w} ${w})`;
+ }
+
+ return (
+ <g transform={`translate(${x} ${y}) ${rotate}`}>
+ <rect
+ width={w}
+ height={w}
+ x={0}
+ y={0}
+ style={{ fill: interpolateViridis(lvl / maxlvl) }}
+ />
+
+ <Pythagoras
+ w={nextLeft}
+ x={0}
+ y={-nextLeft}
+ lvl={lvl + 1}
+ maxlvl={maxlvl}
+ heightFactor={heightFactor}
+ lean={lean}
+ left
+ />
+
+ <Pythagoras
+ w={nextRight}
+ x={w - nextRight}
+ y={-nextRight}
+ lvl={lvl + 1}
+ maxlvl={maxlvl}
+ heightFactor={heightFactor}
+ lean={lean}
+ right
+ />
+ </g>
+ );
+}
diff --git a/preact/demo/redux.js b/preact/demo/redux.js
new file mode 100644
index 0000000..d63dfb7
--- /dev/null
+++ b/preact/demo/redux.js
@@ -0,0 +1,48 @@
+import { createElement } from 'preact';
+import React from 'react';
+import { createStore } from 'redux';
+import { connect, Provider } from 'react-redux';
+
+const store = createStore((state = { value: 0 }, action) => {
+ switch (action.type) {
+ case 'increment':
+ return { value: state.value + 1 };
+ case 'decrement':
+ return { value: state.value - 1 };
+ default:
+ return state;
+ }
+});
+
+class Child extends React.Component {
+ render() {
+ return (
+ <div>
+ <div>Child #1: {this.props.foo}</div>
+ <ConnectedChild2 />
+ </div>
+ );
+ }
+}
+const ConnectedChild = connect(store => ({ foo: store.value }))(Child);
+
+class Child2 extends React.Component {
+ render() {
+ return <div>Child #2: {this.props.foo}</div>;
+ }
+}
+const ConnectedChild2 = connect(store => ({ foo: store.value }))(Child2);
+
+export default function Redux() {
+ return (
+ <div>
+ <h1>Counter</h1>
+ <Provider store={store}>
+ <ConnectedChild />
+ </Provider>
+ <br />
+ <button onClick={() => store.dispatch({ type: 'increment' })}>+</button>
+ <button onClick={() => store.dispatch({ type: 'decrement' })}>-</button>
+ </div>
+ );
+}
diff --git a/preact/demo/reduxUpdate.js b/preact/demo/reduxUpdate.js
new file mode 100644
index 0000000..37e1f9c
--- /dev/null
+++ b/preact/demo/reduxUpdate.js
@@ -0,0 +1,61 @@
+import { createElement, Component } from 'preact';
+import { connect, Provider } from 'react-redux';
+import { createStore } from 'redux';
+import { HashRouter, Route, Link } from 'react-router-dom';
+
+const store = createStore(
+ (state, action) => ({ ...state, display: action.display }),
+ { display: false }
+);
+
+function _Redux({ showMe, counter }) {
+ if (!showMe) return null;
+ return <div>showMe {counter}</div>;
+}
+const Redux = connect(
+ state => console.log('injecting', state.display) || { showMe: state.display }
+)(_Redux);
+
+let display = false;
+class Test extends Component {
+ componentDidUpdate(prevProps) {
+ if (this.props.start != prevProps.start) {
+ this.setState({ f: (this.props.start || 0) + 1 });
+ setTimeout(() => this.setState({ i: (this.state.i || 0) + 1 }));
+ }
+ }
+
+ render() {
+ const { f } = this.state;
+ return (
+ <div>
+ <button
+ onClick={() => {
+ display = !display;
+ store.dispatch({ type: 1, display });
+ }}
+ >
+ Toggle visibility
+ </button>
+ <Link to={`/${(parseInt(this.props.start) || 0) + 1}`}>Click me</Link>
+
+ <Redux counter={f} />
+ </div>
+ );
+ }
+}
+
+function App() {
+ return (
+ <Provider store={store}>
+ <HashRouter>
+ <Route
+ path="/:start?"
+ render={({ match }) => <Test start={match.params.start || 0} />}
+ />
+ </HashRouter>
+ </Provider>
+ );
+}
+
+export default App;
diff --git a/preact/demo/reorder.js b/preact/demo/reorder.js
new file mode 100644
index 0000000..35acc5e
--- /dev/null
+++ b/preact/demo/reorder.js
@@ -0,0 +1,104 @@
+import { createElement, Component } from 'preact';
+
+function createItems(count = 10) {
+ let items = [];
+ for (let i = 0; i < count; i++) {
+ items.push({
+ label: `Item #${i + 1}`,
+ key: i + 1
+ });
+ }
+ return items;
+}
+
+function random() {
+ return Math.random() < 0.5 ? 1 : -1;
+}
+
+export default class Reorder extends Component {
+ state = {
+ items: createItems(),
+ count: 1,
+ useKeys: false
+ };
+
+ shuffle = () => {
+ this.setState({ items: this.state.items.slice().sort(random) });
+ };
+
+ swapTwo = () => {
+ let items = this.state.items.slice(),
+ first = Math.floor(Math.random() * items.length),
+ second;
+ do {
+ second = Math.floor(Math.random() * items.length);
+ } while (second === first);
+ let other = items[first];
+ items[first] = items[second];
+ items[second] = other;
+ this.setState({ items });
+ };
+
+ reverse = () => {
+ this.setState({ items: this.state.items.slice().reverse() });
+ };
+
+ setCount = e => {
+ this.setState({ count: Math.round(e.target.value) });
+ };
+
+ rotate = () => {
+ let { items, count } = this.state;
+ items = items.slice(count).concat(items.slice(0, count));
+ this.setState({ items });
+ };
+
+ rotateBackward = () => {
+ let { items, count } = this.state,
+ len = items.length;
+ items = items.slice(len - count, len).concat(items.slice(0, len - count));
+ this.setState({ items });
+ };
+
+ toggleKeys = () => {
+ this.setState({ useKeys: !this.state.useKeys });
+ };
+
+ renderItem = item => (
+ <li key={this.state.useKeys ? item.key : null}>{item.label}</li>
+ );
+
+ render({}, { items, count, useKeys }) {
+ return (
+ <div class="reorder-demo">
+ <header>
+ <button onClick={this.shuffle}>Shuffle</button>
+ <button onClick={this.swapTwo}>Swap Two</button>
+ <button onClick={this.reverse}>Reverse</button>
+ <button onClick={this.rotate}>Rotate</button>
+ <button onClick={this.rotateBackward}>Rotate Backward</button>
+ <label>
+ <input
+ type="checkbox"
+ onClick={this.toggleKeys}
+ checked={useKeys}
+ />{' '}
+ use keys?
+ </label>
+ <label>
+ <input
+ type="number"
+ step="1"
+ min="1"
+ style={{ width: '3em' }}
+ onInput={this.setCount}
+ value={count}
+ />{' '}
+ count
+ </label>
+ </header>
+ <ul>{items.map(this.renderItem)}</ul>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/spiral.js b/preact/demo/spiral.js
new file mode 100644
index 0000000..baaa052
--- /dev/null
+++ b/preact/demo/spiral.js
@@ -0,0 +1,140 @@
+import { createElement, Component } from 'preact';
+
+const COUNT = 500;
+const LOOPS = 6;
+
+// Component.debounce = requestAnimationFrame;
+
+export default class Spiral extends Component {
+ state = { x: 0, y: 0, big: false, counter: 0 };
+
+ handleClick = e => {
+ console.log('click');
+ };
+
+ increment = () => {
+ if (this.stop) return;
+ // this.setState({ counter: this.state.counter + 1 }, this.increment);
+ this.setState({ counter: this.state.counter + 1 });
+ // this.forceUpdate();
+ requestAnimationFrame(this.increment);
+ };
+
+ setMouse({ pageX: x, pageY: y }) {
+ this.setState({ x, y });
+ return false;
+ }
+
+ setBig(big) {
+ this.setState({ big });
+ }
+
+ componentDidMount() {
+ console.log('mount');
+
+ // let touch = navigator.maxTouchPoints > 1;
+ let touch = false;
+
+ // set mouse position state on move:
+ addEventListener(touch ? 'touchmove' : 'mousemove', e => {
+ this.setMouse(e.touches ? e.touches[0] : e);
+ });
+
+ // holding the mouse down enables big mode:
+ addEventListener(touch ? 'touchstart' : 'mousedown', e => {
+ this.setBig(true);
+ e.preventDefault();
+ });
+ addEventListener(touch ? 'touchend' : 'mouseup', e => this.setBig(false));
+
+ requestAnimationFrame(this.increment);
+ }
+
+ componentWillUnmount() {
+ console.log('unmount');
+ this.stop = true;
+ }
+
+ // componentDidUpdate() {
+ // // invoking setState() in componentDidUpdate() creates an animation loop:
+ // this.increment();
+ // }
+
+ // builds and returns a brand new DOM (every time)
+ render(props, { x, y, big, counter }) {
+ let max =
+ COUNT +
+ Math.round(Math.sin((counter / 90) * 2 * Math.PI) * COUNT * 0.5),
+ cursors = [];
+
+ // the advantage of JSX is that you can use the entirety of JS to "template":
+ for (let i = max; i--; ) {
+ let f = (i / max) * LOOPS,
+ θ = f * 2 * Math.PI,
+ m = 20 + i * 2,
+ hue = (f * 255 + counter * 10) % 255;
+ cursors[i] = (
+ <Cursor
+ big={big}
+ color={'hsl(' + hue + ',100%,50%)'}
+ x={(x + Math.sin(θ) * m) | 0}
+ y={(y + Math.cos(θ) * m) | 0}
+ />
+ );
+ }
+
+ return (
+ <div id="main" onClick={this.handleClick}>
+ <Cursor label x={x} y={y} big={big} />
+ {cursors}
+ </div>
+ );
+ }
+}
+
+/** Represents a single coloured dot. */
+class Cursor extends Component {
+ // get shared/pooled class object
+ getClass(big, label) {
+ let cl = 'cursor';
+ if (big) cl += ' big';
+ if (label) cl += ' label';
+ return cl;
+ }
+
+ // skip any pointless re-renders
+ shouldComponentUpdate(props) {
+ for (let i in props)
+ if (i !== 'children' && props[i] !== this.props[i]) return true;
+ return false;
+ }
+
+ // first argument is "props", the attributes passed to <Cursor ...>
+ render({ x, y, label, color, big }) {
+ let inner = null;
+ if (label)
+ inner = (
+ <span class="label">
+ {x},{y}
+ </span>
+ );
+ return (
+ <div
+ class={this.getClass(big, label)}
+ style={{
+ transform: `translate(${x || 0}px, ${y || 0}px) scale(${
+ big ? 2 : 1
+ })`,
+ // transform: `translate3d(${x || 0}px, ${y || 0}px, 0) scale(${big?2:1})`,
+ borderColor: color
+ }}
+ // style={{ left: x || 0, top: y || 0, borderColor: color }}
+ >
+ {inner}
+ </div>
+ );
+ }
+}
+
+// Addendum: disable dragging on mobile
+addEventListener('touchstart', e => (e.preventDefault(), false));
diff --git a/preact/demo/stateOrderBug.js b/preact/demo/stateOrderBug.js
new file mode 100644
index 0000000..b9f333d
--- /dev/null
+++ b/preact/demo/stateOrderBug.js
@@ -0,0 +1,80 @@
+import htm from 'htm';
+import { h } from 'preact';
+import { useState, useCallback } from 'preact/hooks';
+
+const html = htm.bind(h);
+
+// configuration used to show behavior vs. workaround
+let childFirst = true;
+const Config = () => html`
+ <label>
+ <input
+ type="checkbox"
+ checked=${childFirst}
+ onchange=${evt => {
+ childFirst = evt.target.checked;
+ }}
+ />
+ Set child state before parent state.
+ </label>
+`;
+
+const Child = ({ items, setItems }) => {
+ let [pendingId, setPendingId] = useState(null);
+ if (!pendingId) {
+ setPendingId(
+ (pendingId = Math.random()
+ .toFixed(20)
+ .slice(2))
+ );
+ }
+
+ const onInput = useCallback(
+ evt => {
+ let val = evt.target.value,
+ _items = [...items, { _id: pendingId, val }];
+ if (childFirst) {
+ setPendingId(null);
+ setItems(_items);
+ } else {
+ setItems(_items);
+ setPendingId(null);
+ }
+ },
+ [childFirst, setPendingId, setItems, items, pendingId]
+ );
+
+ return html`
+ <div class="item-editor">
+ ${items.map(
+ (item, idx) => html`
+ <input
+ key=${item._id}
+ value=${item.val}
+ oninput=${evt => {
+ let val = evt.target.value,
+ _items = [...items];
+ _items.splice(idx, 1, { ...item, val });
+ setItems(_items);
+ }}
+ />
+ `
+ )}
+
+ <input
+ key=${pendingId}
+ placeholder="type to add an item"
+ oninput=${onInput}
+ />
+ </div>
+ `;
+};
+
+const Parent = () => {
+ let [items, setItems] = useState([]);
+ return html`
+ <div><${Config} /><${Child} items=${items} setItems=${setItems} /></div>
+ `;
+};
+
+export default Parent;
diff --git a/preact/demo/style.css b/preact/demo/style.css
new file mode 100644
index 0000000..52f0b34
--- /dev/null
+++ b/preact/demo/style.css
@@ -0,0 +1,24 @@
+html, body {
+ font: 14px system-ui, sans-serif;
+}
+.list {
+ list-style: none;
+ padding: 0;
+}
+.list > li {
+ position: relative;
+ padding: 5px 10px;
+ animation: fadeIn 1s ease;
+}
+@keyframes fadeIn {
+ 0% {
+ box-shadow: inset 0 0 2px 2px red,
+ 0 0 2px 2px red;
+ }
+}
+.list > .odd {
+ background-color: #def;
+}
+.list > .even {
+ background-color: #fed;
+}
diff --git a/preact/demo/style.scss b/preact/demo/style.scss
new file mode 100644
index 0000000..8466bbd
--- /dev/null
+++ b/preact/demo/style.scss
@@ -0,0 +1,149 @@
+html, body {
+ height: 100%;
+ margin: 0;
+ background: #eee;
+ font: 400 16px/1.3 'Helvetica Neue',helvetica,sans-serif;
+ text-rendering: optimizeSpeed;
+ color: #444;
+}
+
+.app {
+ display: block;
+ flex-direction: column;
+ height: 100%;
+
+ > header {
+ flex: 0;
+ background: #f9f9f9;
+ box-shadow: inset 0 -.5px 0 0 rgba(0,0,0,0.2), 0 .5px 0 0 rgba(255,255,255,0.6);
+
+ nav {
+ display: inline-block;
+ padding: 4px 7px;
+
+ a {
+ display: inline-block;
+ margin: 2px;
+ padding: 4px 10px;
+ background-color: rgba(255,255,255,0);
+ border-radius: 1em;
+ color: #6b1d8f;
+ text-decoration: none;
+ // transition: all 250ms ease;
+ transition: all 250ms cubic-bezier(.2,0,.4,2);
+ &:hover {
+ background-color: rgba(255,255,255,1);
+ box-shadow: 0 0 0 2px #6b1d8f;
+ }
+ &.active {
+ background-color: #6b1d8f;
+ color: white;
+ }
+ }
+ }
+ }
+
+ > main {
+ flex: 1;
+ padding: 10px;
+ }
+}
+
+
+h1 {
+ margin: 0;
+ color: #6b1d8f;
+ font-weight: 300;
+ font-size: 250%;
+}
+
+
+input, textarea {
+ box-sizing: border-box;
+ margin: 1px;
+ padding: .25em .5em;
+ background: #fff;
+ border: 1px solid #999;
+ border-radius: 3px;
+ font: inherit;
+ color: #000;
+ outline: none;
+
+ &:focus {
+ border-color: #6b1d8f;
+ }
+}
+
+
+button, input[type="submit"], input[type="reset"], input[type="button"] {
+ box-sizing: border-box;
+ margin: 1px;
+ padding: .25em .8em;
+ background: #6b1d8f;
+ border: 1px solid #6b1d8f;
+ // border: none;
+ border-radius: 1.5em;
+ font: inherit;
+ color: white;
+ outline: none;
+ cursor: pointer;
+}
+
+
+.cursor {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 8px;
+ height: 8px;
+ margin: -5px 0 0 -5px;
+ border: 2px solid #F00;
+ border-radius: 50%;
+ transform-origin: 50% 50%;
+ pointer-events: none;
+ overflow: hidden;
+ font-size: 9px;
+ line-height: 25px;
+ text-indent: 15px;
+ white-space: nowrap;
+
+ &:not(.label) {
+ contain: strict;
+ }
+
+ &.label {
+ overflow: visible;
+ }
+
+ // &.big {
+ // transform: scale(2);
+ // // width: 24px;
+ // // height: 24px;
+ // // margin: -13px 0 0 -13px;
+ // }
+
+ .label {
+ position: absolute;
+ left: 0;
+ top: 0;
+ //transform: translateZ(0);
+ // z-index: 10;
+ }
+}
+
+
+.animation-picker {
+ position: fixed;
+ display: inline-block;
+ right: 0;
+ top: 0;
+ padding: 10px;
+ background: #000;
+ color: #BBB;
+ z-index: 1000;
+
+ select {
+ font-size: 100%;
+ margin-left: 5px;
+ }
+}
diff --git a/preact/demo/styled-components.js b/preact/demo/styled-components.js
new file mode 100644
index 0000000..f8433ba
--- /dev/null
+++ b/preact/demo/styled-components.js
@@ -0,0 +1,31 @@
+import { createElement } from 'preact';
+import styled, { css } from 'styled-components';
+
+const Button = styled.button`
+ background: transparent;
+ border-radius: 3px;
+ border: 2px solid palevioletred;
+ color: palevioletred;
+ margin: 0.5em 1em;
+ padding: 0.25em 1em;
+
+ ${props =>
+ props.primary &&
+ css`
+ background: palevioletred;
+ color: white;
+ `}
+`;
+
+const Container = styled.div`
+ text-align: center;
+`;
+
+export default function StyledComp() {
+ return (
+ <Container>
+ <Button>Normal Button</Button>
+ <Button primary>Primary Button</Button>
+ </Container>
+ );
+}
diff --git a/preact/demo/suspense-router/bye.js b/preact/demo/suspense-router/bye.js
new file mode 100644
index 0000000..fe2a49c
--- /dev/null
+++ b/preact/demo/suspense-router/bye.js
@@ -0,0 +1,12 @@
+import { createElement } from 'react';
+import { Link } from './simple-router';
+
+/** @jsx createElement */
+
+export default function Bye() {
+ return (
+ <div>
+ Bye! <Link to="/">Go to Hello!</Link>
+ </div>
+ );
+}
diff --git a/preact/demo/suspense-router/hello.js b/preact/demo/suspense-router/hello.js
new file mode 100644
index 0000000..2566dd3
--- /dev/null
+++ b/preact/demo/suspense-router/hello.js
@@ -0,0 +1,12 @@
+import { createElement } from 'react';
+import { Link } from './simple-router';
+
+/** @jsx createElement */
+
+export default function Hello() {
+ return (
+ <div>
+ Hello! <Link to="/bye">Go to Bye!</Link>
+ </div>
+ );
+}
diff --git a/preact/demo/suspense-router/index.js b/preact/demo/suspense-router/index.js
new file mode 100644
index 0000000..2572209
--- /dev/null
+++ b/preact/demo/suspense-router/index.js
@@ -0,0 +1,30 @@
+import { createElement, Suspense, lazy } from 'react';
+
+import { Router, Route, Switch } from './simple-router';
+
+/** @jsx createElement */
+
+let Hello = lazy(() => import('./hello.js'));
+let Bye = lazy(() => import('./bye.js'));
+
+function Loading() {
+ return <div>Hey! This is a fallback because we're loading things! :D</div>;
+}
+
+export default function SuspenseRouterBug() {
+ return (
+ <Router>
+ <h1>Suspense Router bug</h1>
+ <Suspense fallback={<Loading />}>
+ <Switch>
+ <Route path="/" exact>
+ <Hello />
+ </Route>
+ <Route path="/bye">
+ <Bye />
+ </Route>
+ </Switch>
+ </Suspense>
+ </Router>
+ );
+}
diff --git a/preact/demo/suspense-router/simple-router.js b/preact/demo/suspense-router/simple-router.js
new file mode 100644
index 0000000..ed48ea6
--- /dev/null
+++ b/preact/demo/suspense-router/simple-router.js
@@ -0,0 +1,87 @@
+import {
+ createElement,
+ cloneElement,
+ createContext,
+ useState,
+ useContext,
+ Children,
+ useLayoutEffect
+} from 'react';
+
+/** @jsx createElement */
+
+const memoryHistory = {
+ /**
+ * @typedef {{ pathname: string }} Location
+ * @typedef {(location: Location) => void} HistoryListener
+ * @type {HistoryListener[]}
+ */
+ listeners: [],
+
+ /**
+ * @param {HistoryListener} listener
+ */
+ listen(listener) {
+ const newLength = this.listeners.push(listener);
+ return () => this.listeners.splice(newLength - 1, 1);
+ },
+
+ /**
+ * @param {Location} to
+ */
+ navigate(to) {
+ this.listeners.forEach(listener => listener(to));
+ }
+};
+
+/** @type {import('react').Context<{ history: typeof memoryHistory; location: Location }>} */
+const RouterContext = createContext(null);
+
+export function Router({ history = memoryHistory, children }) {
+ const [location, setLocation] = useState({ pathname: '/' });
+
+ useLayoutEffect(() => {
+ return history.listen(newLocation => setLocation(newLocation));
+ }, []);
+
+ return (
+ <RouterContext.Provider value={{ history, location }}>
+ {children}
+ </RouterContext.Provider>
+ );
+}
+
+export function Switch(props) {
+ const { location } = useContext(RouterContext);
+
+ let element = null;
+ Children.forEach(props.children, child => {
+ if (element == null && child.props.path == location.pathname) {
+ element = child;
+ }
+ });
+
+ return element;
+}
+
+/**
+ * @param {{ children: any; path: string; exact?: boolean; }} props
+ */
+export function Route({ children, path, exact }) {
+ return children;
+}
+
+export function Link({ to, children }) {
+ const { history } = useContext(RouterContext);
+ const onClick = event => {
+ event.preventDefault();
+ event.stopPropagation();
+ history.navigate({ pathname: to });
+ };
+
+ return (
+ <a href={to} onClick={onClick}>
+ {children}
+ </a>
+ );
+}
diff --git a/preact/demo/suspense.js b/preact/demo/suspense.js
new file mode 100644
index 0000000..9b620fa
--- /dev/null
+++ b/preact/demo/suspense.js
@@ -0,0 +1,97 @@
+// eslint-disable-next-line no-unused-vars
+import {
+ createElement,
+ Component,
+ memo,
+ Fragment,
+ Suspense,
+ lazy
+} from 'react';
+
+function LazyComp() {
+ return <div>I'm (fake) lazy loaded</div>;
+}
+
+const Lazy = lazy(() => Promise.resolve({ default: LazyComp }));
+
+function createSuspension(name, timeout, error) {
+ let done = false;
+ let prom;
+
+ return {
+ name,
+ timeout,
+ start: () => {
+ if (!prom) {
+ prom = new Promise((res, rej) => {
+ setTimeout(() => {
+ done = true;
+ if (error) {
+ rej(error);
+ } else {
+ res();
+ }
+ }, timeout);
+ });
+ }
+
+ return prom;
+ },
+ getPromise: () => prom,
+ isDone: () => done
+ };
+}
+
+function CustomSuspense({ isDone, start, timeout, name }) {
+ if (!isDone()) {
+ throw start();
+ }
+
+ return (
+ <div>
+ Hello from CustomSuspense {name}, loaded after {timeout / 1000}s
+ </div>
+ );
+}
+
+function init() {
+ return {
+ s1: createSuspension('1', 1000, null),
+ s2: createSuspension('2', 2000, null),
+ s3: createSuspension('3', 3000, null)
+ };
+}
+
+export default class DevtoolsDemo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = init();
+ this.onRerun = this.onRerun.bind(this);
+ }
+
+ onRerun() {
+ this.setState(init());
+ }
+
+ render(props, state) {
+ return (
+ <div>
+ <h1>lazy()</h1>
+ <Suspense fallback={<div>Loading (fake) lazy loaded component...</div>}>
+ <Lazy />
+ </Suspense>
+ <h1>Suspense</h1>
+ <div>
+ <button onClick={this.onRerun}>Rerun</button>
+ </div>
+ <Suspense fallback={<div>Fallback 1</div>}>
+ <CustomSuspense {...state.s1} />
+ <Suspense fallback={<div>Fallback 2</div>}>
+ <CustomSuspense {...state.s2} />
+ <CustomSuspense {...state.s3} />
+ </Suspense>
+ </Suspense>
+ </div>
+ );
+ }
+}
diff --git a/preact/demo/textFields.js b/preact/demo/textFields.js
new file mode 100644
index 0000000..58f69f1
--- /dev/null
+++ b/preact/demo/textFields.js
@@ -0,0 +1,37 @@
+import React, { useState } from 'react';
+import TextField from '@material-ui/core/TextField';
+
+/** @jsx React.createElement */
+
+const PatchedTextField = props => {
+ const [value, set] = useState(props.value);
+ return (
+ <TextField {...props} value={value} onChange={e => set(e.target.value)} />
+ );
+};
+
+const TextFields = () => (
+ <div>
+ <TextField
+ variant="outlined"
+ margin="normal"
+ fullWidth
+ label="Cannot type in"
+ />
+ <PatchedTextField
+ variant="outlined"
+ margin="normal"
+ fullWidth
+ label="I can"
+ />
+ <TextField
+ defaultValue="Reset after blur or empty"
+ variant="outlined"
+ margin="normal"
+ fullWidth
+ label="default value"
+ />
+ </div>
+);
+
+export default TextFields;
diff --git a/preact/demo/todo.js b/preact/demo/todo.js
new file mode 100644
index 0000000..189b4e8
--- /dev/null
+++ b/preact/demo/todo.js
@@ -0,0 +1,47 @@
+import { createElement, Component } from 'preact';
+
+let counter = 0;
+
+export default class TodoList extends Component {
+ state = { todos: [], text: '' };
+
+ setText = e => {
+ this.setState({ text: e.target.value });
+ };
+
+ addTodo = () => {
+ let { todos, text } = this.state;
+ todos = todos.concat({ text, id: ++counter });
+ this.setState({ todos, text: '' });
+ };
+
+ removeTodo = e => {
+ let id = e.target.getAttribute('data-id');
+ this.setState({ todos: this.state.todos.filter(t => t.id != id) });
+ };
+
+ render({}, { todos, text }) {
+ return (
+ <form onSubmit={this.addTodo} action="javascript:">
+ <input value={text} onInput={this.setText} />
+ <button type="submit">Add</button>
+ <ul>
+ <TodoItems todos={todos} removeTodo={this.removeTodo} />
+ </ul>
+ </form>
+ );
+ }
+}
+
+class TodoItems extends Component {
+ render({ todos, removeTodo }) {
+ return todos.map(todo => (
+ <li key={todo.id}>
+ <button type="button" onClick={removeTodo} data-id={todo.id}>
+ &times;
+ </button>{' '}
+ {todo.text}
+ </li>
+ ));
+ }
+}
diff --git a/preact/demo/tsconfig.json b/preact/demo/tsconfig.json
new file mode 100644
index 0000000..b252efc
--- /dev/null
+++ b/preact/demo/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "experimentalDecorators": true,
+ "jsx": "react",
+ "jsxFactory": "h",
+ "baseUrl": ".",
+ "target": "es2018",
+ "module": "es2015",
+ "moduleResolution": "node",
+ "paths": {
+ "preact/hooks": ["../hooks/src/index.js"],
+ "preact": ["../src/index.js"],
+ }
+ }
+}
diff --git a/preact/demo/webpack.config.js b/preact/demo/webpack.config.js
new file mode 100644
index 0000000..063f507
--- /dev/null
+++ b/preact/demo/webpack.config.js
@@ -0,0 +1,112 @@
+/* eslint-disable */
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+const preact = path.join(__dirname, '..', 'src');
+const compat = path.join(__dirname, '..', 'compat', 'src');
+
+module.exports = {
+ context: __dirname,
+ entry: './index',
+ output: {
+ publicPath: '/'
+ },
+ resolve: {
+ alias: {
+ ['preact/debug']: path.join(__dirname, '..', 'debug'),
+ ['preact/devtools']: path.join(__dirname, '..', 'devtools'),
+ ['preact/hooks']: path.join(__dirname, '..', 'hooks', 'src'),
+ preact: preact,
+ react: compat,
+ 'react-dom': compat
+ },
+ extensions: ['.tsx', '.ts', '.js']
+ },
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ loader: 'babel-loader',
+ options: {
+ sourceMap: true,
+ presets: [
+ [require.resolve('@babel/preset-typescript'), { jsxPragma: 'h' }],
+ [
+ require.resolve('@babel/preset-env'),
+ {
+ targets: {
+ browsers: ['last 2 versions', 'IE >= 9']
+ },
+ modules: false,
+ loose: true
+ }
+ ],
+ [require.resolve('@babel/preset-react')]
+ ],
+ plugins: [
+ [require.resolve('@babel/plugin-transform-runtime')],
+ [require.resolve('@babel/plugin-transform-react-jsx-source')],
+ [
+ require.resolve('@babel/plugin-transform-react-jsx'),
+ { pragma: 'h', pragmaFrag: 'Fragment' }
+ ],
+ [
+ require.resolve('@babel/plugin-proposal-decorators'),
+ { legacy: true }
+ ],
+ [
+ require.resolve('@babel/plugin-proposal-class-properties'),
+ { loose: true }
+ ]
+ ]
+ }
+ },
+ {
+ test: /\.js$/,
+ loader: 'babel-loader',
+ options: {
+ sourceMap: true,
+ presets: [
+ [
+ require.resolve('@babel/preset-env'),
+ {
+ targets: {
+ browsers: ['last 2 versions', 'IE >= 9']
+ },
+ modules: false,
+ loose: true
+ }
+ ],
+ [require.resolve('@babel/preset-react')]
+ ],
+ plugins: [
+ [require.resolve('@babel/plugin-transform-react-jsx-source')],
+ [
+ require.resolve('@babel/plugin-transform-react-jsx'),
+ { pragma: 'createElement', pragmaFrag: 'Fragment' }
+ ],
+ [require.resolve('@babel/plugin-proposal-class-properties')],
+ [
+ require.resolve('@babel/plugin-transform-react-constant-elements')
+ ],
+ [require.resolve('@babel/plugin-syntax-dynamic-import')]
+ ]
+ }
+ },
+ {
+ test: /\.s?css$/,
+ use: ['style-loader', 'css-loader', 'sass-loader']
+ }
+ ]
+ },
+ devtool: 'inline-source-map',
+ node: {
+ process: 'mock',
+ Buffer: false,
+ setImmediate: false
+ },
+ devServer: {
+ historyApiFallback: true
+ },
+ plugins: [new HtmlWebpackPlugin()]
+};
diff --git a/preact/devtools/LICENSE b/preact/devtools/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/devtools/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/devtools/mangle.json b/preact/devtools/mangle.json
new file mode 100644
index 0000000..506a6a4
--- /dev/null
+++ b/preact/devtools/mangle.json
@@ -0,0 +1,21 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/preact/devtools/package.json b/preact/devtools/package.json
new file mode 100644
index 0000000..92beb75
--- /dev/null
+++ b/preact/devtools/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "preact-devtools",
+ "amdName": "preactDevtools",
+ "version": "1.0.0",
+ "private": true,
+ "description": "Preact bridge for Preact devtools",
+ "main": "dist/devtools.js",
+ "module": "dist/devtools.module.js",
+ "umd:main": "dist/devtools.umd.js",
+ "source": "src/index.js",
+ "license": "MIT",
+ "types": "src/index.d.ts",
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ }
+}
diff --git a/preact/devtools/src/devtools.js b/preact/devtools/src/devtools.js
new file mode 100644
index 0000000..2bd462d
--- /dev/null
+++ b/preact/devtools/src/devtools.js
@@ -0,0 +1,10 @@
+import { options, Fragment, Component } from 'preact';
+
+export function initDevTools() {
+ if (typeof window != 'undefined' && window.__PREACT_DEVTOOLS__) {
+ window.__PREACT_DEVTOOLS__.attachPreact('10.5.14', options, {
+ Fragment,
+ Component
+ });
+ }
+}
diff --git a/preact/devtools/src/index.d.ts b/preact/devtools/src/index.d.ts
new file mode 100644
index 0000000..230e5ab
--- /dev/null
+++ b/preact/devtools/src/index.d.ts
@@ -0,0 +1,8 @@
+/**
+ * Customize the displayed name of a useState, useReducer or useRef hook
+ * in the devtools panel.
+ *
+ * @param value Wrapped native hook.
+ * @param name Custom name
+ */
+export function addHookName<T>(value: T, name: string): T;
diff --git a/preact/devtools/src/index.js b/preact/devtools/src/index.js
new file mode 100644
index 0000000..693429f
--- /dev/null
+++ b/preact/devtools/src/index.js
@@ -0,0 +1,15 @@
+import { options } from 'preact';
+import { initDevTools } from './devtools';
+
+initDevTools();
+
+/**
+ * Display a custom label for a custom hook for the devtools panel
+ * @type {<T>(value: T, name: string) => T}
+ */
+export function addHookName(value, name) {
+ if (options._addHookName) {
+ options._addHookName(name);
+ }
+ return value;
+}
diff --git a/preact/devtools/test/browser/addHookName.test.js b/preact/devtools/test/browser/addHookName.test.js
new file mode 100644
index 0000000..28b06b0
--- /dev/null
+++ b/preact/devtools/test/browser/addHookName.test.js
@@ -0,0 +1,51 @@
+import { createElement, render, options } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useState } from 'preact/hooks';
+import { addHookName } from 'preact/devtools';
+
+/** @jsx createElement */
+
+describe('addHookName', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ delete options._addHookName;
+ });
+
+ it('should do nothing when no options hook is present', () => {
+ function useFoo() {
+ return addHookName(useState(0), 'foo');
+ }
+
+ function App() {
+ let [v] = useFoo();
+ return <div>{v}</div>;
+ }
+
+ expect(() => render(<App />, scratch)).to.not.throw();
+ });
+
+ it('should call options hook with value', () => {
+ let spy = (options._addHookName = sinon.spy());
+
+ function useFoo() {
+ return addHookName(useState(0), 'foo');
+ }
+
+ function App() {
+ let [v] = useFoo();
+ return <div>{v}</div>;
+ }
+
+ render(<App />, scratch);
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith('foo');
+ });
+});
diff --git a/preact/hooks/LICENSE b/preact/hooks/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/hooks/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/hooks/mangle.json b/preact/hooks/mangle.json
new file mode 100644
index 0000000..506a6a4
--- /dev/null
+++ b/preact/hooks/mangle.json
@@ -0,0 +1,21 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/preact/hooks/package.json b/preact/hooks/package.json
new file mode 100644
index 0000000..1e8d66a
--- /dev/null
+++ b/preact/hooks/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "preact-hooks",
+ "amdName": "preactHooks",
+ "version": "0.1.0",
+ "private": true,
+ "description": "Hook addon for Preact",
+ "main": "dist/hooks.js",
+ "module": "dist/hooks.module.js",
+ "umd:main": "dist/hooks.umd.js",
+ "source": "src/index.js",
+ "license": "MIT",
+ "types": "src/index.d.ts",
+ "scripts": {
+ "build": "microbundle build --raw",
+ "dev": "microbundle watch --raw --format cjs",
+ "test": "npm-run-all build --parallel test:karma",
+ "test:karma": "karma start test/karma.conf.js --single-run",
+ "test:karma:watch": "karma start test/karma.conf.js --no-single-run"
+ },
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ },
+ "mangle": {
+ "regex": "^_"
+ }
+}
diff --git a/preact/hooks/src/index.d.ts b/preact/hooks/src/index.d.ts
new file mode 100644
index 0000000..c9f6788
--- /dev/null
+++ b/preact/hooks/src/index.d.ts
@@ -0,0 +1,133 @@
+import { PreactContext, Ref as PreactRef, RefObject } from '../..';
+
+type Inputs = ReadonlyArray<unknown>;
+
+export type StateUpdater<S> = (value: S | ((prevState: S) => S)) => void;
+/**
+ * Returns a stateful value, and a function to update it.
+ * @param initialState The initial value (or a function that returns the initial value)
+ */
+export function useState<S>(initialState: S | (() => S)): [S, StateUpdater<S>];
+
+export function useState<S = undefined>(): [
+ S | undefined,
+ StateUpdater<S | undefined>
+];
+
+export type Reducer<S, A> = (prevState: S, action: A) => S;
+/**
+ * An alternative to `useState`.
+ *
+ * `useReducer` is usually preferable to `useState` when you have complex state logic that involves
+ * multiple sub-values. It also lets you optimize performance for components that trigger deep
+ * updates because you can pass `dispatch` down instead of callbacks.
+ * @param reducer Given the current state and an action, returns the new state
+ * @param initialState The initial value to store as state
+ */
+export function useReducer<S, A>(
+ reducer: Reducer<S, A>,
+ initialState: S
+): [S, (action: A) => void];
+
+/**
+ * An alternative to `useState`.
+ *
+ * `useReducer` is usually preferable to `useState` when you have complex state logic that involves
+ * multiple sub-values. It also lets you optimize performance for components that trigger deep
+ * updates because you can pass `dispatch` down instead of callbacks.
+ * @param reducer Given the current state and an action, returns the new state
+ * @param initialArg The initial argument to pass to the `init` function
+ * @param init A function that, given the `initialArg`, returns the initial value to store as state
+ */
+export function useReducer<S, A, I>(
+ reducer: Reducer<S, A>,
+ initialArg: I,
+ init: (arg: I) => S
+): [S, (action: A) => void];
+
+/** @deprecated Use the `Ref` type instead. */
+type PropRef<T> = { current: T };
+type Ref<T> = { current: T };
+
+/**
+ * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
+ * (`initialValue`). The returned object will persist for the full lifetime of the component.
+ *
+ * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
+ * value around similar to how you’d use instance fields in classes.
+ *
+ * @param initialValue the initial value to store in the ref object
+ */
+export function useRef<T>(initialValue: null): RefObject<T>;
+export function useRef<T>(initialValue: T): Ref<T>;
+export function useRef<T>(): Ref<T | undefined>;
+
+type EffectCallback = () => void | (() => void);
+/**
+ * Accepts a function that contains imperative, possibly effectful code.
+ * The effects run after browser paint, without blocking it.
+ *
+ * @param effect Imperative function that can return a cleanup function
+ * @param inputs If present, effect will only activate if the values in the list change (using ===).
+ */
+export function useEffect(effect: EffectCallback, inputs?: Inputs): void;
+
+type CreateHandle = () => object;
+
+/**
+ * @param ref The ref that will be mutated
+ * @param create The function that will be executed to get the value that will be attached to
+ * ref.current
+ * @param inputs If present, effect will only activate if the values in the list change (using ===).
+ */
+export function useImperativeHandle<T, R extends T>(
+ ref: PreactRef<T>,
+ create: () => R,
+ inputs?: Inputs
+): void;
+
+/**
+ * Accepts a function that contains imperative, possibly effectful code.
+ * Use this to read layout from the DOM and synchronously re-render.
+ * Updates scheduled inside `useLayoutEffect` will be flushed synchronously, after all DOM mutations but before the browser has a chance to paint.
+ * Prefer the standard `useEffect` hook when possible to avoid blocking visual updates.
+ *
+ * @param effect Imperative function that can return a cleanup function
+ * @param inputs If present, effect will only activate if the values in the list change (using ===).
+ */
+export function useLayoutEffect(effect: EffectCallback, inputs?: Inputs): void;
+
+/**
+ * Returns a memoized version of the callback that only changes if one of the `inputs`
+ * has changed (using ===).
+ */
+export function useCallback<T extends Function>(callback: T, inputs: Inputs): T;
+
+/**
+ * Pass a factory function and an array of inputs.
+ * useMemo will only recompute the memoized value when one of the inputs has changed.
+ * This optimization helps to avoid expensive calculations on every render.
+ * If no array is provided, a new value will be computed whenever a new function instance is passed as the first argument.
+ */
+// for `inputs`, allow undefined, but don't make it optional as that is very likely a mistake
+export function useMemo<T>(factory: () => T, inputs: Inputs | undefined): T;
+
+/**
+ * Returns the current context value, as given by the nearest context provider for the given context.
+ * When the provider updates, this Hook will trigger a rerender with the latest context value.
+ *
+ * @param context The context you want to use
+ */
+export function useContext<T>(context: PreactContext<T>): T;
+
+/**
+ * Customize the displayed value in the devtools panel.
+ *
+ * @param value Custom hook name or object that is passed to formatter
+ * @param formatter Formatter to modify value before sending it to the devtools
+ */
+export function useDebugValue<T>(value: T, formatter?: (value: T) => any): void;
+
+export function useErrorBoundary(
+ callback?: (error: any) => Promise<void> | void
+): [any, () => void];
diff --git a/preact/hooks/src/index.js b/preact/hooks/src/index.js
new file mode 100644
index 0000000..e3840a2
--- /dev/null
+++ b/preact/hooks/src/index.js
@@ -0,0 +1,386 @@
+import { options } from 'preact';
+
+/** @type {number} */
+let currentIndex;
+
+/** @type {import('./internal').Component} */
+let currentComponent;
+/**
+ * Keep track of the previous component so that we can set
+ * `currentComponent` to `null` and throw when a hook is invoked
+ * outside of render
+ * @type {import('./internal').Component}
+ */
+let previousComponent;
+
+/** @type {number} */
+let currentHook = 0;
+
+/** @type {Array<import('./internal').Component>} */
+let afterPaintEffects = [];
+
+let oldBeforeDiff = options._diff;
+let oldBeforeRender = options._render;
+let oldAfterDiff = options.diffed;
+let oldCommit = options._commit;
+let oldBeforeUnmount = options.unmount;
+
+const RAF_TIMEOUT = 100;
+let prevRaf;
+
+options._diff = vnode => {
+ currentComponent = null;
+ if (oldBeforeDiff) oldBeforeDiff(vnode);
+};
+
+options._render = vnode => {
+ if (oldBeforeRender) oldBeforeRender(vnode);
+
+ currentComponent = vnode._component;
+ currentIndex = 0;
+
+ const hooks = currentComponent.__hooks;
+ if (hooks) {
+ hooks._pendingEffects.forEach(invokeCleanup);
+ hooks._pendingEffects.forEach(invokeEffect);
+ hooks._pendingEffects = [];
+ }
+};
+
+options.diffed = vnode => {
+ if (oldAfterDiff) oldAfterDiff(vnode);
+
+ const c = vnode._component;
+ if (c && c.__hooks && c.__hooks._pendingEffects.length) {
+ afterPaint(afterPaintEffects.push(c));
+ }
+ currentComponent = previousComponent;
+};
+
+options._commit = (vnode, commitQueue) => {
+ commitQueue.some(component => {
+ try {
+ component._renderCallbacks.forEach(invokeCleanup);
+ component._renderCallbacks = component._renderCallbacks.filter(cb =>
+ cb._value ? invokeEffect(cb) : true
+ );
+ } catch (e) {
+ commitQueue.some(c => {
+ if (c._renderCallbacks) c._renderCallbacks = [];
+ });
+ commitQueue = [];
+ options._catchError(e, component._vnode);
+ }
+ });
+
+ if (oldCommit) oldCommit(vnode, commitQueue);
+};
+
+options.unmount = vnode => {
+ if (oldBeforeUnmount) oldBeforeUnmount(vnode);
+
+ const c = vnode._component;
+ if (c && c.__hooks) {
+ try {
+ c.__hooks._list.forEach(invokeCleanup);
+ } catch (e) {
+ options._catchError(e, c._vnode);
+ }
+ }
+};
+
+/**
+ * Get a hook's state from the currentComponent
+ * @param {number} index The index of the hook to get
+ * @param {number} type The index of the hook to get
+ * @returns {any}
+ */
+function getHookState(index, type) {
+ if (options._hook) {
+ options._hook(currentComponent, index, currentHook || type);
+ }
+ currentHook = 0;
+
+ // Largely inspired by:
+ // * https://github.com/michael-klein/funcy.js/blob/f6be73468e6ec46b0ff5aa3cc4c9baf72a29025a/src/hooks/core_hooks.mjs
+ // * https://github.com/michael-klein/funcy.js/blob/650beaa58c43c33a74820a3c98b3c7079cf2e333/src/renderer.mjs
+ // Other implementations to look at:
+ // * https://codesandbox.io/s/mnox05qp8
+ const hooks =
+ currentComponent.__hooks ||
+ (currentComponent.__hooks = {
+ _list: [],
+ _pendingEffects: []
+ });
+
+ if (index >= hooks._list.length) {
+ hooks._list.push({});
+ }
+ return hooks._list[index];
+}
+
+/**
+ * @param {import('./index').StateUpdater<any>} [initialState]
+ */
+export function useState(initialState) {
+ currentHook = 1;
+ return useReducer(invokeOrReturn, initialState);
+}
+
+/**
+ * @param {import('./index').Reducer<any, any>} reducer
+ * @param {import('./index').StateUpdater<any>} initialState
+ * @param {(initialState: any) => void} [init]
+ * @returns {[ any, (state: any) => void ]}
+ */
+export function useReducer(reducer, initialState, init) {
+ /** @type {import('./internal').ReducerHookState} */
+ const hookState = getHookState(currentIndex++, 2);
+ hookState._reducer = reducer;
+ if (!hookState._component) {
+ hookState._value = [
+ !init ? invokeOrReturn(undefined, initialState) : init(initialState),
+
+ action => {
+ const nextValue = hookState._reducer(hookState._value[0], action);
+ if (hookState._value[0] !== nextValue) {
+ hookState._value = [nextValue, hookState._value[1]];
+ hookState._component.setState({});
+ }
+ }
+ ];
+
+ hookState._component = currentComponent;
+ }
+
+ return hookState._value;
+}
+
+/**
+ * @param {import('./internal').Effect} callback
+ * @param {any[]} args
+ */
+export function useEffect(callback, args) {
+ /** @type {import('./internal').EffectHookState} */
+ const state = getHookState(currentIndex++, 3);
+ if (!options._skipEffects && argsChanged(state._args, args)) {
+ state._value = callback;
+ state._args = args;
+
+ currentComponent.__hooks._pendingEffects.push(state);
+ }
+}
+
+/**
+ * @param {import('./internal').Effect} callback
+ * @param {any[]} args
+ */
+export function useLayoutEffect(callback, args) {
+ /** @type {import('./internal').EffectHookState} */
+ const state = getHookState(currentIndex++, 4);
+ if (!options._skipEffects && argsChanged(state._args, args)) {
+ state._value = callback;
+ state._args = args;
+
+ currentComponent._renderCallbacks.push(state);
+ }
+}
+
+export function useRef(initialValue) {
+ currentHook = 5;
+ return useMemo(() => ({ current: initialValue }), []);
+}
+
+/**
+ * @param {object} ref
+ * @param {() => object} createHandle
+ * @param {any[]} args
+ */
+export function useImperativeHandle(ref, createHandle, args) {
+ currentHook = 6;
+ useLayoutEffect(
+ () => {
+ if (typeof ref == 'function') ref(createHandle());
+ else if (ref) ref.current = createHandle();
+ },
+ args == null ? args : args.concat(ref)
+ );
+}
+
+/**
+ * @param {() => any} factory
+ * @param {any[]} args
+ */
+export function useMemo(factory, args) {
+ /** @type {import('./internal').MemoHookState} */
+ const state = getHookState(currentIndex++, 7);
+ if (argsChanged(state._args, args)) {
+ state._value = factory();
+ state._args = args;
+ state._factory = factory;
+ }
+
+ return state._value;
+}
+
+/**
+ * @param {() => void} callback
+ * @param {any[]} args
+ */
+export function useCallback(callback, args) {
+ currentHook = 8;
+ return useMemo(() => callback, args);
+}
+
+/**
+ * @param {import('./internal').PreactContext} context
+ */
+export function useContext(context) {
+ const provider = currentComponent.context[context._id];
+ // We could skip this call here, but than we'd not call
+ // `options._hook`. We need to do that in order to make
+ // the devtools aware of this hook.
+ /** @type {import('./internal').ContextHookState} */
+ const state = getHookState(currentIndex++, 9);
+ // The devtools needs access to the context object to
+ // be able to pull of the default value when no provider
+ // is present in the tree.
+ state._context = context;
+ if (!provider) return context._defaultValue;
+ // This is probably not safe to convert to "!"
+ if (state._value == null) {
+ state._value = true;
+ provider.sub(currentComponent);
+ }
+ return provider.props.value;
+}
+
+/**
+ * Display a custom label for a custom hook for the devtools panel
+ * @type {<T>(value: T, cb?: (value: T) => string | number) => void}
+ */
+export function useDebugValue(value, formatter) {
+ if (options.useDebugValue) {
+ options.useDebugValue(formatter ? formatter(value) : value);
+ }
+}
+
+/**
+ * @param {(error: any) => void} cb
+ */
+export function useErrorBoundary(cb) {
+ /** @type {import('./internal').ErrorBoundaryHookState} */
+ const state = getHookState(currentIndex++, 10);
+ const errState = useState();
+ state._value = cb;
+ if (!currentComponent.componentDidCatch) {
+ currentComponent.componentDidCatch = err => {
+ if (state._value) state._value(err);
+ errState[1](err);
+ };
+ }
+ return [
+ errState[0],
+ () => {
+ errState[1](undefined);
+ }
+ ];
+}
+
+/**
+ * After paint effects consumer.
+ */
+function flushAfterPaintEffects() {
+ afterPaintEffects.forEach(component => {
+ if (component._parentDom) {
+ try {
+ component.__hooks._pendingEffects.forEach(invokeCleanup);
+ component.__hooks._pendingEffects.forEach(invokeEffect);
+ component.__hooks._pendingEffects = [];
+ } catch (e) {
+ component.__hooks._pendingEffects = [];
+ options._catchError(e, component._vnode);
+ }
+ }
+ });
+ afterPaintEffects = [];
+}
+
+let HAS_RAF = typeof requestAnimationFrame == 'function';
+
+/**
+ * Schedule a callback to be invoked after the browser has a chance to paint a new frame.
+ * Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after
+ * the next browser frame.
+ *
+ * Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked
+ * even if RAF doesn't fire (for example if the browser tab is not visible)
+ *
+ * @param {() => void} callback
+ */
+function afterNextFrame(callback) {
+ const done = () => {
+ clearTimeout(timeout);
+ if (HAS_RAF) cancelAnimationFrame(raf);
+ setTimeout(callback);
+ };
+ const timeout = setTimeout(done, RAF_TIMEOUT);
+
+ let raf;
+ if (HAS_RAF) {
+ raf = requestAnimationFrame(done);
+ }
+}
+
+// Note: if someone used options.debounceRendering = requestAnimationFrame,
+// then effects will ALWAYS run on the NEXT frame instead of the current one, incurring a ~16ms delay.
+// Perhaps this is not such a big deal.
+/**
+ * Schedule afterPaintEffects flush after the browser paints
+ * @param {number} newQueueLength
+ */
+function afterPaint(newQueueLength) {
+ if (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {
+ prevRaf = options.requestAnimationFrame;
+ (prevRaf || afterNextFrame)(flushAfterPaintEffects);
+ }
+}
+
+/**
+ * @param {import('./internal').EffectHookState} hook
+ */
+function invokeCleanup(hook) {
+ // A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
+ // and move the currentComponent away.
+ const comp = currentComponent;
+ if (typeof hook._cleanup == 'function') hook._cleanup();
+ currentComponent = comp;
+}
+
+/**
+ * Invoke a Hook's effect
+ * @param {import('./internal').EffectHookState} hook
+ */
+function invokeEffect(hook) {
+ // A hook call can introduce a call to render which creates a new root, this will call options.vnode
+ // and move the currentComponent away.
+ const comp = currentComponent;
+ hook._cleanup = hook._value();
+ currentComponent = comp;
+}
+
+/**
+ * @param {any[]} oldArgs
+ * @param {any[]} newArgs
+ */
+function argsChanged(oldArgs, newArgs) {
+ return (
+ !oldArgs ||
+ oldArgs.length !== newArgs.length ||
+ newArgs.some((arg, index) => arg !== oldArgs[index])
+ );
+}
+
+function invokeOrReturn(arg, f) {
+ return typeof f == 'function' ? f(arg) : f;
+}
diff --git a/preact/hooks/src/internal.d.ts b/preact/hooks/src/internal.d.ts
new file mode 100644
index 0000000..e6b51fb
--- /dev/null
+++ b/preact/hooks/src/internal.d.ts
@@ -0,0 +1,75 @@
+import {
+ Component as PreactComponent,
+ PreactContext
+} from '../../src/internal';
+import { Reducer } from '.';
+
+export { PreactContext };
+
+/**
+ * The type of arguments passed to a Hook function. While this type is not
+ * strictly necessary, they are given a type name to make it easier to read
+ * the following types and trace the flow of data.
+ */
+export type HookArgs = any;
+
+/**
+ * The return type of a Hook function. While this type is not
+ * strictly necessary, they are given a type name to make it easier to read
+ * the following types and trace the flow of data.
+ */
+export type HookReturnValue = any;
+
+/** The public function a user invokes to use a Hook */
+export type Hook = (...args: HookArgs[]) => HookReturnValue;
+
+// Hook tracking
+
+export interface ComponentHooks {
+ /** The list of hooks a component uses */
+ _list: HookState[];
+ /** List of Effects to be invoked after the next frame is rendered */
+ _pendingEffects: EffectHookState[];
+}
+
+export interface Component extends PreactComponent<any, any> {
+ __hooks?: ComponentHooks;
+}
+
+export type HookState =
+ | EffectHookState
+ | MemoHookState
+ | ReducerHookState
+ | ContextHookState
+ | ErrorBoundaryHookState;
+
+export type Effect = () => void | Cleanup;
+export type Cleanup = () => void;
+
+export interface EffectHookState {
+ _value?: Effect;
+ _args?: any[];
+ _cleanup?: Cleanup | void;
+}
+
+export interface MemoHookState {
+ _value?: any;
+ _args?: any[];
+ _factory?: () => any;
+}
+
+export interface ReducerHookState {
+ _value?: any;
+ _component?: Component;
+ _reducer?: Reducer<any, any>;
+}
+
+export interface ContextHookState {
+ /** Whether this hooks as subscribed to updates yet */
+ _value?: boolean;
+ _context?: PreactContext;
+}
+
+export interface ErrorBoundaryHookState {
+ _value?: (error: any) => void;
+}
diff --git a/preact/hooks/test/_util/useEffectUtil.js b/preact/hooks/test/_util/useEffectUtil.js
new file mode 100644
index 0000000..f04edc2
--- /dev/null
+++ b/preact/hooks/test/_util/useEffectUtil.js
@@ -0,0 +1,10 @@
+export function scheduleEffectAssert(assertFn) {
+ return new Promise(resolve => {
+ requestAnimationFrame(() =>
+ setTimeout(() => {
+ assertFn();
+ resolve();
+ }, 0)
+ );
+ });
+}
diff --git a/preact/hooks/test/browser/combinations.test.js b/preact/hooks/test/browser/combinations.test.js
new file mode 100644
index 0000000..986533c
--- /dev/null
+++ b/preact/hooks/test/browser/combinations.test.js
@@ -0,0 +1,301 @@
+import { setupRerender, act } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import {
+ useState,
+ useReducer,
+ useEffect,
+ useLayoutEffect,
+ useRef
+} from 'preact/hooks';
+import { scheduleEffectAssert } from '../_util/useEffectUtil';
+
+/** @jsx createElement */
+
+describe('combinations', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('can mix useState hooks', () => {
+ const states = {};
+ const setStates = {};
+
+ function Parent() {
+ const [state1, setState1] = useState(1);
+ const [state2, setState2] = useState(2);
+
+ Object.assign(states, { state1, state2 });
+ Object.assign(setStates, { setState1, setState2 });
+
+ return <Child />;
+ }
+
+ function Child() {
+ const [state3, setState3] = useState(3);
+ const [state4, setState4] = useState(4);
+
+ Object.assign(states, { state3, state4 });
+ Object.assign(setStates, { setState3, setState4 });
+
+ return null;
+ }
+
+ render(<Parent />, scratch);
+ expect(states).to.deep.equal({
+ state1: 1,
+ state2: 2,
+ state3: 3,
+ state4: 4
+ });
+
+ setStates.setState2(n => n * 10);
+ setStates.setState3(n => n * 10);
+ rerender();
+ expect(states).to.deep.equal({
+ state1: 1,
+ state2: 20,
+ state3: 30,
+ state4: 4
+ });
+ });
+
+ it('can rerender asynchronously from within an effect', () => {
+ const didRender = sinon.spy();
+
+ function Comp() {
+ const [counter, setCounter] = useState(0);
+
+ useEffect(() => {
+ if (counter === 0) setCounter(1);
+ });
+
+ didRender(counter);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ return scheduleEffectAssert(() => {
+ rerender();
+ expect(didRender).to.have.been.calledTwice.and.calledWith(1);
+ });
+ });
+
+ it('can rerender synchronously from within a layout effect', () => {
+ const didRender = sinon.spy();
+
+ function Comp() {
+ const [counter, setCounter] = useState(0);
+
+ useLayoutEffect(() => {
+ if (counter === 0) setCounter(1);
+ });
+
+ didRender(counter);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ rerender();
+
+ expect(didRender).to.have.been.calledTwice.and.calledWith(1);
+ });
+
+ it('can access refs from within a layout effect callback', () => {
+ let refAtLayoutTime;
+
+ function Comp() {
+ const input = useRef();
+
+ useLayoutEffect(() => {
+ refAtLayoutTime = input.current;
+ });
+
+ return <input ref={input} value="hello" />;
+ }
+
+ render(<Comp />, scratch);
+
+ expect(refAtLayoutTime.value).to.equal('hello');
+ });
+
+ it('can use multiple useState and useReducer hooks', () => {
+ let states = [];
+ let dispatchState4;
+
+ function reducer1(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return state + action.count;
+ }
+ }
+
+ function reducer2(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return state + action.count * 2;
+ }
+ }
+
+ function Comp() {
+ const [state1] = useState(0);
+ const [state2] = useReducer(reducer1, 10);
+ const [state3] = useState(1);
+ const [state4, dispatch] = useReducer(reducer2, 20);
+
+ dispatchState4 = dispatch;
+ states.push(state1, state2, state3, state4);
+
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ expect(states).to.deep.equal([0, 10, 1, 20]);
+
+ states = [];
+
+ dispatchState4({ type: 'increment', count: 10 });
+ rerender();
+
+ expect(states).to.deep.equal([0, 10, 1, 40]);
+ });
+
+ it('ensures useEffect always schedule after the next paint following a redraw effect, when using the default debounce strategy', () => {
+ let effectCount = 0;
+
+ function Comp() {
+ const [counter, setCounter] = useState(0);
+
+ useEffect(() => {
+ if (counter === 0) setCounter(1);
+ effectCount++;
+ });
+
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ return scheduleEffectAssert(() => {
+ expect(effectCount).to.equal(1);
+ });
+ });
+
+ it('should not reuse functional components with hooks', () => {
+ let updater = { first: undefined, second: undefined };
+ function Foo(props) {
+ let [v, setter] = useState(0);
+ updater[props.id] = () => setter(++v);
+ return <div>{v}</div>;
+ }
+
+ let updateParent;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: true };
+ updateParent = () => this.setState(p => ({ active: !p.active }));
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.active && <Foo id="first" />}
+ <Foo id="second" />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ act(() => updater.second());
+ expect(scratch.textContent).to.equal('01');
+
+ updateParent();
+ rerender();
+ expect(scratch.textContent).to.equal('1');
+
+ updateParent();
+ rerender();
+
+ expect(scratch.textContent).to.equal('01');
+ });
+
+ it('should have a right call order with correct dom ref', () => {
+ let i = 0,
+ set;
+ const calls = [];
+
+ function Inner() {
+ useLayoutEffect(() => {
+ calls.push('layout inner call ' + scratch.innerHTML);
+ return () => calls.push('layout inner dispose ' + scratch.innerHTML);
+ });
+ useEffect(() => {
+ calls.push('effect inner call ' + scratch.innerHTML);
+ return () => calls.push('effect inner dispose ' + scratch.innerHTML);
+ });
+ return <span>hello {i}</span>;
+ }
+
+ function Outer() {
+ i++;
+ const [state, setState] = useState(false);
+ set = () => setState(!state);
+ useLayoutEffect(() => {
+ calls.push('layout outer call ' + scratch.innerHTML);
+ return () => calls.push('layout outer dispose ' + scratch.innerHTML);
+ });
+ useEffect(() => {
+ calls.push('effect outer call ' + scratch.innerHTML);
+ return () => calls.push('effect outer dispose ' + scratch.innerHTML);
+ });
+ return <Inner />;
+ }
+
+ act(() => render(<Outer />, scratch));
+ expect(calls).to.deep.equal([
+ 'layout inner call <span>hello 1</span>',
+ 'layout outer call <span>hello 1</span>',
+ 'effect inner call <span>hello 1</span>',
+ 'effect outer call <span>hello 1</span>'
+ ]);
+
+ // NOTE: this order is (at the time of writing) intentionally different from
+ // React. React calls all disposes across all components, and then invokes all
+ // effects across all components. We call disposes and effects in order of components:
+ // for each component, call its disposes and then its effects. If presented with a
+ // compelling use case to support inter-component dispose dependencies, then rewrite this
+ // test to test React's order. In other words, if there is a use case to support calling
+ // all disposes across components then re-order the lines below to demonstrate the desired behavior.
+
+ act(() => set());
+ expect(calls).to.deep.equal([
+ 'layout inner call <span>hello 1</span>',
+ 'layout outer call <span>hello 1</span>',
+ 'effect inner call <span>hello 1</span>',
+ 'effect outer call <span>hello 1</span>',
+ 'layout inner dispose <span>hello 2</span>',
+ 'layout inner call <span>hello 2</span>',
+ 'layout outer dispose <span>hello 2</span>',
+ 'layout outer call <span>hello 2</span>',
+ 'effect inner dispose <span>hello 2</span>',
+ 'effect inner call <span>hello 2</span>',
+ 'effect outer dispose <span>hello 2</span>',
+ 'effect outer call <span>hello 2</span>'
+ ]);
+ });
+});
diff --git a/preact/hooks/test/browser/errorBoundary.test.js b/preact/hooks/test/browser/errorBoundary.test.js
new file mode 100644
index 0000000..4c2f7f3
--- /dev/null
+++ b/preact/hooks/test/browser/errorBoundary.test.js
@@ -0,0 +1,92 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useErrorBoundary } from 'preact/hooks';
+import { setupRerender } from 'preact/test-utils';
+
+/** @jsx createElement */
+
+describe('errorBoundary', () => {
+ /** @type {HTMLDivElement} */
+ let scratch, rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('catches errors', () => {
+ let resetErr,
+ success = false;
+ const Throws = () => {
+ throw new Error('test');
+ };
+
+ const App = props => {
+ const [err, reset] = useErrorBoundary();
+ resetErr = reset;
+ return err ? <p>Error</p> : success ? <p>Success</p> : <Throws />;
+ };
+
+ render(<App />, scratch);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+
+ success = true;
+ resetErr();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>Success</p>');
+ });
+
+ it('calls the errorBoundary callback', () => {
+ const spy = sinon.spy();
+ const error = new Error('test');
+ const Throws = () => {
+ throw error;
+ };
+
+ const App = props => {
+ const [err] = useErrorBoundary(spy);
+ return err ? <p>Error</p> : <Throws />;
+ };
+
+ render(<App />, scratch);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith(error);
+ });
+
+ it('does not leave a stale closure', () => {
+ const spy = sinon.spy(),
+ spy2 = sinon.spy();
+ let resetErr;
+ const error = new Error('test');
+ const Throws = () => {
+ throw error;
+ };
+
+ const App = props => {
+ const [err, reset] = useErrorBoundary(props.onError);
+ resetErr = reset;
+ return err ? <p>Error</p> : <Throws />;
+ };
+
+ render(<App onError={spy} />, scratch);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith(error);
+
+ resetErr();
+ render(<App onError={spy2} />, scratch);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ expect(spy).to.be.calledOnce;
+ expect(spy2).to.be.calledOnce;
+ expect(spy2).to.be.calledWith(error);
+ });
+});
diff --git a/preact/hooks/test/browser/hooks.options.test.js b/preact/hooks/test/browser/hooks.options.test.js
new file mode 100644
index 0000000..ca88d1f
--- /dev/null
+++ b/preact/hooks/test/browser/hooks.options.test.js
@@ -0,0 +1,154 @@
+import {
+ afterDiffSpy,
+ beforeRenderSpy,
+ unmountSpy,
+ hookSpy
+} from '../../../test/_util/optionSpies';
+
+import { setupRerender, act } from 'preact/test-utils';
+import { createElement, render, createContext, options } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import {
+ useState,
+ useReducer,
+ useEffect,
+ useLayoutEffect,
+ useRef,
+ useImperativeHandle,
+ useMemo,
+ useCallback,
+ useContext,
+ useErrorBoundary
+} from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('hook options', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ /** @type {() => void} */
+ let increment;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ afterDiffSpy.resetHistory();
+ unmountSpy.resetHistory();
+ beforeRenderSpy.resetHistory();
+ hookSpy.resetHistory();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ function App() {
+ const [count, setCount] = useState(0);
+ increment = () => setCount(prevCount => prevCount + 1);
+ return <div>{count}</div>;
+ }
+
+ it('should call old options on mount', () => {
+ render(<App />, scratch);
+
+ expect(beforeRenderSpy).to.have.been.called;
+ expect(afterDiffSpy).to.have.been.called;
+ });
+
+ it('should call old options.diffed on update', () => {
+ render(<App />, scratch);
+
+ increment();
+ rerender();
+
+ expect(beforeRenderSpy).to.have.been.called;
+ expect(afterDiffSpy).to.have.been.called;
+ });
+
+ it('should call old options on unmount', () => {
+ render(<App />, scratch);
+ render(null, scratch);
+
+ expect(unmountSpy).to.have.been.called;
+ });
+
+ it('should detect hooks', () => {
+ const USE_STATE = 1;
+ const USE_REDUCER = 2;
+ const USE_EFFECT = 3;
+ const USE_LAYOUT_EFFECT = 4;
+ const USE_REF = 5;
+ const USE_IMPERATIVE_HANDLE = 6;
+ const USE_MEMO = 7;
+ const USE_CALLBACK = 8;
+ const USE_CONTEXT = 9;
+ const USE_ERROR_BOUNDARY = 10;
+
+ const Ctx = createContext(null);
+
+ function App() {
+ useState(0);
+ useReducer(x => x, 0);
+ useEffect(() => null, []);
+ useLayoutEffect(() => null, []);
+ const ref = useRef(null);
+ useImperativeHandle(ref, () => null);
+ useMemo(() => null, []);
+ useCallback(() => null, []);
+ useContext(Ctx);
+ useErrorBoundary(() => null);
+ }
+
+ render(
+ <Ctx.Provider value="a">
+ <App />
+ </Ctx.Provider>,
+ scratch
+ );
+
+ expect(hookSpy.args.map(arg => [arg[1], arg[2]])).to.deep.equal([
+ [0, USE_STATE],
+ [1, USE_REDUCER],
+ [2, USE_EFFECT],
+ [3, USE_LAYOUT_EFFECT],
+ [4, USE_REF],
+ [5, USE_IMPERATIVE_HANDLE],
+ [6, USE_MEMO],
+ [7, USE_CALLBACK],
+ [8, USE_CONTEXT],
+ [9, USE_ERROR_BOUNDARY],
+ // Belongs to useErrorBoundary that uses multiple native hooks.
+ [10, USE_STATE]
+ ]);
+ });
+
+ describe('Effects', () => {
+ beforeEach(() => {
+ options._skipEffects = options.__s = true;
+ });
+
+ afterEach(() => {
+ options._skipEffects = options.__s = false;
+ });
+
+ it('should skip effect hooks', () => {
+ const spy = sinon.spy();
+ function App() {
+ useEffect(spy, []);
+ useLayoutEffect(spy, []);
+ return null;
+ }
+
+ act(() => {
+ render(<App />, scratch);
+ });
+
+ expect(spy.callCount).to.equal(0);
+ });
+ });
+});
diff --git a/preact/hooks/test/browser/useCallback.test.js b/preact/hooks/test/browser/useCallback.test.js
new file mode 100644
index 0000000..151fed9
--- /dev/null
+++ b/preact/hooks/test/browser/useCallback.test.js
@@ -0,0 +1,41 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useCallback } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useCallback', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('only recomputes the callback when inputs change', () => {
+ const callbacks = [];
+
+ function Comp({ a, b }) {
+ const cb = useCallback(() => a + b, [a, b]);
+ callbacks.push(cb);
+ return null;
+ }
+
+ render(<Comp a={1} b={1} />, scratch);
+ render(<Comp a={1} b={1} />, scratch);
+
+ expect(callbacks[0]).to.equal(callbacks[1]);
+ expect(callbacks[0]()).to.equal(2);
+
+ render(<Comp a={1} b={2} />, scratch);
+ render(<Comp a={1} b={2} />, scratch);
+
+ expect(callbacks[1]).to.not.equal(callbacks[2]);
+ expect(callbacks[2]).to.equal(callbacks[3]);
+ expect(callbacks[2]()).to.equal(3);
+ });
+});
diff --git a/preact/hooks/test/browser/useContext.test.js b/preact/hooks/test/browser/useContext.test.js
new file mode 100644
index 0000000..67b7851
--- /dev/null
+++ b/preact/hooks/test/browser/useContext.test.js
@@ -0,0 +1,351 @@
+import { createElement, render, createContext, Component } from 'preact';
+import { act } from 'preact/test-utils';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useContext, useEffect, useState } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useContext', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('gets values from context', () => {
+ const values = [];
+ const Context = createContext(13);
+
+ function Comp() {
+ const value = useContext(Context);
+ values.push(value);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(
+ <Context.Provider value={42}>
+ <Comp />
+ </Context.Provider>,
+ scratch
+ );
+ render(
+ <Context.Provider value={69}>
+ <Comp />
+ </Context.Provider>,
+ scratch
+ );
+
+ expect(values).to.deep.equal([13, 42, 69]);
+ });
+
+ it('should use default value', () => {
+ const Foo = createContext(42);
+ const spy = sinon.spy();
+
+ function App() {
+ spy(useContext(Foo));
+ return <div />;
+ }
+
+ render(<App />, scratch);
+ expect(spy).to.be.calledWith(42);
+ });
+
+ it('should update when value changes with nonUpdating Component on top', done => {
+ const spy = sinon.spy();
+ const Ctx = createContext(0);
+
+ class NoUpdate extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return this.props.children;
+ }
+ }
+
+ function App(props) {
+ return (
+ <Ctx.Provider value={props.value}>
+ <NoUpdate>
+ <Comp />
+ </NoUpdate>
+ </Ctx.Provider>
+ );
+ }
+
+ function Comp() {
+ const value = useContext(Ctx);
+ spy(value);
+ return <h1>{value}</h1>;
+ }
+
+ render(<App value={0} />, scratch);
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith(0);
+ render(<App value={1} />, scratch);
+
+ // Wait for enqueued hook update
+ setTimeout(() => {
+ // Should not be called a third time
+ expect(spy).to.be.calledTwice;
+ expect(spy).to.be.calledWith(1);
+ done();
+ }, 0);
+ });
+
+ it('should only update when value has changed', done => {
+ const spy = sinon.spy();
+ const Ctx = createContext(0);
+
+ function App(props) {
+ return (
+ <Ctx.Provider value={props.value}>
+ <Comp />
+ </Ctx.Provider>
+ );
+ }
+
+ function Comp() {
+ const value = useContext(Ctx);
+ spy(value);
+ return <h1>{value}</h1>;
+ }
+
+ render(<App value={0} />, scratch);
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith(0);
+ render(<App value={1} />, scratch);
+
+ expect(spy).to.be.calledTwice;
+ expect(spy).to.be.calledWith(1);
+
+ // Wait for enqueued hook update
+ setTimeout(() => {
+ // Should not be called a third time
+ expect(spy).to.be.calledTwice;
+ done();
+ }, 0);
+ });
+
+ it('should allow multiple context hooks at the same time', () => {
+ const Foo = createContext(0);
+ const Bar = createContext(10);
+ const spy = sinon.spy();
+ const unmountspy = sinon.spy();
+
+ function Comp() {
+ const foo = useContext(Foo);
+ const bar = useContext(Bar);
+ spy(foo, bar);
+ useEffect(() => () => unmountspy());
+
+ return <div />;
+ }
+
+ render(
+ <Foo.Provider value={0}>
+ <Bar.Provider value={10}>
+ <Comp />
+ </Bar.Provider>
+ </Foo.Provider>,
+ scratch
+ );
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith(0, 10);
+
+ render(
+ <Foo.Provider value={11}>
+ <Bar.Provider value={42}>
+ <Comp />
+ </Bar.Provider>
+ </Foo.Provider>,
+ scratch
+ );
+
+ expect(spy).to.be.calledTwice;
+ expect(unmountspy).not.to.be.called;
+ });
+
+ it('should only subscribe a component once', () => {
+ const values = [];
+ const Context = createContext(13);
+ let provider, subSpy;
+
+ function Comp() {
+ const value = useContext(Context);
+ values.push(value);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ render(
+ <Context.Provider ref={p => (provider = p)} value={42}>
+ <Comp />
+ </Context.Provider>,
+ scratch
+ );
+ subSpy = sinon.spy(provider, 'sub');
+
+ render(
+ <Context.Provider value={69}>
+ <Comp />
+ </Context.Provider>,
+ scratch
+ );
+ expect(subSpy).to.not.have.been.called;
+
+ expect(values).to.deep.equal([13, 42, 69]);
+ });
+
+ it('should maintain context', done => {
+ const context = createContext(null);
+ const { Provider } = context;
+ const first = { name: 'first' };
+ const second = { name: 'second' };
+
+ const Input = () => {
+ const config = useContext(context);
+
+ // Avoid eslint complaining about unused first value
+ const state = useState('initial');
+ const set = state[1];
+
+ useEffect(() => {
+ // Schedule the update on the next frame
+ requestAnimationFrame(() => {
+ set('irrelevant');
+ });
+ }, [config]);
+
+ return <div>{config.name}</div>;
+ };
+
+ const App = props => {
+ const [config, setConfig] = useState({});
+
+ useEffect(() => {
+ setConfig(props.config);
+ }, [props.config]);
+
+ return (
+ <Provider value={config}>
+ <Input />
+ </Provider>
+ );
+ };
+
+ act(() => {
+ render(<App config={first} />, scratch);
+
+ // Create a new div to append the `second` case
+ const div = scratch.appendChild(document.createElement('div'));
+ render(<App config={second} />, div);
+ });
+
+ // Push the expect into the next frame
+ requestAnimationFrame(() => {
+ expect(scratch.innerHTML).equal(
+ '<div>first</div><div><div>second</div></div>'
+ );
+ done();
+ });
+ });
+
+ it('should not rerender consumers that have been unmounted', () => {
+ const context = createContext(0);
+ const Provider = context.Provider;
+
+ const Inner = sinon.spy(() => {
+ const value = useContext(context);
+ return <div>{value}</div>;
+ });
+
+ let toggleConsumer;
+ let changeValue;
+ class App extends Component {
+ constructor() {
+ super();
+
+ this.state = { value: 0, show: true };
+ changeValue = value => this.setState({ value });
+ toggleConsumer = () => this.setState(({ show }) => ({ show: !show }));
+ }
+ render(props, state) {
+ return (
+ <Provider value={state.value}>
+ <div>{state.show ? <Inner /> : null}</div>
+ </Provider>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><div>0</div></div>');
+ expect(Inner).to.have.been.calledOnce;
+
+ act(() => changeValue(1));
+ expect(scratch.innerHTML).to.equal('<div><div>1</div></div>');
+ expect(Inner).to.have.been.calledTwice;
+
+ act(() => toggleConsumer());
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ expect(Inner).to.have.been.calledTwice;
+
+ act(() => changeValue(2));
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ expect(Inner).to.have.been.calledTwice;
+ });
+
+ it('should rerender when reset to defaultValue', () => {
+ const defaultValue = { state: 'hi' };
+ const context = createContext(defaultValue);
+ let set;
+
+ const Consumer = () => {
+ const ctx = useContext(context);
+ return <p>{ctx.state}</p>;
+ };
+
+ class NoUpdate extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return <Consumer />;
+ }
+ }
+
+ const Provider = () => {
+ const [state, setState] = useState(defaultValue);
+ set = setState;
+ return (
+ <context.Provider value={state}>
+ <NoUpdate />
+ </context.Provider>
+ );
+ };
+
+ render(<Provider />, scratch);
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+
+ act(() => {
+ set({ state: 'bye' });
+ });
+ expect(scratch.innerHTML).to.equal('<p>bye</p>');
+
+ act(() => {
+ set(defaultValue);
+ });
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+ });
+});
diff --git a/preact/hooks/test/browser/useDebugValue.test.js b/preact/hooks/test/browser/useDebugValue.test.js
new file mode 100644
index 0000000..d19ff6b
--- /dev/null
+++ b/preact/hooks/test/browser/useDebugValue.test.js
@@ -0,0 +1,71 @@
+import { createElement, render, options } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useDebugValue, useState } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useDebugValue', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ delete options.useDebugValue;
+ });
+
+ it('should do nothing when no options hook is present', () => {
+ function useFoo() {
+ useDebugValue('foo');
+ return useState(0);
+ }
+
+ function App() {
+ let [v] = useFoo();
+ return <div>{v}</div>;
+ }
+
+ expect(() => render(<App />, scratch)).to.not.throw();
+ });
+
+ it('should call options hook with value', () => {
+ let spy = (options.useDebugValue = sinon.spy());
+
+ function useFoo() {
+ useDebugValue('foo');
+ return useState(0);
+ }
+
+ function App() {
+ let [v] = useFoo();
+ return <div>{v}</div>;
+ }
+
+ render(<App />, scratch);
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith('foo');
+ });
+
+ it('should apply optional formatter', () => {
+ let spy = (options.useDebugValue = sinon.spy());
+
+ function useFoo() {
+ useDebugValue('foo', x => x + 'bar');
+ return useState(0);
+ }
+
+ function App() {
+ let [v] = useFoo();
+ return <div>{v}</div>;
+ }
+
+ render(<App />, scratch);
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWith('foobar');
+ });
+});
diff --git a/preact/hooks/test/browser/useEffect.test.js b/preact/hooks/test/browser/useEffect.test.js
new file mode 100644
index 0000000..a16d3fc
--- /dev/null
+++ b/preact/hooks/test/browser/useEffect.test.js
@@ -0,0 +1,373 @@
+import { act } from 'preact/test-utils';
+import { createElement, render, Fragment, Component } from 'preact';
+import { useEffect, useState, useRef } from 'preact/hooks';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useEffectAssertions } from './useEffectAssertions.test';
+import { scheduleEffectAssert } from '../_util/useEffectUtil';
+
+/** @jsx createElement */
+
+describe('useEffect', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ useEffectAssertions(useEffect, scheduleEffectAssert);
+
+ it('calls the effect immediately if another render is about to start', () => {
+ const cleanupFunction = sinon.spy();
+ const callback = sinon.spy(() => cleanupFunction);
+
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(cleanupFunction).to.be.not.called;
+ expect(callback).to.be.calledOnce;
+
+ render(<Comp />, scratch);
+
+ expect(cleanupFunction).to.be.calledOnce;
+ expect(callback).to.be.calledTwice;
+ });
+
+ it('cancels the effect when the component get unmounted before it had the chance to run it', () => {
+ const cleanupFunction = sinon.spy();
+ const callback = sinon.spy(() => cleanupFunction);
+
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(null, scratch);
+
+ return scheduleEffectAssert(() => {
+ expect(cleanupFunction).to.not.be.called;
+ expect(callback).to.not.be.called;
+ });
+ });
+
+ it('should execute multiple effects in same component in the right order', () => {
+ let executionOrder = [];
+ const App = ({ i }) => {
+ executionOrder = [];
+ useEffect(() => {
+ executionOrder.push('action1');
+ return () => executionOrder.push('cleanup1');
+ }, [i]);
+ useEffect(() => {
+ executionOrder.push('action2');
+ return () => executionOrder.push('cleanup2');
+ }, [i]);
+ return <p>Test</p>;
+ };
+ act(() => render(<App i={0} />, scratch));
+ act(() => render(<App i={2} />, scratch));
+ expect(executionOrder).to.deep.equal([
+ 'cleanup1',
+ 'cleanup2',
+ 'action1',
+ 'action2'
+ ]);
+ });
+
+ it('should execute effects in parent if child throws in effect', async () => {
+ let executionOrder = [];
+
+ const Child = () => {
+ useEffect(() => {
+ executionOrder.push('child');
+ throw new Error('test');
+ }, []);
+
+ useEffect(() => {
+ executionOrder.push('child after throw');
+ return () => executionOrder.push('child after throw cleanup');
+ }, []);
+
+ return <p>Test</p>;
+ };
+
+ const Parent = () => {
+ useEffect(() => {
+ executionOrder.push('parent');
+ return () => executionOrder.push('parent cleanup');
+ }, []);
+ return <Child />;
+ };
+
+ class ErrorBoundary extends Component {
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+
+ render({ children }, { error }) {
+ return error ? <div>error</div> : children;
+ }
+ }
+
+ act(() =>
+ render(
+ <ErrorBoundary>
+ <Parent />
+ </ErrorBoundary>,
+ scratch
+ )
+ );
+
+ expect(executionOrder).to.deep.equal(['child', 'parent', 'parent cleanup']);
+ expect(scratch.innerHTML).to.equal('<div>error</div>');
+ });
+
+ it('should throw an error upwards', () => {
+ const spy = sinon.spy();
+ let errored = false;
+
+ const Page1 = () => {
+ const [state, setState] = useState('loading');
+ useEffect(() => {
+ setState('loaded');
+ }, []);
+ return <p>{state}</p>;
+ };
+
+ const Page2 = () => {
+ useEffect(() => {
+ throw new Error('err');
+ }, []);
+ return <p>invisible</p>;
+ };
+
+ class App extends Component {
+ componentDidCatch(err) {
+ spy();
+ errored = err;
+ this.forceUpdate();
+ }
+
+ render(props, state) {
+ if (errored) {
+ return <p>Error</p>;
+ }
+
+ return <Fragment>{props.page === 1 ? <Page1 /> : <Page2 />}</Fragment>;
+ }
+ }
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.not.be.called;
+ expect(scratch.innerHTML).to.equal('<p>loaded</p>');
+
+ act(() => render(<App page={2} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ errored = false;
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>loaded</p>');
+ });
+
+ it('should throw an error upwards from return', () => {
+ const spy = sinon.spy();
+ let errored = false;
+
+ const Page1 = () => {
+ const [state, setState] = useState('loading');
+ useEffect(() => {
+ setState('loaded');
+ }, []);
+ return <p>{state}</p>;
+ };
+
+ const Page2 = () => {
+ useEffect(() => {
+ return () => {
+ throw new Error('err');
+ };
+ }, []);
+ return <p>Load</p>;
+ };
+
+ class App extends Component {
+ componentDidCatch(err) {
+ spy();
+ errored = err;
+ this.forceUpdate();
+ }
+
+ render(props, state) {
+ if (errored) {
+ return <p>Error</p>;
+ }
+
+ return <Fragment>{props.page === 1 ? <Page1 /> : <Page2 />}</Fragment>;
+ }
+ }
+
+ act(() => render(<App page={2} />, scratch));
+ expect(scratch.innerHTML).to.equal('<p>Load</p>');
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ });
+
+ it('catches errors when error is invoked during render', () => {
+ const spy = sinon.spy();
+ let errored;
+
+ function Comp() {
+ useEffect(() => {
+ throw new Error('hi');
+ });
+ return null;
+ }
+
+ class App extends Component {
+ componentDidCatch(err) {
+ spy();
+ errored = err;
+ this.forceUpdate();
+ }
+
+ render(props, state) {
+ if (errored) {
+ return <p>Error</p>;
+ }
+
+ return <Comp />;
+ }
+ }
+
+ render(<App />, scratch);
+ act(() => {
+ render(<App />, scratch);
+ });
+ expect(spy).to.be.calledOnce;
+ expect(errored)
+ .to.be.an('Error')
+ .with.property('message', 'hi');
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ });
+
+ it('should allow creating a new root', () => {
+ const root = document.createElement('div');
+ const global = document.createElement('div');
+ scratch.appendChild(root);
+ scratch.appendChild(global);
+
+ const Modal = props => {
+ let [, setCanProceed] = useState(true);
+ let ChildProp = props.content;
+
+ return (
+ <div>
+ <ChildProp setCanProceed={setCanProceed} />
+ </div>
+ );
+ };
+
+ const Inner = () => {
+ useEffect(() => {
+ render(<div>global</div>, global);
+ }, []);
+
+ return <div>Inner</div>;
+ };
+
+ act(() => {
+ render(
+ <Modal
+ content={props => {
+ props.setCanProceed(false);
+ return <Inner />;
+ }}
+ />,
+ root
+ );
+ });
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><div><div>Inner</div></div></div><div><div>global</div></div>'
+ );
+ });
+
+ it('should not crash when effect returns truthy non-function value', () => {
+ const callback = sinon.spy(() => 'truthy');
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(callback).to.have.been.calledOnce;
+
+ render(<div>Replacement</div>, scratch);
+ });
+
+ it('support render roots from an effect', async () => {
+ let promise, increment;
+
+ const Counter = () => {
+ const [count, setCount] = useState(0);
+ const renderRoot = useRef();
+ useEffect(() => {
+ if (count > 0) {
+ const div = renderRoot.current;
+ return () => render(<Dummy />, div);
+ }
+ return () => 'test';
+ }, [count]);
+
+ increment = () => {
+ setCount(x => x + 1);
+ promise = new Promise(res => {
+ setTimeout(() => {
+ setCount(x => x + 1);
+ res();
+ });
+ });
+ };
+
+ return (
+ <div>
+ <div>Count: {count}</div>
+ <div ref={renderRoot} />
+ </div>
+ );
+ };
+
+ const Dummy = () => <div>dummy</div>;
+
+ render(<Counter />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>Count: 0</div><div></div></div>'
+ );
+
+ act(() => {
+ increment();
+ });
+ await promise;
+ act(() => {});
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>Count: 2</div><div><div>dummy</div></div></div>'
+ );
+ });
+});
diff --git a/preact/hooks/test/browser/useEffectAssertions.test.js b/preact/hooks/test/browser/useEffectAssertions.test.js
new file mode 100644
index 0000000..74ba232
--- /dev/null
+++ b/preact/hooks/test/browser/useEffectAssertions.test.js
@@ -0,0 +1,142 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+// Common behaviors between all effect hooks
+export function useEffectAssertions(useEffect, scheduleEffectAssert) {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('performs the effect after every render by default', () => {
+ const callback = sinon.spy();
+
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ return scheduleEffectAssert(() => expect(callback).to.be.calledOnce)
+ .then(() => scheduleEffectAssert(() => expect(callback).to.be.calledOnce))
+ .then(() => render(<Comp />, scratch))
+ .then(() =>
+ scheduleEffectAssert(() => expect(callback).to.be.calledTwice)
+ );
+ });
+
+ it('performs the effect only if one of the inputs changed', () => {
+ const callback = sinon.spy();
+
+ function Comp(props) {
+ useEffect(callback, [props.a, props.b]);
+ return null;
+ }
+
+ render(<Comp a={1} b={2} />, scratch);
+
+ return scheduleEffectAssert(() => expect(callback).to.be.calledOnce)
+ .then(() => render(<Comp a={1} b={2} />, scratch))
+ .then(() => scheduleEffectAssert(() => expect(callback).to.be.calledOnce))
+ .then(() => render(<Comp a={2} b={2} />, scratch))
+ .then(() =>
+ scheduleEffectAssert(() => expect(callback).to.be.calledTwice)
+ )
+ .then(() => render(<Comp a={2} b={2} />, scratch))
+ .then(() =>
+ scheduleEffectAssert(() => expect(callback).to.be.calledTwice)
+ );
+ });
+
+ it('performs the effect at mount time and never again if an empty input Array is passed', () => {
+ const callback = sinon.spy();
+
+ function Comp() {
+ useEffect(callback, []);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(callback).to.be.calledOnce;
+
+ return scheduleEffectAssert(() => expect(callback).to.be.calledOnce)
+ .then(() => render(<Comp />, scratch))
+ .then(() =>
+ scheduleEffectAssert(() => expect(callback).to.be.calledOnce)
+ );
+ });
+
+ it('calls the cleanup function followed by the effect after each render', () => {
+ const cleanupFunction = sinon.spy();
+ const callback = sinon.spy(() => cleanupFunction);
+
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ return scheduleEffectAssert(() => {
+ expect(cleanupFunction).to.be.not.called;
+ expect(callback).to.be.calledOnce;
+ })
+ .then(() => scheduleEffectAssert(() => expect(callback).to.be.calledOnce))
+ .then(() => render(<Comp />, scratch))
+ .then(() =>
+ scheduleEffectAssert(() => {
+ expect(cleanupFunction).to.be.calledOnce;
+ expect(callback).to.be.calledTwice;
+ expect(callback.lastCall.calledAfter(cleanupFunction.lastCall));
+ })
+ );
+ });
+
+ it('cleanups the effect when the component get unmounted if the effect was called before', () => {
+ const cleanupFunction = sinon.spy();
+ const callback = sinon.spy(() => cleanupFunction);
+
+ function Comp() {
+ useEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ return scheduleEffectAssert(() => {
+ render(null, scratch);
+ rerender();
+ expect(cleanupFunction).to.be.calledOnce;
+ });
+ });
+
+ it('works with closure effect callbacks capturing props', () => {
+ const values = [];
+
+ function Comp(props) {
+ useEffect(() => values.push(props.value));
+ return null;
+ }
+
+ render(<Comp value={1} />, scratch);
+ render(<Comp value={2} />, scratch);
+
+ return scheduleEffectAssert(() => expect(values).to.deep.equal([1, 2]));
+ });
+}
diff --git a/preact/hooks/test/browser/useImperativeHandle.test.js b/preact/hooks/test/browser/useImperativeHandle.test.js
new file mode 100644
index 0000000..52cc073
--- /dev/null
+++ b/preact/hooks/test/browser/useImperativeHandle.test.js
@@ -0,0 +1,182 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useImperativeHandle, useRef, useState } from 'preact/hooks';
+import { setupRerender } from 'preact/test-utils';
+
+/** @jsx createElement */
+
+describe('useImperativeHandle', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('Mutates given ref', () => {
+ let ref;
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, () => ({ test: () => 'test' }), []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test');
+ });
+
+ it('calls createHandle after every render by default', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledThrice;
+ });
+
+ it('calls createHandle only on mount if an empty array is passed', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy, []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ });
+
+ it('Updates given ref when args change', () => {
+ let ref,
+ createHandleSpy = sinon.spy();
+
+ function Comp({ a }) {
+ ref = useRef({});
+ useImperativeHandle(
+ ref,
+ () => {
+ createHandleSpy();
+ return { test: () => 'test' + a };
+ },
+ [a]
+ );
+ return <p>Test</p>;
+ }
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test0');
+
+ render(<Comp a={1} />, scratch);
+ expect(createHandleSpy).to.have.been.calledTwice;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test1');
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledThrice;
+ expect(ref.current).to.have.property('test');
+ expect(ref.current.test()).to.equal('test0');
+ });
+
+ it('Updates given ref when passed-in ref changes', () => {
+ let ref1, ref2;
+
+ /** @type {(arg: any) => void} */
+ let setRef;
+
+ /** @type {() => void} */
+ let updateState;
+
+ const createHandleSpy = sinon.spy(() => ({
+ test: () => 'test'
+ }));
+
+ function Comp() {
+ ref1 = useRef({});
+ ref2 = useRef({});
+
+ const [ref, setRefInternal] = useState(ref1);
+ setRef = setRefInternal;
+
+ let [value, setState] = useState(0);
+ updateState = () => setState((value + 1) % 2);
+
+ useImperativeHandle(ref, createHandleSpy, []);
+ return <p>Test</p>;
+ }
+
+ render(<Comp a={0} />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ updateState();
+ rerender();
+ expect(createHandleSpy).to.have.been.calledOnce;
+
+ setRef(ref2);
+ rerender();
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ updateState();
+ rerender();
+ expect(createHandleSpy).to.have.been.calledTwice;
+
+ setRef(ref1);
+ rerender();
+ expect(createHandleSpy).to.have.been.calledThrice;
+ });
+
+ it('should not update ref when args have not changed', () => {
+ let ref,
+ createHandleSpy = sinon.spy(() => ({ test: () => 'test' }));
+
+ function Comp() {
+ ref = useRef({});
+ useImperativeHandle(ref, createHandleSpy, [1]);
+ return <p>Test</p>;
+ }
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current.test()).to.equal('test');
+
+ render(<Comp />, scratch);
+ expect(createHandleSpy).to.have.been.calledOnce;
+ expect(ref.current.test()).to.equal('test');
+ });
+
+ it('should not throw with nullish ref', () => {
+ function Comp() {
+ useImperativeHandle(null, () => ({ test: () => 'test' }), [1]);
+ return <p>Test</p>;
+ }
+
+ expect(() => render(<Comp />, scratch)).to.not.throw();
+ });
+});
diff --git a/preact/hooks/test/browser/useLayoutEffect.test.js b/preact/hooks/test/browser/useLayoutEffect.test.js
new file mode 100644
index 0000000..72ab949
--- /dev/null
+++ b/preact/hooks/test/browser/useLayoutEffect.test.js
@@ -0,0 +1,326 @@
+import { act } from 'preact/test-utils';
+import { createElement, render, Fragment, Component } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml
+} from '../../../test/_util/helpers';
+import { useEffectAssertions } from './useEffectAssertions.test';
+import { useLayoutEffect, useRef, useState } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useLayoutEffect', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ // Layout effects fire synchronously
+ const scheduleEffectAssert = assertFn =>
+ new Promise(resolve => {
+ assertFn();
+ resolve();
+ });
+
+ useEffectAssertions(useLayoutEffect, scheduleEffectAssert);
+
+ it('calls the effect immediately after render', () => {
+ const cleanupFunction = sinon.spy();
+ const callback = sinon.spy(() => cleanupFunction);
+
+ function Comp() {
+ useLayoutEffect(callback);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(cleanupFunction).to.be.calledOnce;
+ expect(callback).to.be.calledTwice;
+
+ render(<Comp />, scratch);
+
+ expect(cleanupFunction).to.be.calledTwice;
+ expect(callback).to.be.calledThrice;
+ });
+
+ it('works on a nested component', () => {
+ const callback = sinon.spy();
+
+ function Parent() {
+ return (
+ <div>
+ <Child />
+ </div>
+ );
+ }
+
+ function Child() {
+ useLayoutEffect(callback);
+ return null;
+ }
+
+ render(<Parent />, scratch);
+
+ expect(callback).to.be.calledOnce;
+ });
+
+ it('should execute multiple layout effects in same component in the right order', () => {
+ let executionOrder = [];
+ const App = ({ i }) => {
+ executionOrder = [];
+ useLayoutEffect(() => {
+ executionOrder.push('action1');
+ return () => executionOrder.push('cleanup1');
+ }, [i]);
+ useLayoutEffect(() => {
+ executionOrder.push('action2');
+ return () => executionOrder.push('cleanup2');
+ }, [i]);
+ return <p>Test</p>;
+ };
+ render(<App i={0} />, scratch);
+ render(<App i={2} />, scratch);
+ expect(executionOrder).to.deep.equal([
+ 'cleanup1',
+ 'cleanup2',
+ 'action1',
+ 'action2'
+ ]);
+ });
+
+ it('should correctly display DOM', () => {
+ function AutoResizeTextareaLayoutEffect(props) {
+ const ref = useRef(null);
+ useLayoutEffect(() => {
+ // IE & Edge put textarea's value as child of textarea when reading innerHTML so use
+ // cross browser serialize helper
+ const actualHtml = serializeHtml(scratch);
+ const expectedHTML = `<div class="${props.value}"><p>${props.value}</p><textarea></textarea></div>`;
+ expect(actualHtml).to.equal(expectedHTML);
+ expect(document.body.contains(ref.current)).to.equal(true);
+ });
+ return (
+ <Fragment>
+ <p>{props.value}</p>
+ <textarea ref={ref} value={props.value} onChange={props.onChange} />
+ </Fragment>
+ );
+ }
+
+ function App(props) {
+ return (
+ <div class={props.value}>
+ <AutoResizeTextareaLayoutEffect {...props} />
+ </div>
+ );
+ }
+
+ render(<App value="hi" />, scratch);
+ render(<App value="hii" />, scratch);
+ });
+
+ it('should invoke layout effects after subtree is fully connected', () => {
+ let ref;
+ let layoutEffect = sinon.spy(() => {
+ const isConnected = document.body.contains(ref.current);
+ expect(isConnected).to.equal(true, 'isConnected');
+ });
+
+ function Inner() {
+ ref = useRef(null);
+ useLayoutEffect(layoutEffect);
+ return (
+ <Fragment>
+ <textarea ref={ref} />
+ <span>hello</span>;
+ </Fragment>
+ );
+ }
+
+ function Outer() {
+ return (
+ <div>
+ <Inner />
+ </div>
+ );
+ }
+
+ render(<Outer />, scratch);
+ expect(layoutEffect).to.have.been.calledOnce;
+ });
+
+ // TODO: Make this test pass to resolve issue #1886
+ it.skip('should call effects correctly when unmounting', () => {
+ let onClick, calledFoo, calledBar, calledFooCleanup, calledBarCleanup;
+
+ const Foo = () => {
+ useLayoutEffect(() => {
+ if (!calledFoo) calledFoo = scratch.innerHTML;
+ return () => {
+ if (!calledFooCleanup) calledFooCleanup = scratch.innerHTML;
+ };
+ }, []);
+
+ return (
+ <div>
+ <p>Foo</p>
+ </div>
+ );
+ };
+
+ const Bar = () => {
+ useLayoutEffect(() => {
+ if (!calledBar) calledBar = scratch.innerHTML;
+ return () => {
+ if (!calledBarCleanup) calledBarCleanup = scratch.innerHTML;
+ };
+ }, []);
+
+ return (
+ <div>
+ <p>Bar</p>
+ </div>
+ );
+ };
+
+ function App() {
+ const [current, setCurrent] = useState('/foo');
+
+ onClick = () => setCurrent(current === '/foo' ? '/bar' : '/foo');
+
+ return (
+ <Fragment>
+ <button onClick={onClick}>next</button>
+
+ {current === '/foo' && <Foo />}
+ {current === '/bar' && <Bar />}
+ </Fragment>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(calledFoo).to.equal(
+ '<button>next</button><div><p>Foo</p></div>',
+ 'calledFoo'
+ );
+
+ act(() => onClick());
+ expect(calledFooCleanup).to.equal(
+ '<button>next</button><div><p>Bar</p></div>',
+ 'calledFooCleanup'
+ );
+ expect(calledBar).to.equal(
+ '<button>next</button><div><p>Bar</p></div>',
+ 'calledBar'
+ );
+
+ act(() => onClick());
+ expect(calledBarCleanup).to.equal(
+ '<button>next</button><div><p>Foo</p></div>',
+ 'calledBarCleanup'
+ );
+ });
+
+ it('should throw an error upwards', () => {
+ const spy = sinon.spy();
+ let errored = false;
+
+ const Page1 = () => {
+ const [state, setState] = useState('loading');
+ useLayoutEffect(() => {
+ setState('loaded');
+ }, []);
+ return <p>{state}</p>;
+ };
+
+ const Page2 = () => {
+ useLayoutEffect(() => {
+ throw new Error('err');
+ }, []);
+ return <p>invisible</p>;
+ };
+
+ class App extends Component {
+ componentDidCatch(err) {
+ spy();
+ errored = err;
+ this.forceUpdate();
+ }
+
+ render(props, state) {
+ if (errored) {
+ return <p>Error</p>;
+ }
+
+ return <Fragment>{props.page === 1 ? <Page1 /> : <Page2 />}</Fragment>;
+ }
+ }
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.not.be.called;
+ expect(scratch.innerHTML).to.equal('<p>loaded</p>');
+
+ act(() => render(<App page={2} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ errored = false;
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>loaded</p>');
+ });
+
+ it('should throw an error upwards from return', () => {
+ const spy = sinon.spy();
+ let errored = false;
+
+ const Page1 = () => {
+ const [state, setState] = useState('loading');
+ useLayoutEffect(() => {
+ setState('loaded');
+ }, []);
+ return <p>{state}</p>;
+ };
+
+ const Page2 = () => {
+ useLayoutEffect(() => {
+ return () => {
+ throw new Error('err');
+ };
+ }, []);
+ return <p>Load</p>;
+ };
+
+ class App extends Component {
+ componentDidCatch(err) {
+ spy();
+ errored = err;
+ this.forceUpdate();
+ }
+
+ render(props, state) {
+ if (errored) {
+ return <p>Error</p>;
+ }
+
+ return <Fragment>{props.page === 1 ? <Page1 /> : <Page2 />}</Fragment>;
+ }
+ }
+
+ act(() => render(<App page={2} />, scratch));
+ expect(scratch.innerHTML).to.equal('<p>Load</p>');
+
+ act(() => render(<App page={1} />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<p>Error</p>');
+ });
+});
diff --git a/preact/hooks/test/browser/useMemo.test.js b/preact/hooks/test/browser/useMemo.test.js
new file mode 100644
index 0000000..68fb72e
--- /dev/null
+++ b/preact/hooks/test/browser/useMemo.test.js
@@ -0,0 +1,125 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useMemo } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useMemo', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('only recomputes the result when inputs change', () => {
+ let memoFunction = sinon.spy((a, b) => a + b);
+ const results = [];
+
+ function Comp({ a, b }) {
+ const result = useMemo(() => memoFunction(a, b), [a, b]);
+ results.push(result);
+ return null;
+ }
+
+ render(<Comp a={1} b={1} />, scratch);
+ render(<Comp a={1} b={1} />, scratch);
+
+ expect(results).to.deep.equal([2, 2]);
+ expect(memoFunction).to.have.been.calledOnce;
+
+ render(<Comp a={1} b={2} />, scratch);
+ render(<Comp a={1} b={2} />, scratch);
+
+ expect(results).to.deep.equal([2, 2, 3, 3]);
+ expect(memoFunction).to.have.been.calledTwice;
+ });
+
+ it('should rerun when deps length changes', () => {
+ let memoFunction = sinon.spy(() => 1 + 2);
+
+ function Comp({ all }) {
+ const deps = [1, all && 2].filter(Boolean);
+ const result = useMemo(() => memoFunction(), deps);
+ return result;
+ }
+
+ render(<Comp all />, scratch);
+ expect(memoFunction).to.have.been.calledOnce;
+ render(<Comp all={false} />, scratch);
+ expect(memoFunction).to.have.been.calledTwice;
+ });
+
+ it('should rerun when first run threw an error', () => {
+ let hasThrown = false;
+ let memoFunction = sinon.spy(() => {
+ if (!hasThrown) {
+ hasThrown = true;
+ throw new Error('test');
+ } else {
+ return 3;
+ }
+ });
+
+ function Comp() {
+ const result = useMemo(() => memoFunction(), []);
+ return result;
+ }
+
+ expect(() => render(<Comp />, scratch)).to.throw('test');
+ expect(memoFunction).to.have.been.calledOnce;
+ expect(() => render(<Comp />, scratch)).not.to.throw();
+ expect(memoFunction).to.have.been.calledTwice;
+ });
+
+ it('short circuits diffing for memoized components', () => {
+ let spy = sinon.spy();
+ let spy2 = sinon.spy();
+ const X = ({ count }) => {
+ spy();
+ return <span>{count}</span>;
+ };
+
+ const Y = ({ count }) => {
+ spy2();
+ return <p>{count}</p>;
+ };
+
+ const App = ({ x }) => {
+ const y = useMemo(() => <Y count={x} />, [x]);
+ return (
+ <div>
+ <X count={x} />
+ {y}
+ </div>
+ );
+ };
+
+ render(<App x={0} />, scratch);
+ expect(spy).to.be.calledOnce;
+ expect(spy2).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<div><span>0</span><p>0</p></div>');
+
+ render(<App x={0} />, scratch);
+ expect(spy).to.be.calledTwice;
+ expect(spy2).to.be.calledOnce;
+ expect(scratch.innerHTML).to.equal('<div><span>0</span><p>0</p></div>');
+
+ render(<App x={1} />, scratch);
+ expect(spy).to.be.calledThrice;
+ expect(spy2).to.be.calledTwice;
+ expect(scratch.innerHTML).to.equal('<div><span>1</span><p>1</p></div>');
+
+ render(<App x={1} />, scratch);
+ expect(spy2).to.be.calledTwice;
+ expect(scratch.innerHTML).to.equal('<div><span>1</span><p>1</p></div>');
+
+ render(<App x={2} />, scratch);
+ expect(spy2).to.be.calledThrice;
+ expect(scratch.innerHTML).to.equal('<div><span>2</span><p>2</p></div>');
+ });
+});
diff --git a/preact/hooks/test/browser/useReducer.test.js b/preact/hooks/test/browser/useReducer.test.js
new file mode 100644
index 0000000..4b9d393
--- /dev/null
+++ b/preact/hooks/test/browser/useReducer.test.js
@@ -0,0 +1,214 @@
+import { setupRerender, act } from 'preact/test-utils';
+import { createElement, render, createContext } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useReducer, useEffect, useContext } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useReducer', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('rerenders when dispatching an action', () => {
+ const states = [];
+ let _dispatch;
+
+ const initState = { count: 0 };
+
+ function reducer(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + action.by };
+ }
+ }
+
+ function Comp() {
+ const [state, dispatch] = useReducer(reducer, initState);
+ _dispatch = dispatch;
+ states.push(state);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ _dispatch({ type: 'increment', by: 10 });
+ rerender();
+
+ expect(states).to.deep.equal([{ count: 0 }, { count: 10 }]);
+ });
+
+ it('can be dispatched by another component', () => {
+ const initState = { count: 0 };
+
+ function reducer(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + action.by };
+ }
+ }
+
+ function ReducerComponent() {
+ const [state, dispatch] = useReducer(reducer, initState);
+ return (
+ <div>
+ <p>Count: {state.count}</p>
+ <DispatchComponent dispatch={dispatch} />
+ </div>
+ );
+ }
+
+ function DispatchComponent(props) {
+ return (
+ <button onClick={() => props.dispatch({ type: 'increment', by: 10 })}>
+ Increment
+ </button>
+ );
+ }
+
+ render(<ReducerComponent />, scratch);
+ expect(scratch.textContent).to.include('Count: 0');
+
+ const button = scratch.querySelector('button');
+ button.click();
+
+ rerender();
+ expect(scratch.textContent).to.include('Count: 10');
+ });
+
+ it('can lazily initialize its state with an action', () => {
+ const states = [];
+ let _dispatch;
+
+ function init(initialCount) {
+ return { count: initialCount };
+ }
+
+ function reducer(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + action.by };
+ }
+ }
+
+ function Comp({ initCount }) {
+ const [state, dispatch] = useReducer(reducer, initCount, init);
+ _dispatch = dispatch;
+ states.push(state);
+ return null;
+ }
+
+ render(<Comp initCount={10} />, scratch);
+
+ _dispatch({ type: 'increment', by: 10 });
+ rerender();
+
+ expect(states).to.deep.equal([{ count: 10 }, { count: 20 }]);
+ });
+
+ it('provides a stable reference for dispatch', () => {
+ const dispatches = [];
+ let _dispatch;
+
+ const initState = { count: 0 };
+
+ function reducer(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + action.by };
+ }
+ }
+
+ function Comp() {
+ const [, dispatch] = useReducer(reducer, initState);
+ _dispatch = dispatch;
+ dispatches.push(dispatch);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+
+ _dispatch({ type: 'increment', by: 10 });
+ rerender();
+
+ expect(dispatches[0]).to.equal(dispatches[1]);
+ });
+
+ it('uses latest reducer', () => {
+ const states = [];
+ let _dispatch;
+
+ const initState = { count: 0 };
+
+ function Comp({ increment }) {
+ const [state, dispatch] = useReducer(function(state, action) {
+ switch (action.type) {
+ case 'increment':
+ return { count: state.count + increment };
+ }
+ }, initState);
+ _dispatch = dispatch;
+ states.push(state);
+ return null;
+ }
+
+ render(<Comp increment={10} />, scratch);
+
+ render(<Comp increment={20} />, scratch);
+
+ _dispatch({ type: 'increment' });
+ rerender();
+
+ expect(states).to.deep.equal([{ count: 0 }, { count: 0 }, { count: 20 }]);
+ });
+
+ // Relates to #2549
+ it('should not mutate the hookState', () => {
+ const reducer = (state, action) => ({
+ ...state,
+ innerMessage: action.payload
+ });
+
+ const ContextMessage = ({ context }) => {
+ const [{ innerMessage }, dispatch] = useContext(context);
+ useEffect(() => {
+ dispatch({ payload: 'message' });
+ }, []);
+
+ return innerMessage && <p>{innerMessage}</p>;
+ };
+
+ const Wrapper = ({ children }) => <div>{children}</div>;
+
+ const badContextDefault = {};
+ const BadContext = createContext({});
+
+ const Abstraction = ({ reducer, defaultState, children }) => (
+ <BadContext.Provider value={useReducer(reducer, defaultState)}>
+ <Wrapper>{children}</Wrapper>
+ </BadContext.Provider>
+ );
+
+ const App = () => (
+ <Abstraction reducer={reducer} defaultState={badContextDefault}>
+ <ContextMessage context={BadContext} />
+ </Abstraction>
+ );
+
+ act(() => {
+ render(<App />, scratch);
+ });
+ expect(scratch.innerHTML).to.equal('<div><p>message</p></div>');
+ });
+});
diff --git a/preact/hooks/test/browser/useRef.test.js b/preact/hooks/test/browser/useRef.test.js
new file mode 100644
index 0000000..7d7a657
--- /dev/null
+++ b/preact/hooks/test/browser/useRef.test.js
@@ -0,0 +1,50 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useRef } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useRef', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('provides a stable reference', () => {
+ const values = [];
+
+ function Comp() {
+ const ref = useRef(1);
+ values.push(ref.current);
+ ref.current = 2;
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(values).to.deep.equal([1, 2]);
+ });
+
+ it('defaults to undefined', () => {
+ const values = [];
+
+ function Comp() {
+ const ref = useRef();
+ values.push(ref.current);
+ ref.current = 2;
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(values).to.deep.equal([undefined, 2]);
+ });
+});
diff --git a/preact/hooks/test/browser/useState.test.js b/preact/hooks/test/browser/useState.test.js
new file mode 100644
index 0000000..c65a21b
--- /dev/null
+++ b/preact/hooks/test/browser/useState.test.js
@@ -0,0 +1,214 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+import { useState } from 'preact/hooks';
+
+/** @jsx createElement */
+
+describe('useState', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('serves the same state across render calls', () => {
+ const stateHistory = [];
+
+ function Comp() {
+ const [state] = useState({ a: 1 });
+ stateHistory.push(state);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(stateHistory).to.deep.equal([{ a: 1 }, { a: 1 }]);
+ expect(stateHistory[0]).to.equal(stateHistory[1]);
+ });
+
+ it('can initialize the state via a function', () => {
+ const initState = sinon.spy(() => 1);
+
+ function Comp() {
+ useState(initState);
+ return null;
+ }
+
+ render(<Comp />, scratch);
+ render(<Comp />, scratch);
+
+ expect(initState).to.be.calledOnce;
+ });
+
+ it('does not rerender on equal state', () => {
+ let lastState;
+ let doSetState;
+
+ const Comp = sinon.spy(() => {
+ const [state, setState] = useState(0);
+ lastState = state;
+ doSetState = setState;
+ return null;
+ });
+
+ render(<Comp />, scratch);
+ expect(lastState).to.equal(0);
+ expect(Comp).to.be.calledOnce;
+
+ doSetState(0);
+ rerender();
+ expect(lastState).to.equal(0);
+ expect(Comp).to.be.calledOnce;
+
+ doSetState(() => 0);
+ rerender();
+ expect(lastState).to.equal(0);
+ expect(Comp).to.be.calledOnce;
+ });
+
+ it('rerenders when setting the state', () => {
+ let lastState;
+ let doSetState;
+
+ const Comp = sinon.spy(() => {
+ const [state, setState] = useState(0);
+ lastState = state;
+ doSetState = setState;
+ return null;
+ });
+
+ render(<Comp />, scratch);
+ expect(lastState).to.equal(0);
+ expect(Comp).to.be.calledOnce;
+
+ doSetState(1);
+ rerender();
+ expect(lastState).to.equal(1);
+ expect(Comp).to.be.calledTwice;
+
+ // Updater function style
+ doSetState(current => current * 10);
+ rerender();
+ expect(lastState).to.equal(10);
+ expect(Comp).to.be.calledThrice;
+ });
+
+ it('can be set by another component', () => {
+ function StateContainer() {
+ const [count, setCount] = useState(0);
+ return (
+ <div>
+ <p>Count: {count}</p>
+ <Increment increment={() => setCount(c => c + 10)} />
+ </div>
+ );
+ }
+
+ function Increment(props) {
+ return <button onClick={props.increment}>Increment</button>;
+ }
+
+ render(<StateContainer />, scratch);
+ expect(scratch.textContent).to.include('Count: 0');
+
+ const button = scratch.querySelector('button');
+ button.click();
+
+ rerender();
+ expect(scratch.textContent).to.include('Count: 10');
+ });
+
+ it('should correctly initialize', () => {
+ let scopedThing = 'hi';
+ let arg;
+
+ function useSomething() {
+ const args = useState(setup);
+ function setup(thing = scopedThing) {
+ arg = thing;
+ return thing;
+ }
+ return args;
+ }
+
+ const App = () => {
+ const [state] = useSomething();
+ return <p>{state}</p>;
+ };
+
+ render(<App />, scratch);
+
+ expect(arg).to.equal('hi');
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+ });
+
+ it('should correctly re-initialize when first run threw an error', () => {
+ let hasThrown = false;
+ let setup = sinon.spy(() => {
+ if (!hasThrown) {
+ hasThrown = true;
+ throw new Error('test');
+ } else {
+ return 'hi';
+ }
+ });
+
+ const App = () => {
+ const state = useState(setup)[0];
+ return <p>{state}</p>;
+ };
+
+ expect(() => render(<App />, scratch)).to.throw('test');
+ expect(setup).to.have.been.calledOnce;
+ expect(() => render(<App />, scratch)).not.to.throw();
+ expect(setup).to.have.been.calledTwice;
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+ });
+
+ it('should handle queued useState', () => {
+ function Message({ message, onClose }) {
+ const [isVisible, setVisible] = useState(Boolean(message));
+ const [prevMessage, setPrevMessage] = useState(message);
+
+ if (message !== prevMessage) {
+ setPrevMessage(message);
+ setVisible(Boolean(message));
+ }
+
+ if (!isVisible) {
+ return null;
+ }
+ return <p onClick={onClose}>{message}</p>;
+ }
+
+ function App() {
+ const [message, setMessage] = useState('Click Here!!');
+ return (
+ <Message
+ onClose={() => {
+ setMessage('');
+ }}
+ message={message}
+ />
+ );
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('Click Here!!');
+ const text = scratch.querySelector('p');
+ text.click();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+ });
+});
diff --git a/preact/jsconfig.json b/preact/jsconfig.json
new file mode 100644
index 0000000..cd6a2a5
--- /dev/null
+++ b/preact/jsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "checkJs": true,
+ "jsx": "react",
+ "lib": ["dom", "es5"],
+ "moduleResolution": "node",
+ "paths": {
+ "preact": ["."],
+ "preact/*": ["./*"]
+ },
+ "reactNamespace": "createElement",
+ "target": "es5"
+ },
+ "exclude": ["node_modules", "dist", "demo"]
+}
diff --git a/preact/jsx-runtime/LICENSE b/preact/jsx-runtime/LICENSE
new file mode 100644
index 0000000..da5389a
--- /dev/null
+++ b/preact/jsx-runtime/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-present Jason Miller
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/preact/jsx-runtime/mangle.json b/preact/jsx-runtime/mangle.json
new file mode 100644
index 0000000..506a6a4
--- /dev/null
+++ b/preact/jsx-runtime/mangle.json
@@ -0,0 +1,21 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/preact/jsx-runtime/package.json b/preact/jsx-runtime/package.json
new file mode 100644
index 0000000..3cb548c
--- /dev/null
+++ b/preact/jsx-runtime/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "jsx-runtime",
+ "amdName": "jsxRuntime",
+ "version": "1.0.0",
+ "private": true,
+ "description": "Preact JSX runtime",
+ "main": "dist/jsxRuntime.js",
+ "module": "dist/jsxRuntime.module.js",
+ "umd:main": "dist/jsxRuntime.umd.js",
+ "source": "src/index.js",
+ "types": "src/index.d.ts",
+ "license": "MIT",
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ },
+ "mangle": {
+ "regex": "^_"
+ }
+}
diff --git a/preact/jsx-runtime/src/index.d.ts b/preact/jsx-runtime/src/index.d.ts
new file mode 100644
index 0000000..64470a8
--- /dev/null
+++ b/preact/jsx-runtime/src/index.d.ts
@@ -0,0 +1,50 @@
+export { Fragment } from '../../';
+import {
+ ComponentType,
+ ComponentChild,
+ ComponentChildren,
+ VNode,
+ Attributes
+} from '../../';
+import { JSXInternal } from '../../src/jsx';
+
+export function jsx(
+ type: string,
+ props: JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any> & { children?: ComponentChild },
+ key?: string
+): VNode<any>;
+export function jsx<P>(
+ type: ComponentType<P>,
+ props: Attributes & P & { children?: ComponentChild },
+ key?: string
+): VNode<any>;
+
+export function jsxs(
+ type: string,
+ props: JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any> & { children?: ComponentChild[] },
+ key?: string
+): VNode<any>;
+export function jsxs<P>(
+ type: ComponentType<P>,
+ props: Attributes & P & { children?: ComponentChild[] },
+ key?: string
+): VNode<any>;
+
+export function jsxDEV(
+ type: string,
+ props: JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any> & { children?: ComponentChildren },
+ key?: string
+): VNode<any>;
+export function jsxDEV<P>(
+ type: ComponentType<P>,
+ props: Attributes & P & { children?: ComponentChildren },
+ key?: string
+): VNode<any>;
+
+export { JSXInternal as JSX };
diff --git a/preact/jsx-runtime/src/index.js b/preact/jsx-runtime/src/index.js
new file mode 100644
index 0000000..82c7b33
--- /dev/null
+++ b/preact/jsx-runtime/src/index.js
@@ -0,0 +1,77 @@
+import { options, Fragment } from 'preact';
+
+/** @typedef {import('preact').VNode} VNode */
+
+let vnodeId = 0;
+
+/**
+ * @fileoverview
+ * This file exports various methods that implement Babel's "automatic" JSX runtime API:
+ * - jsx(type, props, key)
+ * - jsxs(type, props, key)
+ * - jsxDEV(type, props, key, __source, __self)
+ *
+ * The implementation of createVNode here is optimized for performance.
+ * Benchmarks: https://esbench.com/bench/5f6b54a0b4632100a7dcd2b3
+ */
+
+/**
+ * JSX.Element factory used by Babel's {runtime:"automatic"} JSX transform
+ * @param {VNode['type']} type
+ * @param {VNode['props']} props
+ * @param {VNode['key']} [key]
+ * @param {string} [__source]
+ * @param {string} [__self]
+ */
+function createVNode(type, props, key, __source, __self) {
+ // We'll want to preserve `ref` in props to get rid of the need for
+ // forwardRef components in the future, but that should happen via
+ // a separate PR.
+ let normalizedProps = {},
+ ref,
+ i;
+ for (i in props) {
+ if (i == 'ref') {
+ ref = props[i];
+ } else {
+ normalizedProps[i] = props[i];
+ }
+ }
+
+ const vnode = {
+ type,
+ props: normalizedProps,
+ key,
+ ref,
+ _children: null,
+ _parent: null,
+ _depth: 0,
+ _dom: null,
+ _nextDom: undefined,
+ _component: null,
+ _hydrating: null,
+ constructor: undefined,
+ _original: --vnodeId,
+ __source,
+ __self
+ };
+
+ // If a Component VNode, check for and apply defaultProps.
+ // Note: `type` is often a String, and can be `undefined` in development.
+ if (typeof type === 'function' && (ref = type.defaultProps)) {
+ for (i in ref)
+ if (typeof normalizedProps[i] === 'undefined') {
+ normalizedProps[i] = ref[i];
+ }
+ }
+
+ if (options.vnode) options.vnode(vnode);
+ return vnode;
+}
+
+export {
+ createVNode as jsx,
+ createVNode as jsxs,
+ createVNode as jsxDEV,
+ Fragment
+};
diff --git a/preact/jsx-runtime/test/browser/jsx-runtime.test.js b/preact/jsx-runtime/test/browser/jsx-runtime.test.js
new file mode 100644
index 0000000..e293881
--- /dev/null
+++ b/preact/jsx-runtime/test/browser/jsx-runtime.test.js
@@ -0,0 +1,94 @@
+import { Component, createElement, createRef } from 'preact';
+import { jsx, jsxs, jsxDEV, Fragment } from 'preact/jsx-runtime';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+describe('Babel jsx/jsxDEV', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should have needed exports', () => {
+ expect(typeof jsx).to.equal('function');
+ expect(typeof jsxs).to.equal('function');
+ expect(typeof jsxDEV).to.equal('function');
+ expect(typeof Fragment).to.equal('function');
+ });
+
+ it('should keep ref in props', () => {
+ const ref = () => null;
+ const vnode = jsx('div', { ref });
+ expect(vnode.ref).to.equal(ref);
+ });
+
+ it('should add keys', () => {
+ const vnode = jsx('div', null, 'foo');
+ expect(vnode.key).to.equal('foo');
+ });
+
+ it('should apply defaultProps', () => {
+ class Foo extends Component {
+ render() {
+ return <div />;
+ }
+ }
+
+ Foo.defaultProps = {
+ foo: 'bar'
+ };
+
+ const vnode = jsx(Foo, {}, null);
+ expect(vnode.props).to.deep.equal({
+ foo: 'bar'
+ });
+ });
+
+ it('should keep props over defaultProps', () => {
+ class Foo extends Component {
+ render() {
+ return <div />;
+ }
+ }
+
+ Foo.defaultProps = {
+ foo: 'bar'
+ };
+
+ const vnode = jsx(Foo, { foo: 'baz' }, null);
+ expect(vnode.props).to.deep.equal({
+ foo: 'baz'
+ });
+ });
+
+ it('should set __source and __self', () => {
+ const vnode = jsx('div', { class: 'foo' }, 'key', 'source', 'self');
+ expect(vnode.__source).to.equal('source');
+ expect(vnode.__self).to.equal('self');
+ });
+
+ it('should return a vnode like createElement', () => {
+ const elementVNode = createElement('div', {
+ class: 'foo',
+ key: 'key'
+ });
+ const jsxVNode = jsx('div', { class: 'foo' }, 'key');
+ delete jsxVNode.__self;
+ delete jsxVNode.__source;
+ delete jsxVNode._original;
+ delete elementVNode._original;
+ expect(jsxVNode).to.deep.equal(elementVNode);
+ });
+
+ // #2839
+ it('should remove ref from props', () => {
+ const ref = createRef();
+ const vnode = jsx('div', { ref }, null);
+ expect(vnode.props).to.deep.equal({});
+ expect(vnode.ref).to.equal(ref);
+ });
+});
diff --git a/preact/karma.conf.js b/preact/karma.conf.js
new file mode 100644
index 0000000..187192a
--- /dev/null
+++ b/preact/karma.conf.js
@@ -0,0 +1,338 @@
+/*eslint no-var:0, object-shorthand:0 */
+
+var coverage = String(process.env.COVERAGE) === 'true',
+ minify = String(process.env.MINIFY) === 'true',
+ ci = String(process.env.CI).match(/^(1|true)$/gi),
+ sauceLabs = ci && String(process.env.RUN_SAUCE_LABS) === 'true',
+ performance = !coverage && String(process.env.PERFORMANCE) !== 'false',
+ path = require('path'),
+ errorstacks = require('errorstacks'),
+ kl = require('kolorist');
+
+const babel = require('@babel/core');
+const fs = require('fs').promises;
+
+// This strips Karma's annoying `LOG: '...'` string from logs
+const orgStdoutWrite = process.stdout.write;
+process.stdout.write = msg => {
+ let out = '';
+ const match = msg.match(
+ /(^|.*\s)(LOG|WARN|ERROR):\s'__LOG_CUSTOM:([\S\s]*)'/
+ );
+ if (match && match.length >= 4) {
+ // Sometimes the UA of the browser will be included in the message
+ if (match[1].length) {
+ out += kl.yellow(kl.italic(match[1]));
+ out += match[3]
+ .split('\n')
+ .map(line => ' ' + line)
+ .join('\n');
+ } else {
+ out += match[3];
+ }
+ out += '\n';
+ } else if (/(^|.*\s)(LOG|WARN|ERROR):\s([\S\s]*)/.test(msg)) {
+ // Nothing
+ } else {
+ out = msg;
+ }
+
+ return orgStdoutWrite.call(process.stdout, out);
+};
+
+var sauceLabsLaunchers = {
+ sl_chrome: {
+ base: 'SauceLabs',
+ browserName: 'chrome',
+ platform: 'Windows 10'
+ },
+ sl_firefox: {
+ base: 'SauceLabs',
+ browserName: 'firefox',
+ platform: 'Windows 10'
+ },
+ // TODO: Safari always fails and disconnects before any tests are executed.
+ // This seems to be an issue with Saucelabs and they're actively investigating
+ // that (see: https://mobile.twitter.com/bromann/status/1136323458328084482).
+ // We'll disable Safari for now until that's resolved.
+ // sl_safari: {
+ // base: 'SauceLabs',
+ // browserName: 'Safari',
+ // version: '11',
+ // platform: 'OS X 10.13'
+ // },
+ sl_edge: {
+ base: 'SauceLabs',
+ browserName: 'MicrosoftEdge',
+ platform: 'Windows 10'
+ },
+ sl_ie_11: {
+ base: 'SauceLabs',
+ browserName: 'internet explorer',
+ version: '11.0',
+ platform: 'Windows 7'
+ }
+};
+
+var localLaunchers = {
+ ChromeNoSandboxHeadless: {
+ base: 'Chrome',
+ flags: [
+ '--no-sandbox',
+ '--disable-setuid-sandbox',
+ // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
+ '--headless',
+ '--disable-gpu',
+ '--no-gpu',
+ // Without a remote debugging port, Google Chrome exits immediately.
+ '--remote-debugging-port=9333'
+ ]
+ }
+};
+
+const subPkgPath = pkgName => {
+ if (!minify) {
+ return path.join(__dirname, pkgName, 'src', 'index.js');
+ }
+
+ // Resolve from package.exports field
+ const stripped = pkgName.replace(/[/\\./]/g, '');
+ const pkgJson = path.join(__dirname, 'package.json');
+ const pkgExports = require(pkgJson).exports;
+ const file = pkgExports[stripped ? `./${stripped}` : '.'].browser;
+ return path.join(__dirname, file);
+};
+
+// Esbuild plugin for aliasing + babel pass
+function createEsbuildPlugin() {
+ const pending = new Map();
+ const cache = new Map();
+
+ const rename = {};
+ const mangle = require('./mangle.json');
+ for (let prop in mangle.props.props) {
+ let name = prop;
+ if (name[0] === '$') {
+ name = name.slice(1);
+ }
+
+ rename[name] = mangle.props.props[prop];
+ }
+
+ const alias = {
+ 'preact/debug': subPkgPath('./debug/'),
+ 'preact/devtools': subPkgPath('./devtools/'),
+ 'preact/compat': subPkgPath('./compat/'),
+ 'preact/hooks': subPkgPath('./hooks/'),
+ 'preact/test-utils': subPkgPath('./test-utils/'),
+ 'preact/jsx-runtime': subPkgPath('./jsx-runtime/'),
+ 'preact/jsx-dev-runtime': subPkgPath('./jsx-runtime/'),
+ preact: subPkgPath('')
+ };
+ return {
+ name: 'custom',
+ setup(build) {
+ // Aliasing: If "MINIFY" is set to "true" we use the dist/
+ // files instead of those from src/
+ build.onResolve({ filter: /^preact.*/ }, args => {
+ const pkg = alias[args.path];
+ return {
+ path: pkg,
+ namespace: 'preact'
+ };
+ });
+
+ build.onResolve({ filter: /^(react|react-dom)$/ }, args => {
+ const pkg = alias['preact/compat'];
+ return {
+ path: pkg,
+ namespace: 'preact'
+ };
+ });
+
+ // Transpile node_modules that are es2015+ to es5 for IE11
+ build.onLoad({ filter: /kolorist/ }, async args => {
+ const contents = await fs.readFile(args.path, 'utf-8');
+
+ const tmp = await babel.transformAsync(contents, {
+ filename: args.path,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ loose: true,
+ modules: false,
+ targets: {
+ browsers: ['last 2 versions', 'IE >= 9']
+ }
+ }
+ ]
+ ]
+ });
+
+ return {
+ contents: tmp.code,
+ resolveDir: path.dirname(args.path),
+ loader: 'js'
+ };
+ });
+
+ // Apply babel pass whenever we load a .js file
+ build.onLoad({ filter: /\.js$/ }, async args => {
+ const contents = await fs.readFile(args.path, 'utf-8');
+
+ // Using a cache is crucial as babel is 30x slower than esbuild
+ const cached = cache.get(args.path);
+ if (cached && cached.input === contents) {
+ return {
+ contents: cached.result,
+ resolveDir: path.dirname(args.path),
+ loader: 'js'
+ };
+ }
+
+ let result = contents;
+
+ // Check if somebody already requested the current file. If they
+ // did than we push a listener instead of doing a duplicate
+ // transform of the same file. This is crucial for build perf.
+ if (!pending.has(args.path)) {
+ pending.set(args.path, []);
+
+ const tmp = await babel.transformAsync(result, {
+ filename: args.path,
+ sourceMaps: 'inline',
+ plugins: [
+ coverage && [
+ 'istanbul',
+ {
+ include: minify ? '**/dist/**/*.js' : '**/src/**/*.js'
+ }
+ ]
+ ].filter(Boolean)
+ });
+ result = tmp.code || result;
+ cache.set(args.path, { input: contents, result });
+
+ // Fire all pending listeners that are waiting on the same
+ // file transformation
+ const waited = pending.get(args.path);
+ pending.delete(args.path);
+ waited.forEach(fn => fn());
+ } else {
+ // Subscribe to the existing transformation completion call
+ await new Promise(r => {
+ pending.get(args.path).push(r);
+ });
+ result = cache.get(args.path).result;
+ }
+
+ return {
+ contents: result,
+ resolveDir: path.dirname(args.path),
+ loader: 'js'
+ };
+ });
+ }
+ };
+}
+
+module.exports = function(config) {
+ config.set({
+ browsers: sauceLabs
+ ? Object.keys(sauceLabsLaunchers)
+ : Object.keys(localLaunchers),
+
+ frameworks: ['mocha', 'chai-sinon'],
+
+ reporters: ['mocha'].concat(
+ coverage ? 'coverage' : [],
+ sauceLabs ? 'saucelabs' : []
+ ),
+
+ formatError(msg) {
+ const frames = errorstacks.parseStackTrace(msg);
+ if (!frames.length || frames[0].column === -1) return '\n' + msg + '\n';
+
+ const frame = frames[0];
+ const filePath = kl.lightCyan(
+ frame.fileName.replace(__dirname + '/', '')
+ );
+
+ const indentMatch = msg.match(/^(\s*)/);
+ const indent = indentMatch ? indentMatch[1] : ' ';
+ const location = kl.yellow(`:${frame.line}:${frame.column}`);
+ return `${indent}at ${frame.name} (${filePath}${location})\n`;
+ },
+
+ coverageReporter: {
+ dir: path.join(__dirname, 'coverage'),
+ reporters: [
+ { type: 'text-summary' },
+ { type: 'html' },
+ { type: 'lcovonly', subdir: '.', file: 'lcov.info' }
+ ]
+ },
+
+ mochaReporter: {
+ showDiff: true
+ },
+
+ browserLogOptions: { terminal: true },
+ browserConsoleLogOptions: { terminal: true },
+
+ browserNoActivityTimeout: 5 * 60 * 1000,
+
+ // Use only two browsers concurrently, works better with open source Sauce Labs remote testing
+ concurrency: 2,
+
+ captureTimeout: 0,
+
+ sauceLabs: {
+ build: `CI #${process.env.GITHUB_RUN_NUMBER} (${process.env.GITHUB_RUN_ID})`,
+ tunnelIdentifier:
+ process.env.GITHUB_RUN_NUMBER ||
+ `local${require('./package.json').version}`,
+ connectLocationForSERelay: 'localhost',
+ connectPortForSERelay: 4445,
+ startConnect: !!sauceLabs
+ },
+
+ customLaunchers: sauceLabs ? sauceLabsLaunchers : localLaunchers,
+
+ files: [
+ { pattern: 'test/polyfills.js', watched: false },
+ {
+ pattern:
+ config.grep ||
+ '{debug,devtools,hooks,compat,test-utils,jsx-runtime,}/test/{browser,shared}/**/*.test.js',
+ watched: false,
+ type: 'js'
+ }
+ ],
+
+ mime: {
+ 'text/javascript': ['js', 'jsx']
+ },
+
+ preprocessors: {
+ '{debug,devtools,hooks,compat,test-utils,jsx-runtime,}/test/**/*': [
+ 'esbuild'
+ ]
+ },
+
+ esbuild: {
+ // karma-esbuild options
+ singleBundle: false,
+
+ // esbuild options
+ target: 'es5',
+ define: {
+ COVERAGE: coverage,
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || ''),
+ ENABLE_PERFORMANCE: performance
+ },
+ plugins: [createEsbuildPlugin()]
+ }
+ });
+};
diff --git a/preact/mangle.json b/preact/mangle.json
new file mode 100644
index 0000000..fc87f43
--- /dev/null
+++ b/preact/mangle.json
@@ -0,0 +1,80 @@
+{
+ "help": {
+ "what is this file?": "It controls protected/private property mangling so that minified builds have consistent property names.",
+ "why are there duplicate minified properties?": "Most properties are only used on one type of objects, so they can have the same name since they will never collide. Doing this reduces size."
+ },
+ "minify": {
+ "mangle": {
+ "properties": {
+ "regex": "^_[^_]",
+ "reserved": [
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
+ "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+ "__PREACT_DEVTOOLS__",
+ "_renderers",
+ "__source",
+ "__self"
+ ]
+ }
+ },
+ "compress": {
+ "hoist_vars": true,
+ "reduce_funcs": false
+ }
+ },
+ "props": {
+ "cname": 6,
+ "props": {
+ "$_cleanup": "__c",
+ "$_afterPaintQueued": "__a",
+ "$__hooks": "__H",
+ "$_list": "__",
+ "$_pendingEffects": "__h",
+ "$_value": "__",
+ "$_original": "__v",
+ "$_args": "__H",
+ "$_factory": "__h",
+ "$_depth": "__b",
+ "$_nextDom": "__d",
+ "$_dirty": "__d",
+ "$_detachOnNextRender": "__b",
+ "$_force": "__e",
+ "$_nextState": "__s",
+ "$_renderCallbacks": "__h",
+ "$_vnode": "__v",
+ "$_children": "__k",
+ "$_pendingSuspensionCount": "__u",
+ "$_childDidSuspend": "__c",
+ "$_onResolve": "__R",
+ "$_suspended": "__e",
+ "$_dom": "__e",
+ "$_hydrating": "__h",
+ "$_component": "__c",
+ "$__html": "__html",
+ "$_parent": "__",
+ "$_pendingError": "__E",
+ "$_processingException": "__",
+ "$_globalContext": "__n",
+ "$_context": "c",
+ "$_defaultValue": "__",
+ "$_id": "__c",
+ "$_contextRef": "__",
+ "$_parentDom": "__P",
+ "$_originalParentDom": "__O",
+ "$_prevState": "__u",
+ "$_root": "__",
+ "$_diff": "__b",
+ "$_commit": "__c",
+ "$_addHookName": "__a",
+ "$_render": "__r",
+ "$_hook": "__h",
+ "$_catchError": "__e",
+ "$_unmount": "__u",
+ "$_owner": "__o",
+ "$_skipEffects": "__s",
+ "$_rerenderCount": "__r",
+ "$_forwarded": "__f",
+ "$_isSuspended": "__i"
+ }
+ }
+}
diff --git a/preact/package-lock.json b/preact/package-lock.json
new file mode 100644
index 0000000..83f011f
--- /dev/null
+++ b/preact/package-lock.json
@@ -0,0 +1,32470 @@
+{
+ "name": "preact",
+ "version": "10.5.14",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "version": "10.5.14",
+ "license": "MIT",
+ "devDependencies": {
+ "@babel/core": "^7.7.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.6.2",
+ "@babel/plugin-transform-react-jsx": "^7.7.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.7.4",
+ "@babel/preset-env": "^7.7.1",
+ "@babel/register": "^7.7.0",
+ "@types/chai": "^4.1.2",
+ "@types/mocha": "^5.0.0",
+ "@types/node": "^14.14.10",
+ "babel-plugin-istanbul": "^6.0.0",
+ "babel-plugin-transform-async-to-promises": "^0.8.15",
+ "babel-plugin-transform-rename-properties": "0.1.0",
+ "benchmark": "^2.1.4",
+ "chai": "^4.1.2",
+ "check-export-map": "^1.0.1",
+ "coveralls": "^3.0.0",
+ "cross-env": "^7.0.2",
+ "csstype": "^3.0.5",
+ "diff": "^5.0.0",
+ "errorstacks": "^2.3.0",
+ "esbuild": "^0.8.47",
+ "eslint": "5.15.1",
+ "eslint-config-developit": "^1.1.1",
+ "eslint-config-prettier": "^6.5.0",
+ "eslint-plugin-react": "7.12.4",
+ "husky": "^4.3.0",
+ "karma": "^5.2.3",
+ "karma-chai-sinon": "^0.1.5",
+ "karma-chrome-launcher": "^3.1.0",
+ "karma-coverage": "^2.0.3",
+ "karma-esbuild": "^2.2.0",
+ "karma-mocha": "^2.0.1",
+ "karma-mocha-reporter": "^2.2.5",
+ "karma-sauce-launcher": "^4.3.4",
+ "karma-sinon": "^1.0.5",
+ "karma-sourcemap-loader": "^0.3.7",
+ "kolorist": "^1.2.10",
+ "lint-staged": "^10.5.2",
+ "lodash": "^4.17.20",
+ "microbundle": "^0.11.0",
+ "mocha": "^8.2.1",
+ "npm-merge-driver-install": "^1.1.1",
+ "npm-run-all": "^4.0.0",
+ "prettier": "^1.18.2",
+ "prop-types": "^15.7.2",
+ "sinon": "^9.2.3",
+ "sinon-chai": "^3.5.0",
+ "typescript": "3.5.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.4.tgz",
+ "integrity": "sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.7.4",
+ "@babel/helpers": "^7.7.4",
+ "@babel/parser": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz",
+ "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz",
+ "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz",
+ "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-explode-assignable-expression": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-builder-react-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.4.tgz",
+ "integrity": "sha512-kvbfHJNN9dg4rkEM4xn1s8d1/h6TYNvajy9L1wx4qLn9HFg0IkTsQi4rfBe92nxrPUFcMsHoMV+8rU7MJb3fCA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4",
+ "esutils": "^2.0.0"
+ }
+ },
+ "node_modules/@babel/helper-call-delegate": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz",
+ "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-hoist-variables": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz",
+ "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/generator": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
+ "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.5",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-function-name": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+ "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-get-function-arity": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-get-function-arity": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+ "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz",
+ "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz",
+ "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-replace-supers": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz",
+ "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/traverse": "^7.12.5",
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+ "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.11.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/parser": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
+ "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/template": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
+ "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/parser": "^7.12.7",
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/traverse": {
+ "version": "7.12.9",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
+ "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/generator": "^7.12.5",
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-split-export-declaration": "^7.11.0",
+ "@babel/parser": "^7.12.7",
+ "@babel/types": "^7.12.7",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.19"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/types": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
+ "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz",
+ "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-regex": "^7.4.4",
+ "regexpu-core": "^4.6.0"
+ }
+ },
+ "node_modules/@babel/helper-define-map": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz",
+ "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/@babel/helper-explode-assignable-expression": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz",
+ "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz",
+ "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-get-function-arity": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-get-function-arity": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz",
+ "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz",
+ "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz",
+ "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz",
+ "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz",
+ "integrity": "sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-simple-access": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz",
+ "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+ "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
+ "dev": true
+ },
+ "node_modules/@babel/helper-regex": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz",
+ "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz",
+ "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-wrap-function": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz",
+ "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.7.4",
+ "@babel/helper-optimise-call-expression": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz",
+ "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz",
+ "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "dev": true
+ },
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz",
+ "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz",
+ "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
+ "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-async-generator-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz",
+ "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.7.4",
+ "@babel/plugin-syntax-async-generators": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-class-properties": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.2.1.tgz",
+ "integrity": "sha512-/4FKFChkQ2Jgb8lBDsvFX496YTi7UWTetVgS8oJUpX1e/DlaoeEK57At27ug8Hu2zI2g8bzkJ+8k9qrHZRPGPA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.2.1",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-dynamic-import": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz",
+ "integrity": "sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-json-strings": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz",
+ "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-json-strings": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-object-rest-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz",
+ "integrity": "sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-object-rest-spread": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-optional-catch-binding": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz",
+ "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-unicode-property-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz",
+ "integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-async-generators": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz",
+ "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-dynamic-import": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz",
+ "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-json-strings": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz",
+ "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz",
+ "integrity": "sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz",
+ "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz",
+ "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-top-level-await": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz",
+ "integrity": "sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz",
+ "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz",
+ "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz",
+ "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz",
+ "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz",
+ "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-define-map": "^7.7.4",
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-optimise-call-expression": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "globals": "^11.1.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz",
+ "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz",
+ "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dotall-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz",
+ "integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-keys": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz",
+ "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz",
+ "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz",
+ "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz",
+ "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz",
+ "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-member-expression-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz",
+ "integrity": "sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-amd": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz",
+ "integrity": "sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz",
+ "integrity": "sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-simple-access": "^7.7.4",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-systemjs": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz",
+ "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-hoist-variables": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-umd": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz",
+ "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz",
+ "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-transform-new-target": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz",
+ "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-super": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz",
+ "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz",
+ "integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-call-delegate": "^7.7.4",
+ "@babel/helper-get-function-arity": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-property-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz",
+ "integrity": "sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.4.tgz",
+ "integrity": "sha512-LixU4BS95ZTEAZdPaIuyg/k8FiiqN9laQ0dMHB4MlpydHY53uQdWCUrwjLr5o6ilS6fAgZey4Q14XBjl5tL6xw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-builder-react-jsx": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-jsx": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.7.4.tgz",
+ "integrity": "sha512-5ZU9FnPhqtHsOXxutRtXZAzoEJwDaP32QcobbMP1/qt7NYcsCNK8XgzJcJfoEr/ZnzVvUNInNjIW22Z6I8p9mg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-jsx": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz",
+ "integrity": "sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-transform": "^0.14.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-reserved-words": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz",
+ "integrity": "sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz",
+ "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz",
+ "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz",
+ "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz",
+ "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typeof-symbol": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz",
+ "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz",
+ "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/polyfill": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
+ "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==",
+ "dev": true,
+ "dependencies": {
+ "core-js": "^2.6.5",
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "node_modules/@babel/polyfill/node_modules/regenerator-runtime": {
+ "version": "0.13.7",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
+ "dev": true
+ },
+ "node_modules/@babel/preset-env": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.4.tgz",
+ "integrity": "sha512-Dg+ciGJjwvC1NIe/DGblMbcGq1HOtKbw8RLl4nIjlfcILKEOkWT/vRqPpumswABEBVudii6dnVwrBtzD7ibm4g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.7.4",
+ "@babel/plugin-proposal-dynamic-import": "^7.7.4",
+ "@babel/plugin-proposal-json-strings": "^7.7.4",
+ "@babel/plugin-proposal-object-rest-spread": "^7.7.4",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.7.4",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.7.4",
+ "@babel/plugin-syntax-async-generators": "^7.7.4",
+ "@babel/plugin-syntax-dynamic-import": "^7.7.4",
+ "@babel/plugin-syntax-json-strings": "^7.7.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.7.4",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.7.4",
+ "@babel/plugin-syntax-top-level-await": "^7.7.4",
+ "@babel/plugin-transform-arrow-functions": "^7.7.4",
+ "@babel/plugin-transform-async-to-generator": "^7.7.4",
+ "@babel/plugin-transform-block-scoped-functions": "^7.7.4",
+ "@babel/plugin-transform-block-scoping": "^7.7.4",
+ "@babel/plugin-transform-classes": "^7.7.4",
+ "@babel/plugin-transform-computed-properties": "^7.7.4",
+ "@babel/plugin-transform-destructuring": "^7.7.4",
+ "@babel/plugin-transform-dotall-regex": "^7.7.4",
+ "@babel/plugin-transform-duplicate-keys": "^7.7.4",
+ "@babel/plugin-transform-exponentiation-operator": "^7.7.4",
+ "@babel/plugin-transform-for-of": "^7.7.4",
+ "@babel/plugin-transform-function-name": "^7.7.4",
+ "@babel/plugin-transform-literals": "^7.7.4",
+ "@babel/plugin-transform-member-expression-literals": "^7.7.4",
+ "@babel/plugin-transform-modules-amd": "^7.7.4",
+ "@babel/plugin-transform-modules-commonjs": "^7.7.4",
+ "@babel/plugin-transform-modules-systemjs": "^7.7.4",
+ "@babel/plugin-transform-modules-umd": "^7.7.4",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4",
+ "@babel/plugin-transform-new-target": "^7.7.4",
+ "@babel/plugin-transform-object-super": "^7.7.4",
+ "@babel/plugin-transform-parameters": "^7.7.4",
+ "@babel/plugin-transform-property-literals": "^7.7.4",
+ "@babel/plugin-transform-regenerator": "^7.7.4",
+ "@babel/plugin-transform-reserved-words": "^7.7.4",
+ "@babel/plugin-transform-shorthand-properties": "^7.7.4",
+ "@babel/plugin-transform-spread": "^7.7.4",
+ "@babel/plugin-transform-sticky-regex": "^7.7.4",
+ "@babel/plugin-transform-template-literals": "^7.7.4",
+ "@babel/plugin-transform-typeof-symbol": "^7.7.4",
+ "@babel/plugin-transform-unicode-regex": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "browserslist": "^4.6.0",
+ "core-js-compat": "^3.1.1",
+ "invariant": "^2.2.2",
+ "js-levenshtein": "^1.1.3",
+ "semver": "^5.5.0"
+ }
+ },
+ "node_modules/@babel/register": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.7.4.tgz",
+ "integrity": "sha512-/fmONZqL6ZMl9KJUYajetCrID6m0xmL4odX7v+Xvoxcv0DdbP/oO0TWIeLUCHqczQ6L6njDMqmqHFy2cp3FFsA==",
+ "dev": true,
+ "dependencies": {
+ "find-cache-dir": "^2.0.0",
+ "lodash": "^4.17.13",
+ "make-dir": "^2.1.0",
+ "pirates": "^4.0.0",
+ "source-map-support": "^0.5.16"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz",
+ "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-runtime": "^0.13.2"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz",
+ "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz",
+ "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.7.4",
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz",
+ "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz",
+ "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
+ "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
+ "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
+ "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^1.7.0"
+ }
+ },
+ "node_modules/@sinonjs/samsam": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.0.tgz",
+ "integrity": "sha512-hXpcfx3aq+ETVBwPlRFICld5EnrkexXuXDwqUNhDdr5L8VjvMeSRwyOa0qL7XFmR+jVWR4rUZtnxlG7RX72sBg==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^1.6.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/text-encoding": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
+ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
+ "dev": true
+ },
+ "node_modules/@szmarczak/http-timer": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
+ "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
+ "dev": true,
+ "dependencies": {
+ "defer-to-connect": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@types/archiver": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.1.0.tgz",
+ "integrity": "sha512-baFOhanb/hxmcOd1Uey2TfFg43kTSmM6py1Eo7Rjbv/ivcl7PXLhY0QgXGf50Hx/eskGCFqPfhs/7IZLb15C5g==",
+ "dev": true,
+ "dependencies": {
+ "@types/glob": "*"
+ }
+ },
+ "node_modules/@types/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@types/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-8GAYQ1jDRUQkSpHzJUqXwAkYFOxuWAOGLhIR4aPd/Y/yL12Q/9m7LsKpHKlfKdNE/362Hc9wPI1Yh6opDfxVJg==",
+ "dev": true
+ },
+ "node_modules/@types/cacheable-request": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
+ "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/http-cache-semantics": "*",
+ "@types/keyv": "*",
+ "@types/node": "*",
+ "@types/responselike": "*"
+ }
+ },
+ "node_modules/@types/chai": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.5.tgz",
+ "integrity": "sha512-YvbLiIc0DbbhiANrfVObdkLEHJksQZVq0Uvfg550SRAKVYaEJy+V70j65BVe2WNp6E3HtKsUczeijHFCjba3og==",
+ "dev": true
+ },
+ "node_modules/@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
+ "node_modules/@types/fs-extra": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.4.tgz",
+ "integrity": "sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/http-cache-semantics": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
+ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==",
+ "dev": true
+ },
+ "node_modules/@types/keyv": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
+ "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.14.165",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz",
+ "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==",
+ "dev": true
+ },
+ "node_modules/@types/lodash.clonedeep": {
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz",
+ "integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==",
+ "dev": true,
+ "dependencies": {
+ "@types/lodash": "*"
+ }
+ },
+ "node_modules/@types/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-8G41YFhmOl8Ck6NrwLK5hhnbz6ADfuDJP+zusDnX3PoYhfC60+H/rQE6zmdO4yFzPCPJPY4oGZK2spbXm6gYEA==",
+ "dev": true,
+ "dependencies": {
+ "@types/lodash": "*"
+ }
+ },
+ "node_modules/@types/lodash.merge": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.6.tgz",
+ "integrity": "sha512-IB90krzMf7YpfgP3u/EvZEdXVvm4e3gJbUvh5ieuI+o+XqiNEt6fCzqNRaiLlPVScLI59RxIGZMQ3+Ko/DJ8vQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/lodash": "*"
+ }
+ },
+ "node_modules/@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+ "dev": true
+ },
+ "node_modules/@types/mocha": {
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
+ "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "14.14.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
+ "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==",
+ "dev": true
+ },
+ "node_modules/@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "node_modules/@types/puppeteer": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.0.tgz",
+ "integrity": "sha512-zTYDLjnHjgzokrwKt7N0rgn7oZPYo1J0m8Ghu+gXqzLCEn8RWbELa2uprE2UFJ0jU/Sk0x9jXXdOH/5QQLFHhQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/puppeteer-core": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/puppeteer-core/-/puppeteer-core-2.0.0.tgz",
+ "integrity": "sha512-JvoEb7KgEkUet009ZDrtpUER3hheXoHgQByuYpJZ5WWT7LWwMH+0NTqGQXGgoOKzs+G5NA1T4DZwXK79Bhnejw==",
+ "dev": true,
+ "dependencies": {
+ "@types/puppeteer": "*"
+ }
+ },
+ "node_modules/@types/q": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+ "dev": true
+ },
+ "node_modules/@types/resolve": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
+ "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/responselike": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
+ "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/ua-parser-js": {
+ "version": "0.7.33",
+ "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
+ "integrity": "sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==",
+ "dev": true
+ },
+ "node_modules/@types/uuid": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz",
+ "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==",
+ "dev": true
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
+ "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@ungap/promise-all-settled": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "dev": true
+ },
+ "node_modules/@wdio/config": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.10.4.tgz",
+ "integrity": "sha512-M22EunI+n/mmYOQqb9+BTVRqrfmPw+7rR1AHeD36vOXCnZ55Nrl4ZU4d6QzPHp9cLdMZqV786iDmkonnb6jb8w==",
+ "dev": true,
+ "dependencies": {
+ "@wdio/logger": "6.10.4",
+ "deepmerge": "^4.0.0",
+ "glob": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@wdio/logger": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.10.4.tgz",
+ "integrity": "sha512-I+1I/5CtQigy59QJen56PHuwV0yiQdnZaOxmXIP6FzpWkeXLjcoUNaCRDuKwJx5GKrUSDqmGlMWSH53scwwzHg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "loglevel": "^1.6.0",
+ "loglevel-plugin-prefix": "^0.8.4",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@wdio/logger/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wdio/logger/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@wdio/protocols": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-6.10.0.tgz",
+ "integrity": "sha512-MaloMFtlZeeGoqHyy2g5QM8HHuQDZOAGjxotsQ6mVAzZpAFbwUGHPSRlwBbbsB3gHVALJVowViltJ95jgaFfZg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@wdio/repl": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-6.10.4.tgz",
+ "integrity": "sha512-VwucPyUqAxU6CWWoEVf14asjtLGTgyaJwp47kEFegr06ZBG43zVQ6JqKFiGDxUJ+fZVRhdd7nRVHd+6UllK18w==",
+ "dev": true,
+ "dependencies": {
+ "@wdio/utils": "6.10.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@wdio/utils": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-6.10.4.tgz",
+ "integrity": "sha512-DkFguYGKUcv9TmIYuuwS/pxpiGcgyv8gWUWRXffirt2OYpFXJNwB+S96CSQnjgb4B5MqSFgEti+gl8A2wsdDgQ==",
+ "dev": true,
+ "dependencies": {
+ "@wdio/logger": "6.10.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
+ "dependencies": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-dynamic-import": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
+ "dev": true
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
+ "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==",
+ "dev": true
+ },
+ "node_modules/after": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+ "dev": true
+ },
+ "node_modules/agent-base": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "node_modules/alphanum-sort": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
+ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
+ "dev": true
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "node_modules/arch": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
+ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
+ "dev": true
+ },
+ "node_modules/archive-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz",
+ "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=",
+ "dev": true,
+ "dependencies": {
+ "file-type": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/archive-type/node_modules/file-type": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
+ "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/archiver": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.1.0.tgz",
+ "integrity": "sha512-iKuQUP1nuKzBC2PFlGet5twENzCfyODmvkxwDV0cEFXavwcLrIW5ssTuHi9dyTPvpWr6Faweo2eQaQiLIwyXTA==",
+ "dev": true,
+ "dependencies": {
+ "archiver-utils": "^2.1.0",
+ "async": "^3.2.0",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.0.0",
+ "tar-stream": "^2.1.4",
+ "zip-stream": "^4.0.4"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.difference": "^4.5.0",
+ "lodash.flatten": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.union": "^4.6.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/archiver/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dev": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
+ "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.7.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arraybuffer.slice": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
+ "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
+ "dev": true
+ },
+ "node_modules/asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+ "dev": true
+ },
+ "node_modules/async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "node_modules/asyncro": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/asyncro/-/asyncro-3.0.0.tgz",
+ "integrity": "sha512-nEnWYfrBmA3taTiuiOoZYmgJ/CNrSoQLeLs29SeLcPu60yaw/mHDBHV0iOZ051fTvsTHxpCY+gXibqT9wbQYfg==",
+ "dev": true
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true,
+ "bin": {
+ "atob": "bin/atob.js"
+ },
+ "engines": {
+ "node": ">= 4.5.0"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "9.8.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
+ "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.12.0",
+ "caniuse-lite": "^1.0.30001109",
+ "colorette": "^1.2.1",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.32",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ }
+ },
+ "node_modules/autoprefixer/node_modules/browserslist": {
+ "version": "4.14.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz",
+ "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==",
+ "dev": true,
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001157",
+ "colorette": "^1.2.1",
+ "electron-to-chromium": "^1.3.591",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.66"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/autoprefixer/node_modules/caniuse-lite": {
+ "version": "1.0.30001163",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001163.tgz",
+ "integrity": "sha512-QQbOGkHWnvhn3Dlf4scPlXTZVhGOK+2qCOP5gPxqzXHhtn3tZHwNdH9qNcQRWN0f3tDYrsyXFJCFiP/GLzI5Vg==",
+ "dev": true
+ },
+ "node_modules/autoprefixer/node_modules/electron-to-chromium": {
+ "version": "1.3.611",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.611.tgz",
+ "integrity": "sha512-YhqTzCXtEO2h0foGLGS60ortd6yY/yUQhqDEp1VWG3DIyHvckFFyaRwR41M0/M3m7Yb8Exqh+nzyb2TuxaoMTw==",
+ "dev": true
+ },
+ "node_modules/autoprefixer/node_modules/node-releases": {
+ "version": "1.1.67",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
+ "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==",
+ "dev": true
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
+ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==",
+ "dev": true
+ },
+ "node_modules/babel-eslint": {
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz",
+ "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/traverse": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "eslint-scope": "3.7.1",
+ "eslint-visitor-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/code-frame": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz",
+ "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "7.0.0-beta.44"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/generator": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "7.0.0-beta.44",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.2.0",
+ "source-map": "^0.5.0",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/helper-function-name": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz",
+ "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-get-function-arity": "7.0.0-beta.44",
+ "@babel/template": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/helper-get-function-arity": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz",
+ "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz",
+ "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/highlight": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz",
+ "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.0"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/template": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz",
+ "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "lodash": "^4.2.0"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/traverse": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz",
+ "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/generator": "7.0.0-beta.44",
+ "@babel/helper-function-name": "7.0.0-beta.44",
+ "@babel/helper-split-export-declaration": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "debug": "^3.1.0",
+ "globals": "^11.1.0",
+ "invariant": "^2.2.0",
+ "lodash": "^4.2.0"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/@babel/types": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.2.0",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/eslint-scope": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/babel-eslint/node_modules/js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ },
+ "node_modules/babel-plugin-dynamic-import-node": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz",
+ "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==",
+ "dev": true,
+ "dependencies": {
+ "object.assign": "^4.1.0"
+ }
+ },
+ "node_modules/babel-plugin-istanbul": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz",
+ "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-instrument": "^4.0.0",
+ "test-exclude": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-plugin-transform-async-to-promises": {
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-promises/-/babel-plugin-transform-async-to-promises-0.8.15.tgz",
+ "integrity": "sha512-fDXP68ZqcinZO2WCiimCL9zhGjGXOnn3D33zvbh+yheZ/qOrNVVDDIBtAaM3Faz8TRvQzHiRKsu3hfrBAhEncQ==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-transform-rename-properties": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-rename-properties/-/babel-plugin-transform-rename-properties-0.1.0.tgz",
+ "integrity": "sha512-uBSvAC8qH81TsXsWYD20ME4qg9ICflMLjsNfeuSxrKkJkym4Riqne1BrCCW15lcM/t9lfEiz4FJbVeUoaOVGWA==",
+ "dev": true
+ },
+ "node_modules/babylon": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
+ "dev": true,
+ "bin": {
+ "babylon": "bin/babylon.js"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/backo2": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+ "dev": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "node_modules/base64-arraybuffer": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
+ "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+ "dev": true
+ },
+ "node_modules/base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "dev": true,
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
+ }
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/benchmark": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
+ "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.4",
+ "platform": "^1.3.3"
+ }
+ },
+ "node_modules/better-assert": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+ "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+ "dev": true,
+ "dependencies": {
+ "callsite": "1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/bin-check": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz",
+ "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^0.7.0",
+ "executable": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/bin-version": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz",
+ "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^1.0.0",
+ "find-versions": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bin-version-check": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz",
+ "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==",
+ "dev": true,
+ "dependencies": {
+ "bin-version": "^3.0.0",
+ "semver": "^5.6.0",
+ "semver-truncate": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bin-version/node_modules/execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bin-version/node_modules/get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bin-wrapper": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz",
+ "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==",
+ "dev": true,
+ "dependencies": {
+ "bin-check": "^4.1.0",
+ "bin-version-check": "^4.0.0",
+ "download": "^7.1.0",
+ "import-lazy": "^3.1.0",
+ "os-filter-obj": "^2.0.0",
+ "pify": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
+ "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/bl/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/blob": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
+ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
+ "dev": true
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "dev": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/body-parser/node_modules/qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+ "dev": true
+ },
+ "node_modules/boolean": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz",
+ "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brotli-size": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-0.0.3.tgz",
+ "integrity": "sha512-bBIdd8uUGxKGldAVykxOqPegl+HlIm4FpXJamwWw5x77WCE8jO7AhXFE1YXOhOB28gS+2pTQete0FqRE6U5hQQ==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "^0.1.1",
+ "iltorb": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "node_modules/browserslist": {
+ "version": "4.7.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.3.tgz",
+ "integrity": "sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ==",
+ "dev": true,
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001010",
+ "electron-to-chromium": "^1.3.306",
+ "node-releases": "^1.1.40"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ }
+ },
+ "node_modules/buble": {
+ "version": "0.19.8",
+ "resolved": "https://registry.npmjs.org/buble/-/buble-0.19.8.tgz",
+ "integrity": "sha512-IoGZzrUTY5fKXVkgGHw3QeXFMUNBFv+9l8a4QJKG1JhG3nCMHTdEX1DCOg8568E2Q9qvAQIiSokv6Jsgx8p2cA==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^6.1.1",
+ "acorn-dynamic-import": "^4.0.0",
+ "acorn-jsx": "^5.0.1",
+ "chalk": "^2.4.2",
+ "magic-string": "^0.25.3",
+ "minimist": "^1.2.0",
+ "os-homedir": "^2.0.0",
+ "regexpu-core": "^4.5.4"
+ },
+ "bin": {
+ "buble": "bin/buble"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dev": true,
+ "dependencies": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "dev": true
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+ "dev": true
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "node_modules/builtin-modules": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
+ "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/cacheable-lookup": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz",
+ "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cacheable-request": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
+ "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=",
+ "dev": true,
+ "dependencies": {
+ "clone-response": "1.0.2",
+ "get-stream": "3.0.0",
+ "http-cache-semantics": "3.8.1",
+ "keyv": "3.0.0",
+ "lowercase-keys": "1.0.0",
+ "normalize-url": "2.0.1",
+ "responselike": "1.0.2"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/lowercase-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
+ "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/normalize-url": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz",
+ "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==",
+ "dev": true,
+ "dependencies": {
+ "prepend-http": "^2.0.0",
+ "query-string": "^5.0.1",
+ "sort-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/query-string": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
+ "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
+ "dev": true,
+ "dependencies": {
+ "decode-uri-component": "^0.2.0",
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/sort-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
+ "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
+ "dev": true,
+ "dependencies": {
+ "is-plain-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
+ "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.0"
+ }
+ },
+ "node_modules/caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-callsite/node_modules/callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "dev": true,
+ "dependencies": {
+ "caller-callsite": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/callsite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camel-case": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
+ "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
+ "dev": true,
+ "dependencies": {
+ "pascal-case": "^3.1.1",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-api": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
+ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "caniuse-lite": "^1.0.0",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
+ "node_modules/caniuse-db": {
+ "version": "1.0.30001012",
+ "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001012.tgz",
+ "integrity": "sha512-fm4VZQo0F1WYTmJcaTsqGhRuqcbkUW1/1hx8n5xdkbJSyaJV3jZ1vPXHYNcn376cAcuhxUIcE9TpHlSAYtN6bA==",
+ "dev": true
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001012",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz",
+ "integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==",
+ "dev": true
+ },
+ "node_modules/capital-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.3.tgz",
+ "integrity": "sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case-first": "^2.0.1"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "node_modules/caw": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz",
+ "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==",
+ "dev": true,
+ "dependencies": {
+ "get-proxy": "^2.0.0",
+ "isurl": "^1.0.0-alpha5",
+ "tunnel-agent": "^0.6.0",
+ "url-to-options": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chai": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
+ "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
+ "dev": true,
+ "dependencies": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.2",
+ "deep-eql": "^3.0.1",
+ "get-func-name": "^2.0.0",
+ "pathval": "^1.1.0",
+ "type-detect": "^4.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/change-case": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.1.tgz",
+ "integrity": "sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==",
+ "dev": true,
+ "dependencies": {
+ "camel-case": "^4.1.1",
+ "capital-case": "^1.0.3",
+ "constant-case": "^3.0.3",
+ "dot-case": "^3.0.3",
+ "header-case": "^2.0.3",
+ "no-case": "^3.0.3",
+ "param-case": "^3.0.3",
+ "pascal-case": "^3.1.1",
+ "path-case": "^3.0.3",
+ "sentence-case": "^3.0.3",
+ "snake-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "node_modules/check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/check-export-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/check-export-map/-/check-export-map-1.0.1.tgz",
+ "integrity": "sha512-6nJK5v9fiUQjAACrLyVlIm8UlAak5zdvYxJhpl0zYa7IqUElInMU6lRL/+rTHjEmy+hbkn5Wphq4Rj9cRkEbqg==",
+ "dev": true,
+ "dependencies": {
+ "kolorist": "^1.2.3",
+ "mri": "^1.1.6"
+ },
+ "bin": {
+ "check-export-map": "src/cli.js"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
+ "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.1.2"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
+ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
+ "dev": true
+ },
+ "node_modules/chrome-launcher": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz",
+ "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^1.0.5",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^0.5.3",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "node_modules/chrome-launcher/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "node_modules/clap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+ "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clap/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clap/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clap/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clap/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/clap/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "dependencies": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/cli-truncate/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-truncate/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
+ "node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/cliui/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/clone-response": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+ "dev": true,
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "node_modules/clone-response/node_modules/mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/coa": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
+ "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
+ "dev": true,
+ "dependencies": {
+ "@types/q": "^1.5.1",
+ "chalk": "^2.4.1",
+ "q": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
+ "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.1",
+ "color-string": "^1.5.4"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "node_modules/color-string": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz",
+ "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/colorette": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+ "dev": true
+ },
+ "node_modules/colormin": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
+ "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
+ "dev": true,
+ "dependencies": {
+ "color": "^0.11.0",
+ "css-color-names": "0.0.4",
+ "has": "^1.0.1"
+ }
+ },
+ "node_modules/colormin/node_modules/color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "dev": true,
+ "dependencies": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "node_modules/colormin/node_modules/color-string": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
+ "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
+ "dev": true,
+ "dependencies": {
+ "color-name": "^1.0.0"
+ }
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "node_modules/compare-versions": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
+ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
+ "dev": true
+ },
+ "node_modules/component-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+ "dev": true
+ },
+ "node_modules/component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "node_modules/component-inherit": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+ "dev": true
+ },
+ "node_modules/compress-commons": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.2.tgz",
+ "integrity": "sha512-qhd32a9xgzmpfoga1VQEiLEwdKZ6Plnpx5UCgIsf89FSolyJ7WnifY4Gtjgv5WR6hWAyRaHxC5MiEhU/38U70A==",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "^0.2.13",
+ "crc32-stream": "^4.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/compress-commons/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "node_modules/concat-with-sourcemaps": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+ "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "^0.6.1"
+ }
+ },
+ "node_modules/concat-with-sourcemaps/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/config-chain": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
+ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "node_modules/connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/connect/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/connect/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "node_modules/constant-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.3.tgz",
+ "integrity": "sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case": "^2.0.1"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "2.6.10",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
+ "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
+ "dev": true
+ },
+ "node_modules/core-js-compat": {
+ "version": "3.4.5",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.5.tgz",
+ "integrity": "sha512-rYVvzvKJDKoefdAC+q6VP63vp5hMmeVONCi9pVUbU1qRrtVrmAk/nPhnRg+i+XFd775m1hpG2Yd5RY3X45ccuw==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.7.3",
+ "semver": "^6.3.0"
+ }
+ },
+ "node_modules/core-js-compat/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "dev": true,
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/coveralls": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz",
+ "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==",
+ "dev": true,
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "lcov-parse": "^1.0.0",
+ "log-driver": "^1.2.7",
+ "minimist": "^1.2.0",
+ "request": "^2.88.0"
+ },
+ "bin": {
+ "coveralls": "bin/coveralls.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
+ "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
+ "dev": true,
+ "dependencies": {
+ "exit-on-epipe": "~1.0.1",
+ "printj": "~1.1.0"
+ },
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.1.tgz",
+ "integrity": "sha512-FN5V+weeO/8JaXsamelVYO1PHyeCsuL3HcG4cqsj0ceARcocxalaShCsohZMSAF+db7UYFwBy1rARK/0oFItUw==",
+ "dev": true,
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^3.4.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/crc32-stream/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/cross-env": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
+ "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "bin": {
+ "cross-env": "src/bin/cross-env.js",
+ "cross-env-shell": "src/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=10.14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
+ "node_modules/cross-env/node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cross-env/node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cross-env/node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cross-env/node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cross-env/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "dependencies": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ },
+ "engines": {
+ "node": ">=4.8"
+ }
+ },
+ "node_modules/css-color-names": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/css-declaration-sorter": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz",
+ "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.1",
+ "timsort": "^0.3.0"
+ },
+ "engines": {
+ "node": ">4"
+ }
+ },
+ "node_modules/css-modules-loader-core": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz",
+ "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=",
+ "dev": true,
+ "dependencies": {
+ "icss-replace-symbols": "1.1.0",
+ "postcss": "6.0.1",
+ "postcss-modules-extract-imports": "1.1.0",
+ "postcss-modules-local-by-default": "1.2.0",
+ "postcss-modules-scope": "1.1.0",
+ "postcss-modules-values": "1.3.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/postcss": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz",
+ "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-modules-loader-core/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
+ "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^3.2.1",
+ "domutils": "^1.7.0",
+ "nth-check": "^1.0.2"
+ }
+ },
+ "node_modules/css-select-base-adapter": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
+ "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
+ "dev": true
+ },
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+ "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "node_modules/css-shorthand-properties": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz",
+ "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==",
+ "dev": true
+ },
+ "node_modules/css-tree": {
+ "version": "1.0.0-alpha.37",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
+ "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
+ "dev": true,
+ "dependencies": {
+ "mdn-data": "2.0.4",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/css-tree/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css-value": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz",
+ "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=",
+ "dev": true
+ },
+ "node_modules/css-what": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
+ "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cssnano": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
+ "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==",
+ "dev": true,
+ "dependencies": {
+ "cosmiconfig": "^5.0.0",
+ "cssnano-preset-default": "^4.0.7",
+ "is-resolvable": "^1.0.0",
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/cssnano-preset-default": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz",
+ "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==",
+ "dev": true,
+ "dependencies": {
+ "css-declaration-sorter": "^4.0.1",
+ "cssnano-util-raw-cache": "^4.0.1",
+ "postcss": "^7.0.0",
+ "postcss-calc": "^7.0.1",
+ "postcss-colormin": "^4.0.3",
+ "postcss-convert-values": "^4.0.1",
+ "postcss-discard-comments": "^4.0.2",
+ "postcss-discard-duplicates": "^4.0.2",
+ "postcss-discard-empty": "^4.0.1",
+ "postcss-discard-overridden": "^4.0.1",
+ "postcss-merge-longhand": "^4.0.11",
+ "postcss-merge-rules": "^4.0.3",
+ "postcss-minify-font-values": "^4.0.2",
+ "postcss-minify-gradients": "^4.0.2",
+ "postcss-minify-params": "^4.0.2",
+ "postcss-minify-selectors": "^4.0.2",
+ "postcss-normalize-charset": "^4.0.1",
+ "postcss-normalize-display-values": "^4.0.2",
+ "postcss-normalize-positions": "^4.0.2",
+ "postcss-normalize-repeat-style": "^4.0.2",
+ "postcss-normalize-string": "^4.0.2",
+ "postcss-normalize-timing-functions": "^4.0.2",
+ "postcss-normalize-unicode": "^4.0.1",
+ "postcss-normalize-url": "^4.0.1",
+ "postcss-normalize-whitespace": "^4.0.2",
+ "postcss-ordered-values": "^4.1.2",
+ "postcss-reduce-initial": "^4.0.3",
+ "postcss-reduce-transforms": "^4.0.2",
+ "postcss-svgo": "^4.0.2",
+ "postcss-unique-selectors": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/cssnano-util-get-arguments": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
+ "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/cssnano-util-get-match": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
+ "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/cssnano-util-raw-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz",
+ "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/cssnano-util-same-parent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz",
+ "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/csso": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
+ "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+ "dev": true,
+ "dependencies": {
+ "css-tree": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/css-tree": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz",
+ "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==",
+ "dev": true,
+ "dependencies": {
+ "mdn-data": "2.0.14",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/mdn-data": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+ "dev": true
+ },
+ "node_modules/csso/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz",
+ "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==",
+ "dev": true
+ },
+ "node_modules/custom-event": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
+ "dev": true
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/date-format": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
+ "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/decompress": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz",
+ "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==",
+ "dev": true,
+ "dependencies": {
+ "decompress-tar": "^4.0.0",
+ "decompress-tarbz2": "^4.0.0",
+ "decompress-targz": "^4.0.0",
+ "decompress-unzip": "^4.0.1",
+ "graceful-fs": "^4.1.10",
+ "make-dir": "^1.0.0",
+ "pify": "^2.3.0",
+ "strip-dirs": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "dev": true,
+ "dependencies": {
+ "mimic-response": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/decompress-tar": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
+ "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
+ "dev": true,
+ "dependencies": {
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0",
+ "tar-stream": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/bl": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+ "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-tar/node_modules/tar-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^1.0.0",
+ "buffer-alloc": "^1.2.0",
+ "end-of-stream": "^1.0.0",
+ "fs-constants": "^1.0.0",
+ "readable-stream": "^2.3.0",
+ "to-buffer": "^1.1.1",
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/decompress-tarbz2": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz",
+ "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==",
+ "dev": true,
+ "dependencies": {
+ "decompress-tar": "^4.1.0",
+ "file-type": "^6.1.0",
+ "is-stream": "^1.1.0",
+ "seek-bzip": "^1.0.5",
+ "unbzip2-stream": "^1.0.9"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-tarbz2/node_modules/file-type": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz",
+ "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-targz": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
+ "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
+ "dev": true,
+ "dependencies": {
+ "decompress-tar": "^4.1.1",
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-targz/node_modules/file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-unzip": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz",
+ "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=",
+ "dev": true,
+ "dependencies": {
+ "file-type": "^3.8.0",
+ "get-stream": "^2.2.0",
+ "pify": "^2.3.0",
+ "yauzl": "^2.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress-unzip/node_modules/file-type": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
+ "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decompress-unzip/node_modules/get-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
+ "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.0.1",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decompress-unzip/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decompress/node_modules/make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress/node_modules/make-dir/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decompress/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
+ "dev": true
+ },
+ "node_modules/deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "node_modules/deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/defer-to-connect": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz",
+ "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "dependencies": {
+ "object-keys": "^1.0.12"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/defined": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+ "dev": true
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "dev": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/detect-node": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+ "dev": true
+ },
+ "node_modules/devtools": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/devtools/-/devtools-6.10.4.tgz",
+ "integrity": "sha512-53LoeU2S4q4cLJGKgo2Or7WU9Kc5RQscC0DbBAZcodkot1lKFbMg/z6/cQTq+XKl4kgYr5VA/s5kzNU7ScBctQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/puppeteer-core": "^2.0.0",
+ "@types/ua-parser-js": "^0.7.33",
+ "@types/uuid": "^8.3.0",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/protocols": "6.10.0",
+ "@wdio/utils": "6.10.4",
+ "chrome-launcher": "^0.13.1",
+ "edge-paths": "^2.1.0",
+ "puppeteer-core": "^5.1.0",
+ "ua-parser-js": "^0.7.21",
+ "uuid": "^8.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/devtools-protocol": {
+ "version": "0.0.818844",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz",
+ "integrity": "sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==",
+ "dev": true
+ },
+ "node_modules/devtools/node_modules/uuid": {
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
+ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
+ "dev": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/di": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
+ "dev": true
+ },
+ "node_modules/diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dom-serialize": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
+ "dev": true,
+ "dependencies": {
+ "custom-event": "~1.0.0",
+ "ent": "~2.2.0",
+ "extend": "^3.0.0",
+ "void-elements": "^2.0.0"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/domelementtype": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz",
+ "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==",
+ "dev": true
+ },
+ "node_modules/domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "node_modules/domutils": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+ "dev": true,
+ "dependencies": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/dot-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
+ "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dot-prop/node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/download": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz",
+ "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==",
+ "dev": true,
+ "dependencies": {
+ "archive-type": "^4.0.0",
+ "caw": "^2.0.1",
+ "content-disposition": "^0.5.2",
+ "decompress": "^4.2.0",
+ "ext-name": "^5.0.0",
+ "file-type": "^8.1.0",
+ "filenamify": "^2.0.0",
+ "get-stream": "^3.0.0",
+ "got": "^8.3.1",
+ "make-dir": "^1.2.0",
+ "p-event": "^2.1.0",
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/download/node_modules/decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+ "dev": true,
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/download/node_modules/got": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz",
+ "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==",
+ "dev": true,
+ "dependencies": {
+ "@sindresorhus/is": "^0.7.0",
+ "cacheable-request": "^2.1.1",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^3.0.0",
+ "into-stream": "^3.1.0",
+ "is-retry-allowed": "^1.1.0",
+ "isurl": "^1.0.0-alpha5",
+ "lowercase-keys": "^1.0.0",
+ "mimic-response": "^1.0.0",
+ "p-cancelable": "^0.4.0",
+ "p-timeout": "^2.0.1",
+ "pify": "^3.0.0",
+ "safe-buffer": "^5.1.1",
+ "timed-out": "^4.0.1",
+ "url-parse-lax": "^3.0.0",
+ "url-to-options": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/download/node_modules/make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/download/node_modules/mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/download/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
+ "node_modules/duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
+ "dev": true
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/edge-paths": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.1.0.tgz",
+ "integrity": "sha512-ZpIN1Vm5hlo9dkkST/1s8QqPNne2uwk3Plf6HcVUhnpfal0WnDRLdNj/wdQo3xRc+wnN3C25wPpPlV2E6aOunQ==",
+ "dev": true
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.3.314",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz",
+ "integrity": "sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ==",
+ "dev": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "node_modules/emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/engine.io": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz",
+ "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==",
+ "dev": true,
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "0.3.1",
+ "debug": "~4.1.0",
+ "engine.io-parser": "~2.2.0",
+ "ws": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/engine.io-client": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz",
+ "integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==",
+ "dev": true,
+ "dependencies": {
+ "component-emitter": "~1.3.0",
+ "component-inherit": "0.0.3",
+ "debug": "~3.1.0",
+ "engine.io-parser": "~2.2.0",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "parseqs": "0.0.6",
+ "parseuri": "0.0.6",
+ "ws": "~6.1.0",
+ "xmlhttprequest-ssl": "~1.5.4",
+ "yeast": "0.1.2"
+ }
+ },
+ "node_modules/engine.io-client/node_modules/debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/engine.io-client/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/engine.io-client/node_modules/parseqs": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
+ "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
+ "dev": true
+ },
+ "node_modules/engine.io-client/node_modules/parseuri": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
+ "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
+ "dev": true
+ },
+ "node_modules/engine.io-client/node_modules/ws": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
+ "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
+ "dev": true,
+ "dependencies": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
+ "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
+ "dev": true,
+ "dependencies": {
+ "after": "0.8.2",
+ "arraybuffer.slice": "~0.0.7",
+ "base64-arraybuffer": "0.1.4",
+ "blob": "0.0.5",
+ "has-binary2": "~1.0.2"
+ }
+ },
+ "node_modules/enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/ent": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
+ "dev": true
+ },
+ "node_modules/entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/errorstacks": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/errorstacks/-/errorstacks-2.3.0.tgz",
+ "integrity": "sha512-VjCIUbEyLymy2N1M/uTniewz+j69YC2R7Sp1UiJn04RHwyIniBib6hUZwgmphAAZTOk7LRg/wryGFEJhblEd7Q==",
+ "dev": true
+ },
+ "node_modules/es-abstract": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.2.tgz",
+ "integrity": "sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.1.4",
+ "is-regex": "^1.0.4",
+ "object-inspect": "^1.7.0",
+ "object-keys": "^1.1.1",
+ "string.prototype.trimleft": "^2.1.0",
+ "string.prototype.trimright": "^2.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true
+ },
+ "node_modules/es6-promisify": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
+ "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.8.47",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.47.tgz",
+ "integrity": "sha512-4C9pInguP36c9CRDMSb6W1KrMfXrLIQVtI02Vglc43RBV0Dw49ODEnP6985mrz5iqCdQ2Cxmb9i670J/s3DBPA==",
+ "dev": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "5.15.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.15.1.tgz",
+ "integrity": "sha512-NTcm6vQ+PTgN3UBsALw5BMhgO6i5EpIjQF/Xb5tIh3sk9QhrFafujUOczGz4J24JBlzWclSB9Vmx8d+9Z6bFCg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.9.1",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^4.0.2",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.1",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.2.2",
+ "js-yaml": "^3.12.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.11",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^6.14.0 || ^8.10.0 || >=9.10.0"
+ }
+ },
+ "node_modules/eslint-config-developit": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-developit/-/eslint-config-developit-1.1.1.tgz",
+ "integrity": "sha512-Wc2jbDhWixq9IDfFBVcFHYaOo2i3qwdVH236jQKsiNpJlfErxm0KDT5SWZiDSWU/h6ppHsru94W3DGbUg/MjzA==",
+ "dev": true,
+ "dependencies": {
+ "babel-eslint": "^8.0.3",
+ "eslint-plugin-compat": "^2.1.0",
+ "eslint-plugin-jest": "^21.4.2",
+ "eslint-plugin-mocha": "^4.0.0",
+ "eslint-plugin-react": "^7.0.0"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz",
+ "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==",
+ "dev": true,
+ "dependencies": {
+ "get-stdin": "^6.0.0"
+ },
+ "bin": {
+ "eslint-config-prettier-check": "bin/cli.js"
+ }
+ },
+ "node_modules/eslint-plugin-compat": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-2.7.0.tgz",
+ "integrity": "sha512-3J4Ic1WS+SgF1smUOc62fdf7Cnrdsg0GNwKmGVPziPtWdrc2vV5Oq2ut4kG6SM5DJcxOoz/sWJIN7rkcsWh60Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "^7.3.1",
+ "browserslist": "^4.4.1",
+ "caniuse-db": "^1.0.30000935",
+ "mdn-browser-compat-data": "^0.0.65"
+ },
+ "engines": {
+ "node": ">=8.x",
+ "npm": ">=6.7.0"
+ }
+ },
+ "node_modules/eslint-plugin-jest": {
+ "version": "21.27.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.27.2.tgz",
+ "integrity": "sha512-0E4OIgBJVlAmf1KfYFtZ3gYxgUzC5Eb3Jzmrc9ikI1OY+/cM8Kh72Ti7KfpeHNeD3HJNf9SmEfmvQLIz44Hrhw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/eslint-plugin-mocha": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.12.1.tgz",
+ "integrity": "sha512-hxWtYHvLA0p/PKymRfDYh9Mxt5dYkg2Goy1vZDarTEEYfELP9ksga7kKG1NUKSQy27C8Qjc7YrSWTLUhOEOksA==",
+ "dev": true,
+ "dependencies": {
+ "ramda": "^0.25.0"
+ }
+ },
+ "node_modules/eslint-plugin-react": {
+ "version": "7.12.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz",
+ "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.0.3",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.0.1",
+ "object.fromentries": "^2.0.0",
+ "prop-types": "^15.6.2",
+ "resolve": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint-plugin-react/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+ "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/espree": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
+ "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^6.0.7",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "node_modules/execa": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/execa/node_modules/cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/executable/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/exit-on-epipe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+ "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "dependencies": {
+ "is-posix-bracket": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-range/node_modules/fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-range/node_modules/is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-range/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ext-list": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
+ "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "^1.28.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ext-name": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
+ "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
+ "dev": true,
+ "dependencies": {
+ "ext-list": "^2.0.0",
+ "sort-keys-length": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extglob/node_modules/is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extract-zip/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/file-type": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz",
+ "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/filenamify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz",
+ "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==",
+ "dev": true,
+ "dependencies": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.0",
+ "trim-repeated": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/filesize": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
+ "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "dev": true,
+ "dependencies": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "dev": true
+ },
+ "node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/find-versions": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
+ "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
+ "dev": true,
+ "dependencies": {
+ "semver-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true,
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
+ "dev": true
+ },
+ "node_modules/flatten": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
+ "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
+ "dev": true
+ },
+ "node_modules/flow-remove-types": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-1.2.3.tgz",
+ "integrity": "sha512-ypq/U3V+t9atYiOuSJd40tekCra03EHKoRsiK/wXGrsZimuum0kdwVY7Yv0HTaoXgHW1WiayomYd+Q3kkvPl9Q==",
+ "dev": true,
+ "dependencies": {
+ "babylon": "^6.15.0",
+ "vlq": "^0.2.1"
+ },
+ "bin": {
+ "flow-node": "flow-node",
+ "flow-remove-types": "flow-remove-types"
+ }
+ },
+ "node_modules/flow-remove-types/node_modules/babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true,
+ "bin": {
+ "babylon": "bin/babylon.js"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
+ "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "dependencies": {
+ "for-in": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
+ "node_modules/fs-extra": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
+ "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "node_modules/gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": true,
+ "dependencies": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "node_modules/gauge/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gauge/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gauge/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gauge/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/generic-names": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
+ "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
+ "dev": true,
+ "dependencies": {
+ "loader-utils": "^1.1.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.1",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+ "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
+ "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "node_modules/get-own-enumerable-property-symbols": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+ "dev": true
+ },
+ "node_modules/get-port": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/get-proxy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz",
+ "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==",
+ "dev": true,
+ "dependencies": {
+ "npm-conf": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/get-stdin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+ "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "dependencies": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob-base/node_modules/glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "node_modules/glob-base/node_modules/is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob-base/node_modules/is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/global-agent": {
+ "version": "2.1.12",
+ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz",
+ "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==",
+ "dev": true,
+ "dependencies": {
+ "boolean": "^3.0.1",
+ "core-js": "^3.6.5",
+ "es6-error": "^4.1.1",
+ "matcher": "^3.0.0",
+ "roarr": "^2.15.3",
+ "semver": "^7.3.2",
+ "serialize-error": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=10.0"
+ }
+ },
+ "node_modules/global-agent/node_modules/core-js": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.0.tgz",
+ "integrity": "sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA==",
+ "dev": true
+ },
+ "node_modules/global-agent/node_modules/semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz",
+ "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/globalyzer": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
+ "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
+ "dev": true
+ },
+ "node_modules/globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+ "dev": true
+ },
+ "node_modules/got": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz",
+ "integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==",
+ "dev": true,
+ "dependencies": {
+ "@sindresorhus/is": "^4.0.0",
+ "@szmarczak/http-timer": "^4.0.5",
+ "@types/cacheable-request": "^6.0.1",
+ "@types/responselike": "^1.0.0",
+ "cacheable-lookup": "^5.0.3",
+ "cacheable-request": "^7.0.1",
+ "decompress-response": "^6.0.0",
+ "http2-wrapper": "^1.0.0-beta.5.2",
+ "lowercase-keys": "^2.0.0",
+ "p-cancelable": "^2.0.0",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "node_modules/got/node_modules/@sindresorhus/is": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz",
+ "integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/got/node_modules/cacheable-request": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
+ "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
+ "dev": true,
+ "dependencies": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^4.1.0",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/got/node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/got/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/got/node_modules/http-cache-semantics": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
+ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
+ "dev": true
+ },
+ "node_modules/got/node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "node_modules/got/node_modules/keyv": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz",
+ "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/got/node_modules/lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/got/node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/got/node_modules/normalize-url": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
+ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/got/node_modules/p-cancelable": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
+ "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/got/node_modules/responselike": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
+ "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
+ "dev": true,
+ "dependencies": {
+ "lowercase-keys": "^2.0.0"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+ "dev": true
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "node_modules/growl": {
+ "version": "1.10.5",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.x"
+ }
+ },
+ "node_modules/gzip-size": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
+ "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "^0.1.1",
+ "pify": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-ansi/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-binary2": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
+ "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
+ "dev": true,
+ "dependencies": {
+ "isarray": "2.0.1"
+ }
+ },
+ "node_modules/has-binary2/node_modules/isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ },
+ "node_modules/has-cors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
+ "dev": true
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbol-support-x": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
+ "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/has-to-string-tag-x": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz",
+ "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==",
+ "dev": true,
+ "dependencies": {
+ "has-symbol-support-x": "^1.4.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true
+ },
+ "node_modules/hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/header-case": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz",
+ "integrity": "sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==",
+ "dev": true,
+ "dependencies": {
+ "capital-case": "^1.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/hex-color-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
+ "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==",
+ "dev": true
+ },
+ "node_modules/hosted-git-info": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+ "dev": true
+ },
+ "node_modules/hsl-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
+ "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=",
+ "dev": true
+ },
+ "node_modules/hsla-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
+ "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=",
+ "dev": true
+ },
+ "node_modules/html-comment-regex": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
+ "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
+ "dev": true
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
+ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+ "dev": true
+ },
+ "node_modules/http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "dev": true,
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-errors/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/http2-wrapper": {
+ "version": "1.0.0-beta.5.2",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz",
+ "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==",
+ "dev": true,
+ "dependencies": {
+ "quick-lru": "^5.1.1",
+ "resolve-alpn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "5",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.12.0"
+ }
+ },
+ "node_modules/husky": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz",
+ "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "ci-info": "^2.0.0",
+ "compare-versions": "^3.6.0",
+ "cosmiconfig": "^7.0.0",
+ "find-versions": "^3.2.0",
+ "opencollective-postinstall": "^2.0.2",
+ "pkg-dir": "^4.2.0",
+ "please-upgrade-node": "^3.2.0",
+ "slash": "^3.0.0",
+ "which-pm-runs": "^1.0.0"
+ },
+ "bin": {
+ "husky-run": "bin/run.js",
+ "husky-upgrade": "lib/upgrader/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/husky/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/husky/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/husky/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/husky/node_modules/cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "dev": true,
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/husky/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/parse-json": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
+ "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/husky/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/icss-replace-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+ "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
+ "dev": true
+ },
+ "node_modules/ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/iltorb": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/iltorb/-/iltorb-2.4.5.tgz",
+ "integrity": "sha512-EMCMl3LnnNSZJS5QrxyZmMTaAC4+TJkM5woD+xbpm9RB+mFYCr7C05GFE3TEGCsVQSVHmjX+3sf5AiwsylNInQ==",
+ "dev": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "nan": "^2.14.0",
+ "npmlog": "^4.1.2",
+ "prebuild-install": "^5.3.3",
+ "which-pm-runs": "^1.0.0"
+ }
+ },
+ "node_modules/import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+ "dev": true,
+ "dependencies": {
+ "import-from": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+ "dev": true,
+ "dependencies": {
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-from/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-lazy": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz",
+ "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "node_modules/indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/inquirer": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+ "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.12",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/inquirer/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/inquirer/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/into-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
+ "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
+ "dev": true,
+ "dependencies": {
+ "from2": "^2.1.1",
+ "p-is-promise": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/is-absolute-url": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
+ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "node_modules/is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-ci": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
+ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
+ "dev": true,
+ "dependencies": {
+ "ci-info": "^1.5.0"
+ },
+ "bin": {
+ "is-ci": "bin.js"
+ }
+ },
+ "node_modules/is-ci/node_modules/ci-info": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
+ "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
+ "dev": true
+ },
+ "node_modules/is-color-stop": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
+ "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
+ "dev": true,
+ "dependencies": {
+ "css-color-names": "^0.0.4",
+ "hex-color-regex": "^1.1.0",
+ "hsl-regex": "^1.0.0",
+ "hsla-regex": "^1.0.0",
+ "rgb-regex": "^1.0.1",
+ "rgba-regex": "^1.0.0"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
+ "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
+ "dev": true,
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "dependencies": {
+ "is-primitive": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+ "dev": true
+ },
+ "node_modules/is-natural-number": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
+ "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=",
+ "dev": true
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
+ "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
+ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
+ "dev": true
+ },
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "node_modules/is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-resolvable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+ "dev": true
+ },
+ "node_modules/is-retry-allowed": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
+ "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-svg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
+ "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
+ "dev": true,
+ "dependencies": {
+ "html-comment-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "node_modules/isbinaryfile": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz",
+ "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "node_modules/isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "dependencies": {
+ "isarray": "1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
+ "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz",
+ "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.7.5",
+ "@babel/parser": "^7.7.5",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/core": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz",
+ "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helpers": "^7.8.4",
+ "@babel/parser": "^7.8.4",
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/core/node_modules/@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/core/node_modules/@babel/traverse": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
+ "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/core/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/generator": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
+ "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.8.3",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helper-function-name": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
+ "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helper-function-name/node_modules/@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helper-get-function-arity": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
+ "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
+ "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helpers": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz",
+ "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.4",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helpers/node_modules/@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/helpers/node_modules/@babel/traverse": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
+ "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/highlight": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
+ "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/parser": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
+ "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/@babel/types": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
+ "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+ "dev": true,
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^3.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
+ "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
+ "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
+ "dev": true,
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isurl": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
+ "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
+ "dev": true,
+ "dependencies": {
+ "has-to-string-tag-x": "^1.2.0",
+ "is-object": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "23.2.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz",
+ "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=",
+ "dev": true,
+ "dependencies": {
+ "merge-stream": "^1.0.1"
+ }
+ },
+ "node_modules/jest-worker/node_modules/merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "node_modules/js-base64": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
+ "dev": true
+ },
+ "node_modules/js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
+ "dev": true
+ },
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "node_modules/json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+ "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/jsx-ast-utils": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz",
+ "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.0.3",
+ "object.assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/just-extend": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz",
+ "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==",
+ "dev": true
+ },
+ "node_modules/karma": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/karma/-/karma-5.2.3.tgz",
+ "integrity": "sha512-tHdyFADhVVPBorIKCX8A37iLHxc6RBRphkSoQ+MLKdAtFn1k97tD8WUGi1KlEtDZKL3hui0qhsY9HXUfSNDYPQ==",
+ "dev": true,
+ "dependencies": {
+ "body-parser": "^1.19.0",
+ "braces": "^3.0.2",
+ "chokidar": "^3.4.2",
+ "colors": "^1.4.0",
+ "connect": "^3.7.0",
+ "di": "^0.0.1",
+ "dom-serialize": "^2.2.1",
+ "glob": "^7.1.6",
+ "graceful-fs": "^4.2.4",
+ "http-proxy": "^1.18.1",
+ "isbinaryfile": "^4.0.6",
+ "lodash": "^4.17.19",
+ "log4js": "^6.2.1",
+ "mime": "^2.4.5",
+ "minimatch": "^3.0.4",
+ "qjobs": "^1.2.0",
+ "range-parser": "^1.2.1",
+ "rimraf": "^3.0.2",
+ "socket.io": "^2.3.0",
+ "source-map": "^0.6.1",
+ "tmp": "0.2.1",
+ "ua-parser-js": "0.7.22",
+ "yargs": "^15.3.1"
+ },
+ "bin": {
+ "karma": "bin/karma"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/karma-chai-sinon": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/karma-chai-sinon/-/karma-chai-sinon-0.1.5.tgz",
+ "integrity": "sha1-XDksqVJHgYlR1rV5AvAsNugDdTo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/karma-chrome-launcher": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz",
+ "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==",
+ "dev": true,
+ "dependencies": {
+ "which": "^1.2.1"
+ }
+ },
+ "node_modules/karma-coverage": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.3.tgz",
+ "integrity": "sha512-atDvLQqvPcLxhED0cmXYdsPMCQuh6Asa9FMZW1bhNqlVEhJoB9qyZ2BY1gu7D/rr5GLGb5QzYO4siQskxaWP/g==",
+ "dev": true,
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.1",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.0",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/karma-esbuild": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/karma-esbuild/-/karma-esbuild-2.2.0.tgz",
+ "integrity": "sha512-6dZSoKHod2YJzQSe5sbUhXFuuLR8TIJXGRRxf4ZOgBzk34WTtasBS7+eRDbVRjp/hryULvhD06Vx7bo/veg8Yw==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^3.5.1",
+ "source-map": "0.6.1"
+ },
+ "peerDependencies": {
+ "esbuild": ">=0.8.45"
+ }
+ },
+ "node_modules/karma-esbuild/node_modules/chokidar": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.1"
+ }
+ },
+ "node_modules/karma-esbuild/node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/karma-esbuild/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/karma-mocha": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz",
+ "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.3"
+ }
+ },
+ "node_modules/karma-mocha-reporter": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz",
+ "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.1.0",
+ "log-symbols": "^2.1.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "node_modules/karma-sauce-launcher": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/karma-sauce-launcher/-/karma-sauce-launcher-4.3.4.tgz",
+ "integrity": "sha512-sXka3l3Z9x+UhGMsg0fU+i+Jq82j7tfApMrAupM8JxO8ZskmSCozUM4cffLTwuzJPYjf0ffFNu3Up5Pzr26N/g==",
+ "dev": true,
+ "dependencies": {
+ "fs-extra": "^9.0.1",
+ "global-agent": "^2.1.12",
+ "saucelabs": "^4.5.1",
+ "webdriverio": "^6.7.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/karma-sauce-launcher/node_modules/fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/karma-sauce-launcher/node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "node_modules/karma-sauce-launcher/node_modules/jsonfile/node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/karma-sauce-launcher/node_modules/universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/karma-sinon": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz",
+ "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/karma-sourcemap-loader": {
+ "version": "0.3.7",
+ "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz",
+ "integrity": "sha1-kTIsd/jxPUb+0GKwQuEAnUxFBdg=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "node_modules/karma/node_modules/graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "node_modules/karma/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/karma/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/karma/node_modules/tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "dependencies": {
+ "rimraf": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8.17.0"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz",
+ "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.0"
+ }
+ },
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/kolorist": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.2.10.tgz",
+ "integrity": "sha512-S3QtGjCHyINclP4LSClgHw4gi/NxTFcSorqD9SWfrREHKtMyGfi6pyDCTbpQaqyZrMAjB4Exde8eco6kejkqQg==",
+ "dev": true
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lcov-parse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
+ "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=",
+ "dev": true,
+ "bin": {
+ "lcov-parse": "bin/cli.js"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lighthouse-logger": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz",
+ "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^2.6.8",
+ "marky": "^1.2.0"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "node_modules/lint-staged": {
+ "version": "10.5.2",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.2.tgz",
+ "integrity": "sha512-e8AYR1TDlzwB8VVd38Xu2lXDZf6BcshVqKVuBQThDJRaJLobqKnpbm4dkwJ2puypQNbLr9KF/9mfA649mAGvjA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "commander": "^6.2.0",
+ "cosmiconfig": "^7.0.0",
+ "debug": "^4.2.0",
+ "dedent": "^0.7.0",
+ "enquirer": "^2.3.6",
+ "execa": "^4.1.0",
+ "listr2": "^3.2.2",
+ "log-symbols": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "normalize-path": "^3.0.0",
+ "please-upgrade-node": "^3.2.0",
+ "string-argv": "0.3.1",
+ "stringify-object": "^3.3.0"
+ },
+ "bin": {
+ "lint-staged": "bin/lint-staged.js"
+ }
+ },
+ "node_modules/lint-staged/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lint-staged/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/lint-staged/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/lint-staged/node_modules/commander": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
+ "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/lint-staged/node_modules/cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "dev": true,
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lint-staged/node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/lint-staged/node_modules/execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lint-staged/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/log-symbols": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+ "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lint-staged/node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lint-staged/node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lint-staged/node_modules/parse-json": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
+ "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lint-staged/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/listr2": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.2.3.tgz",
+ "integrity": "sha512-vUb80S2dSUi8YxXahO8/I/s29GqnOL8ozgHVLjfWQXa03BNEeS1TpBLjh2ruaqq5ufx46BRGvfymdBSuoXET5w==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "figures": "^3.2.0",
+ "indent-string": "^4.0.0",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rxjs": "^6.6.3",
+ "through": "^2.3.8"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/listr2/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/listr2/node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/listr2/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/listr2/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/listr2/node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/listr2/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/listr2/node_modules/rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.9.0"
+ },
+ "engines": {
+ "npm": ">=2.0.0"
+ }
+ },
+ "node_modules/listr2/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/loader-utils": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
+ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "dev": true,
+ "dependencies": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^2.0.0",
+ "json5": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/loader-utils/node_modules/json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+ "dev": true
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+ "dev": true
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
+ "dev": true
+ },
+ "node_modules/lodash.difference": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+ "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=",
+ "dev": true
+ },
+ "node_modules/lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
+ "dev": true
+ },
+ "node_modules/lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=",
+ "dev": true
+ },
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "dev": true
+ },
+ "node_modules/lodash.isobject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
+ "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
+ "dev": true
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "dev": true
+ },
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.sumby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.sumby/-/lodash.sumby-4.6.0.tgz",
+ "integrity": "sha1-fYdzfdshbaL35efNLdnEA6eIc0Y=",
+ "dev": true
+ },
+ "node_modules/lodash.union": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=",
+ "dev": true
+ },
+ "node_modules/lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
+ "dev": true
+ },
+ "node_modules/lodash.zip": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz",
+ "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=",
+ "dev": true
+ },
+ "node_modules/log-driver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
+ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.6"
+ }
+ },
+ "node_modules/log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-escapes": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+ "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.11.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-update/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/log-update/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/log-update/node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/log-update/node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-update/node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/log-update/node_modules/type-fest": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+ "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log4js": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz",
+ "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==",
+ "dev": true,
+ "dependencies": {
+ "date-format": "^3.0.0",
+ "debug": "^4.1.1",
+ "flatted": "^2.0.1",
+ "rfdc": "^1.1.4",
+ "streamroller": "^2.2.4"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/loglevel": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
+ "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/loglevel-plugin-prefix": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz",
+ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lower-case": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
+ "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.25.7",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+ "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "dev": true,
+ "dependencies": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/marky": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.1.tgz",
+ "integrity": "sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==",
+ "dev": true
+ },
+ "node_modules/matcher": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
+ "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/matcher/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/math-expression-evaluator": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.3.tgz",
+ "integrity": "sha512-geKTlqoxnjqHoWqB71h0kchWIC23a3yfwwbZu4E2amjvGLF+fTjCCwBQOHkE0/oHc6KdnSVmMt3QB82KaPmKEA==",
+ "dev": true
+ },
+ "node_modules/math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true
+ },
+ "node_modules/maxmin": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
+ "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.0.0",
+ "figures": "^1.0.1",
+ "gzip-size": "^3.0.0",
+ "pretty-bytes": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/maxmin/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5",
+ "object-assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/gzip-size": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/pretty-bytes": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
+ "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/maxmin/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/mdn-browser-compat-data": {
+ "version": "0.0.65",
+ "resolved": "https://registry.npmjs.org/mdn-browser-compat-data/-/mdn-browser-compat-data-0.0.65.tgz",
+ "integrity": "sha512-OC27wWCLD2mw2aW6+8zZTwCv0+9WMTOFxuvTBfWoCx8f9gVFNUXHxGYA16mhKyso7hEa4tw1hY+ruCB/kg3EzQ==",
+ "dev": true,
+ "dependencies": {
+ "extend": "3.0.2"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
+ "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
+ "dev": true
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/memorystream": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+ "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/microbundle": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/microbundle/-/microbundle-0.11.0.tgz",
+ "integrity": "sha512-Lt2f8OhC2y2uKyJ5zA8lEEiDsIAbk6yllBuoAWLIdYVIXYqOdN9mO3DI7VW7x/fw87gdnCLIJdVtpP6kaI99LA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.2.2",
+ "@babel/plugin-proposal-class-properties": "7.2.1",
+ "@babel/plugin-syntax-jsx": "^7.2.0",
+ "@babel/polyfill": "^7.0.0",
+ "asyncro": "^3.0.0",
+ "autoprefixer": "^9.0.0",
+ "babel-plugin-transform-async-to-promises": "^0.8.3",
+ "brotli-size": "^0.0.3",
+ "camelcase": "^5.0.0",
+ "chalk": "^2.4.0",
+ "cssnano": "^4.1.7",
+ "es6-promisify": "^6.0.1",
+ "gzip-size": "^5.0.0",
+ "pretty-bytes": "^5.1.0",
+ "rollup": "^0.67.3",
+ "rollup-plugin-alias": "^1.5.1",
+ "rollup-plugin-babel": "^4.1.0-0",
+ "rollup-plugin-buble": "^0.19.4",
+ "rollup-plugin-bundle-size": "^1.0.1",
+ "rollup-plugin-commonjs": "^9.0.0",
+ "rollup-plugin-es3": "^1.1.0",
+ "rollup-plugin-flow": "^1.1.1",
+ "rollup-plugin-json": "^3.1.0",
+ "rollup-plugin-node-resolve": "^4.0.0",
+ "rollup-plugin-postcss": "^1.6.1",
+ "rollup-plugin-preserve-shebang": "^0.1.6",
+ "rollup-plugin-sizes": "^0.4.2",
+ "rollup-plugin-terser": "^3.0.0",
+ "rollup-plugin-typescript2": "^0.19.0",
+ "sade": "^1.4.0",
+ "tiny-glob": "^0.2.6",
+ "tslib": "^1.9.0",
+ "typescript": ">=2.8.3"
+ },
+ "bin": {
+ "microbundle": "dist/cli.js"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mime": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
+ "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.42.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
+ "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.25",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
+ "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.42.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "dev": true
+ },
+ "node_modules/mocha": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz",
+ "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==",
+ "dev": true,
+ "dependencies": {
+ "@ungap/promise-all-settled": "1.1.2",
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.4.3",
+ "debug": "4.2.0",
+ "diff": "4.0.2",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.1.6",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "3.14.0",
+ "log-symbols": "4.0.0",
+ "minimatch": "3.0.4",
+ "ms": "2.1.2",
+ "nanoid": "3.1.12",
+ "serialize-javascript": "5.0.1",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "7.2.0",
+ "which": "2.0.2",
+ "wide-align": "1.1.3",
+ "workerpool": "6.0.2",
+ "yargs": "13.3.2",
+ "yargs-parser": "13.1.2",
+ "yargs-unparser": "2.0.0"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha"
+ },
+ "engines": {
+ "node": ">= 10.12.0"
+ }
+ },
+ "node_modules/mocha/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "node_modules/mocha/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/mocha/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/mocha/node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/mocha/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/mocha/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/log-symbols": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+ "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/mocha/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/mocha/node_modules/wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mocha/node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/mocha/node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mocha/node_modules/yargs/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/module-details-from-path": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz",
+ "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=",
+ "dev": true
+ },
+ "node_modules/mri": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
+ "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "node_modules/nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+ "dev": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.1.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz",
+ "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==",
+ "dev": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/napi-build-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+ "dev": true
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "node_modules/nise": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz",
+ "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^1.7.0",
+ "@sinonjs/fake-timers": "^6.0.0",
+ "@sinonjs/text-encoding": "^0.7.1",
+ "just-extend": "^4.0.2",
+ "path-to-regexp": "^1.7.0"
+ }
+ },
+ "node_modules/no-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
+ "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
+ "dev": true,
+ "dependencies": {
+ "lower-case": "^2.0.1",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/node-abi": {
+ "version": "2.19.3",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz",
+ "integrity": "sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^5.4.1"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
+ "dev": true,
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/node-modules-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
+ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "1.1.41",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.41.tgz",
+ "integrity": "sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^6.3.0"
+ }
+ },
+ "node_modules/node-releases/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/noop-logger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+ "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=",
+ "dev": true
+ },
+ "node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-url": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
+ "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/npm-conf": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz",
+ "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
+ "dev": true,
+ "dependencies": {
+ "config-chain": "^1.1.11",
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-conf/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/npm-merge-driver/-/npm-merge-driver-2.3.6.tgz",
+ "integrity": "sha512-uPjCEWZ93f379zw0AMEgFtZIlpSSnpXc8BEIcs8yYHEZs5Y3d85OZHisLjNhjbYnbdAznxTq+VbyBWAQZDEm9w==",
+ "dev": true,
+ "dependencies": {
+ "mkdirp": "^0.5.1",
+ "yargs": "^10.0.3"
+ },
+ "bin": {
+ "npm-merge-driver": "index.js"
+ }
+ },
+ "node_modules/npm-merge-driver-install": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/npm-merge-driver-install/-/npm-merge-driver-install-1.1.1.tgz",
+ "integrity": "sha512-QoEoJ1SAkkVPoZ9p84yel5xiMeXXqpkw1KwA8hP0iVO/NWZUYYgTUkXRL54YJ7HyLK3aTaiQrRVfpPpb9Cm/FA==",
+ "dev": true,
+ "dependencies": {
+ "find-root": "^1.1.0",
+ "is-ci": "^1.2.0",
+ "npm-merge-driver": "^2.3.5"
+ },
+ "bin": {
+ "npm-merge-driver-install": "index.js"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/execa": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/get-caller-file": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
+ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "dependencies": {
+ "number-is-nan": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "dev": true,
+ "dependencies": {
+ "invert-kv": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/lru-cache": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
+ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/mem": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/mimic-fn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
+ "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "dependencies": {
+ "minimist": "0.0.8"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/os-locale": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^0.7.0",
+ "lcid": "^1.0.0",
+ "mem": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/p-limit": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
+ "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/which": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
+ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz",
+ "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "find-up": "^2.1.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^2.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^8.0.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz",
+ "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^4.1.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs-parser/node_modules/camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/cliui/node_modules/string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "dependencies": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "dependencies": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/string-width/node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-merge-driver/node_modules/yargs/node_modules/string-width/node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-run-all": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
+ "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "chalk": "^2.4.1",
+ "cross-spawn": "^6.0.5",
+ "memorystream": "^0.3.1",
+ "minimatch": "^3.0.4",
+ "pidtree": "^0.3.0",
+ "read-pkg": "^3.0.0",
+ "shell-quote": "^1.6.1",
+ "string.prototype.padend": "^3.0.0"
+ },
+ "bin": {
+ "npm-run-all": "bin/npm-run-all/index.js",
+ "run-p": "bin/run-p/index.js",
+ "run-s": "bin/run-s/index.js"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dev": true,
+ "dependencies": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "node_modules/num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+ "dev": true
+ },
+ "node_modules/number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-component": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
+ "dev": true
+ },
+ "node_modules/object-inspect": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
+ "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
+ "dev": true
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz",
+ "integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.15.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz",
+ "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors/node_modules/es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors/node_modules/is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors/node_modules/is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.getownpropertydescriptors/node_modules/object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "node_modules/object.getownpropertydescriptors/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "dependencies": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
+ "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values/node_modules/es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values/node_modules/is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values/node_modules/is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values/node_modules/object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "node_modules/object.values/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "dev": true,
+ "bin": {
+ "opencollective-postinstall": "index.js"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-filter-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz",
+ "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==",
+ "dev": true,
+ "dependencies": {
+ "arch": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/os-homedir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-2.0.0.tgz",
+ "integrity": "sha512-saRNz0DSC5C/I++gFIaJTXoFJMRwiP5zHar5vV3xQ2TkgEw6hDCcU5F272JjUylpiVgBrZNQHnfjkLabTfb92Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/p-cancelable": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz",
+ "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-event": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz",
+ "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==",
+ "dev": true,
+ "dependencies": {
+ "p-timeout": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-is-promise": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
+ "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+ "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/p-queue": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
+ "integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
+ "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+ "dev": true,
+ "dependencies": {
+ "p-finally": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/param-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz",
+ "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==",
+ "dev": true,
+ "dependencies": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "dependencies": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse-glob/node_modules/is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse-glob/node_modules/is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/parseqs": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+ "dev": true,
+ "dependencies": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "node_modules/parseuri": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+ "dev": true,
+ "dependencies": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/pascal-case": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
+ "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/path-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.3.tgz",
+ "integrity": "sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==",
+ "dev": true,
+ "dependencies": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "node_modules/path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "node_modules/path-to-regexp": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "dev": true,
+ "dependencies": {
+ "isarray": "0.0.1"
+ }
+ },
+ "node_modules/path-to-regexp/node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "node_modules/path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-type/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/pidtree": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
+ "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
+ "dev": true,
+ "bin": {
+ "pidtree": "bin/pidtree.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "dependencies": {
+ "pinkie": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
+ "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
+ "dev": true,
+ "dependencies": {
+ "node-modules-regexp": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/platform": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
+ "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==",
+ "dev": true
+ },
+ "node_modules/please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "dependencies": {
+ "semver-compare": "^1.0.0"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "7.0.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+ "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/postcss-calc": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
+ "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.27",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "node_modules/postcss-colormin": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz",
+ "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "color": "^3.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-colormin/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-convert-values": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz",
+ "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-convert-values/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-discard-comments": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
+ "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-discard-duplicates": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz",
+ "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-discard-empty": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz",
+ "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-discard-overridden": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz",
+ "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-discard-unused": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
+ "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.14",
+ "uniqs": "^2.0.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-discard-unused/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
+ "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-filter-plugins/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
+ "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
+ "dev": true,
+ "dependencies": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0",
+ "postcss-load-options": "^1.2.0",
+ "postcss-load-plugins": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "dependencies": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-load-options": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz",
+ "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=",
+ "dev": true,
+ "dependencies": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-options/node_modules/cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "dependencies": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-options/node_modules/os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-load-options/node_modules/parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-load-plugins": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz",
+ "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=",
+ "dev": true,
+ "dependencies": {
+ "cosmiconfig": "^2.1.1",
+ "object-assign": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-plugins/node_modules/cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "dependencies": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-load-plugins/node_modules/os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-load-plugins/node_modules/parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
+ "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.10",
+ "postcss-value-parser": "^3.1.1"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-merge-idents/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-merge-idents/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-merge-longhand": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
+ "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==",
+ "dev": true,
+ "dependencies": {
+ "css-color-names": "0.0.4",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "stylehacks": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-merge-rules": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz",
+ "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "caniuse-api": "^3.0.0",
+ "cssnano-util-same-parent": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0",
+ "vendors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "dependencies": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/postcss-message-helpers": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
+ "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
+ "dev": true
+ },
+ "node_modules/postcss-minify-font-values": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz",
+ "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-minify-gradients": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz",
+ "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "is-color-stop": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-minify-params": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz",
+ "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.0",
+ "browserslist": "^4.0.0",
+ "cssnano-util-get-arguments": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "uniqs": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-minify-params/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-minify-selectors": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz",
+ "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "dependencies": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/postcss-modules": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-1.5.0.tgz",
+ "integrity": "sha512-KiAihzcV0TxTTNA5OXreyIXctuHOfR50WIhqBpc8pe0Q5dcs/Uap9EVlifOI9am7zGGdGOJQ6B1MPYKo2UxgOg==",
+ "dev": true,
+ "dependencies": {
+ "css-modules-loader-core": "^1.1.0",
+ "generic-names": "^2.0.1",
+ "lodash.camelcase": "^4.3.0",
+ "postcss": "^7.0.1",
+ "string-hash": "^1.1.1"
+ }
+ },
+ "node_modules/postcss-modules-extract-imports": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz",
+ "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^6.0.1"
+ }
+ },
+ "node_modules/postcss-modules-extract-imports/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-modules-extract-imports/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-modules-local-by-default": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
+ "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
+ "dev": true,
+ "dependencies": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "node_modules/postcss-modules-local-by-default/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-modules-local-by-default/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-modules-scope": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
+ "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
+ "dev": true,
+ "dependencies": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "node_modules/postcss-modules-scope/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-modules-scope/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-modules-values": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
+ "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
+ "dev": true,
+ "dependencies": {
+ "icss-replace-symbols": "^1.1.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "node_modules/postcss-modules-values/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-modules-values/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-normalize-charset": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz",
+ "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-display-values": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz",
+ "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-positions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz",
+ "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-repeat-style": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz",
+ "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-string": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz",
+ "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-timing-functions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz",
+ "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-unicode": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz",
+ "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-url": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz",
+ "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==",
+ "dev": true,
+ "dependencies": {
+ "is-absolute-url": "^2.0.0",
+ "normalize-url": "^3.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-normalize-whitespace": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz",
+ "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-ordered-values": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz",
+ "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-reduce-idents": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
+ "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-reduce-idents/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-reduce-idents/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-reduce-initial": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz",
+ "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "caniuse-api": "^3.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-reduce-transforms": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz",
+ "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==",
+ "dev": true,
+ "dependencies": {
+ "cssnano-util-get-match": "^4.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
+ "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-svgo": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz",
+ "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==",
+ "dev": true,
+ "dependencies": {
+ "is-svg": "^3.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "svgo": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-svgo/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/postcss-unique-selectors": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
+ "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.0",
+ "postcss": "^7.0.0",
+ "uniqs": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+ "dev": true
+ },
+ "node_modules/postcss-zindex": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
+ "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss-zindex/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/postcss/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss/node_modules/supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/prebuild-install": {
+ "version": "5.3.6",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz",
+ "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==",
+ "dev": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^2.7.0",
+ "noop-logger": "^0.1.1",
+ "npmlog": "^4.0.1",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^3.0.3",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0",
+ "which-pm-runs": "^1.0.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+ "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pretty-bytes": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
+ "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/printj": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
+ "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
+ "dev": true,
+ "bin": {
+ "printj": "bin/printj.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/promise.series": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz",
+ "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "node_modules/proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+ "dev": true
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
+ "node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "node_modules/psl": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
+ "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==",
+ "dev": true
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/puppeteer-core": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-5.5.0.tgz",
+ "integrity": "sha512-tlA+1n+ziW/Db03hVV+bAecDKse8ihFRXYiEypBe9IlLRvOCzYFG6qrCMBYK34HO/Q/Ecjc+tvkHRAfLVH+NgQ==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.0",
+ "devtools-protocol": "0.0.818844",
+ "extract-zip": "^2.0.0",
+ "https-proxy-agent": "^4.0.0",
+ "node-fetch": "^2.6.1",
+ "pkg-dir": "^4.2.0",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^3.0.2",
+ "tar-fs": "^2.0.0",
+ "unbzip2-stream": "^1.3.3",
+ "ws": "^7.2.3"
+ },
+ "engines": {
+ "node": ">=10.18.1"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer-core/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6.0",
+ "teleport": ">=0.2.0"
+ }
+ },
+ "node_modules/qjobs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.9"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ramda": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz",
+ "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==",
+ "dev": true
+ },
+ "node_modules/randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/randomatic/node_modules/is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "dev": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dev": true,
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.12.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
+ "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==",
+ "dev": true
+ },
+ "node_modules/read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
+ "dependencies": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz",
+ "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==",
+ "dev": true,
+ "dependencies": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reduce-css-calc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
+ "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^0.4.2",
+ "math-expression-evaluator": "^1.2.14",
+ "reduce-function-call": "^1.0.1"
+ }
+ },
+ "node_modules/reduce-css-calc/node_modules/balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
+ "dev": true
+ },
+ "node_modules/reduce-function-call": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz",
+ "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
+ "dev": true
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz",
+ "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.4.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+ "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
+ "dev": true
+ },
+ "node_modules/regenerator-transform": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz",
+ "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==",
+ "dev": true,
+ "dependencies": {
+ "private": "^0.1.6"
+ }
+ },
+ "node_modules/regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "dependencies": {
+ "is-equal-shallow": "^0.1.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.5.0"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz",
+ "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.4.0",
+ "regenerate-unicode-properties": "^8.1.0",
+ "regjsgen": "^0.5.0",
+ "regjsparser": "^0.6.0",
+ "unicode-match-property-ecmascript": "^1.0.4",
+ "unicode-match-property-value-ecmascript": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz",
+ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==",
+ "dev": true
+ },
+ "node_modules/regjsparser": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz",
+ "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==",
+ "dev": true,
+ "dependencies": {
+ "jsesc": "~0.5.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "node_modules/repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "dev": true,
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
+ "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "node_modules/reserved-words": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz",
+ "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=",
+ "dev": true
+ },
+ "node_modules/resolve": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz",
+ "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==",
+ "dev": true,
+ "dependencies": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "node_modules/resolve-alpn": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz",
+ "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==",
+ "dev": true
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+ "dev": true,
+ "dependencies": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
+ "node_modules/resq": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/resq/-/resq-1.10.0.tgz",
+ "integrity": "sha512-hCUd0xMalqtPDz4jXIqs0M5Wnv/LZXN8h7unFOo4/nvExT9dDPbhwd3udRxLlp0HgBnHcV009UlduE9NZi7A6w==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rfdc": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
+ "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==",
+ "dev": true
+ },
+ "node_modules/rgb-regex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
+ "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=",
+ "dev": true
+ },
+ "node_modules/rgb2hex": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.3.tgz",
+ "integrity": "sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ==",
+ "dev": true
+ },
+ "node_modules/rgba-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
+ "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
+ "dev": true
+ },
+ "node_modules/rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/roarr": {
+ "version": "2.15.4",
+ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
+ "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
+ "dev": true,
+ "dependencies": {
+ "boolean": "^3.0.1",
+ "detect-node": "^2.0.4",
+ "globalthis": "^1.0.1",
+ "json-stringify-safe": "^5.0.1",
+ "semver-compare": "^1.0.0",
+ "sprintf-js": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/roarr/node_modules/sprintf-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
+ },
+ "node_modules/rollup": {
+ "version": "0.67.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.67.4.tgz",
+ "integrity": "sha512-AVuP73mkb4BBMUmksQ3Jw0jTrBTU1i7rLiUYjFxLZGb3xiFmtVEg40oByphkZAsiL0bJC3hRAJUQos/e5EBd+w==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "0.0.39",
+ "@types/node": "*"
+ },
+ "bin": {
+ "rollup": "bin/rollup"
+ }
+ },
+ "node_modules/rollup-plugin-alias": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-alias/-/rollup-plugin-alias-1.5.2.tgz",
+ "integrity": "sha512-ODeZXhTxpD48sfcYLAFc1BGrsXKDj7o1CSNH3uYbdK3o0NxyMmaQPTNgW+ko+am92DLC8QSTe4kyxTuEkI5S5w==",
+ "dev": true,
+ "dependencies": {
+ "slash": "^3.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-babel": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz",
+ "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "rollup-pluginutils": "^2.8.1"
+ }
+ },
+ "node_modules/rollup-plugin-buble": {
+ "version": "0.19.8",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-buble/-/rollup-plugin-buble-0.19.8.tgz",
+ "integrity": "sha512-8J4zPk2DQdk3rxeZvxgzhHh/rm5nJkjwgcsUYisCQg1QbT5yagW+hehYEW7ZNns/NVbDCTv4JQ7h4fC8qKGOKw==",
+ "dev": true,
+ "dependencies": {
+ "buble": "^0.19.8",
+ "rollup-pluginutils": "^2.3.3"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-bundle-size/-/rollup-plugin-bundle-size-1.0.3.tgz",
+ "integrity": "sha512-aWj0Pvzq90fqbI5vN1IvUrlf4utOqy+AERYxwWjegH1G8PzheMnrRIgQ5tkwKVtQMDP0bHZEACW/zLDF+XgfXQ==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "maxmin": "^2.1.0"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-bundle-size/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-commonjs": {
+ "version": "9.3.4",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-9.3.4.tgz",
+ "integrity": "sha512-DTZOvRoiVIHHLFBCL4pFxOaJt8pagxsVldEXBOn6wl3/V21wVaj17HFfyzTsQUuou3sZL3lEJZVWKPFblJfI6w==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.0",
+ "magic-string": "^0.25.2",
+ "resolve": "^1.10.0",
+ "rollup-pluginutils": "^2.6.0"
+ }
+ },
+ "node_modules/rollup-plugin-es3": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-es3/-/rollup-plugin-es3-1.1.0.tgz",
+ "integrity": "sha512-jTMqQgMZ/tkjRW4scf4ln5c0OiTSi+Lx/IEyFd41ldgGoLvvg9AQxmVOl93+KaoyB7XRYToYjiHDvO40NPF/fA==",
+ "dev": true,
+ "dependencies": {
+ "magic-string": "^0.22.4"
+ }
+ },
+ "node_modules/rollup-plugin-es3/node_modules/magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "dev": true,
+ "dependencies": {
+ "vlq": "^0.2.2"
+ }
+ },
+ "node_modules/rollup-plugin-flow": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-flow/-/rollup-plugin-flow-1.1.1.tgz",
+ "integrity": "sha1-bOVo8d1Vlma3erdrS64lFAdSjbY=",
+ "dev": true,
+ "dependencies": {
+ "flow-remove-types": "^1.1.0",
+ "rollup-pluginutils": "^1.5.1"
+ }
+ },
+ "node_modules/rollup-plugin-flow/node_modules/estree-walker": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz",
+ "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=",
+ "dev": true
+ },
+ "node_modules/rollup-plugin-flow/node_modules/rollup-pluginutils": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz",
+ "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.2.1",
+ "minimatch": "^3.0.2"
+ }
+ },
+ "node_modules/rollup-plugin-json": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-3.1.0.tgz",
+ "integrity": "sha512-BlYk5VspvGpjz7lAwArVzBXR60JK+4EKtPkCHouAWg39obk9S61hZYJDBfMK+oitPdoe11i69TlxKlMQNFC/Uw==",
+ "dev": true,
+ "dependencies": {
+ "rollup-pluginutils": "^2.3.1"
+ }
+ },
+ "node_modules/rollup-plugin-node-resolve": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.2.4.tgz",
+ "integrity": "sha512-t/64I6l7fZ9BxqD3XlX4ZeO6+5RLKyfpwE2CiPNUKa+GocPlQhf/C208ou8y3AwtNsc6bjSk/8/6y/YAyxCIvw==",
+ "dev": true,
+ "dependencies": {
+ "@types/resolve": "0.0.8",
+ "builtin-modules": "^3.1.0",
+ "is-module": "^1.0.0",
+ "resolve": "^1.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-1.6.3.tgz",
+ "integrity": "sha512-se1qftVETua9ZGViud4A4gbgEQenjYnLPvjh3kTqbBZU+f0mQ9YvJptIuzPhEk5kZAHZhkwIkk2jk+byrn1XPA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.0.0",
+ "concat-with-sourcemaps": "^1.0.5",
+ "cssnano": "^3.10.0",
+ "fs-extra": "^5.0.0",
+ "import-cwd": "^2.1.0",
+ "p-queue": "^2.4.2",
+ "pify": "^3.0.0",
+ "postcss": "^6.0.21",
+ "postcss-load-config": "^1.2.0",
+ "postcss-modules": "^1.1.0",
+ "promise.series": "^0.2.0",
+ "reserved-words": "^0.1.2",
+ "resolve": "^1.5.0",
+ "rollup-pluginutils": "^2.0.1",
+ "style-inject": "^0.3.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/autoprefixer": {
+ "version": "6.7.7",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
+ "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^1.7.6",
+ "caniuse-db": "^1.0.30000634",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^5.2.16",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/autoprefixer/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/autoprefixer/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/autoprefixer/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "dev": true,
+ "dependencies": {
+ "caniuse-db": "^1.0.30000639",
+ "electron-to-chromium": "^1.2.7"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/caniuse-api": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
+ "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^1.3.6",
+ "caniuse-db": "^1.0.30000529",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/coa": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+ "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/cssnano": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
+ "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+ "dev": true,
+ "dependencies": {
+ "autoprefixer": "^6.3.1",
+ "decamelize": "^1.1.2",
+ "defined": "^1.0.0",
+ "has": "^1.0.1",
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.14",
+ "postcss-calc": "^5.2.0",
+ "postcss-colormin": "^2.1.8",
+ "postcss-convert-values": "^2.3.4",
+ "postcss-discard-comments": "^2.0.4",
+ "postcss-discard-duplicates": "^2.0.1",
+ "postcss-discard-empty": "^2.0.1",
+ "postcss-discard-overridden": "^0.1.1",
+ "postcss-discard-unused": "^2.2.1",
+ "postcss-filter-plugins": "^2.0.0",
+ "postcss-merge-idents": "^2.1.5",
+ "postcss-merge-longhand": "^2.0.1",
+ "postcss-merge-rules": "^2.0.3",
+ "postcss-minify-font-values": "^1.0.2",
+ "postcss-minify-gradients": "^1.0.1",
+ "postcss-minify-params": "^1.0.4",
+ "postcss-minify-selectors": "^2.0.4",
+ "postcss-normalize-charset": "^1.1.0",
+ "postcss-normalize-url": "^3.0.7",
+ "postcss-ordered-values": "^2.1.0",
+ "postcss-reduce-idents": "^2.2.2",
+ "postcss-reduce-initial": "^1.0.0",
+ "postcss-reduce-transforms": "^1.0.3",
+ "postcss-svgo": "^2.1.1",
+ "postcss-unique-selectors": "^2.0.2",
+ "postcss-value-parser": "^3.2.3",
+ "postcss-zindex": "^2.0.1"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/cssnano/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/cssnano/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/cssnano/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/csso": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
+ "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
+ "dev": true,
+ "dependencies": {
+ "clap": "^1.0.9",
+ "source-map": "^0.5.3"
+ },
+ "bin": {
+ "csso": "bin/csso"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/is-svg": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
+ "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
+ "dev": true,
+ "dependencies": {
+ "html-comment-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/js-yaml": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+ "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^2.6.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-calc": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
+ "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.2",
+ "postcss-message-helpers": "^2.0.0",
+ "reduce-css-calc": "^1.2.6"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-calc/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-calc/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-calc/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-colormin": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
+ "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
+ "dev": true,
+ "dependencies": {
+ "colormin": "^1.0.5",
+ "postcss": "^5.0.13",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-colormin/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-colormin/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-colormin/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-convert-values": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
+ "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.11",
+ "postcss-value-parser": "^3.1.2"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-convert-values/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-convert-values/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-convert-values/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-comments": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
+ "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.14"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-comments/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-comments/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-comments/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-duplicates": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
+ "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-duplicates/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-duplicates/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-duplicates/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-empty": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
+ "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.14"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-empty/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-empty/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-empty/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-overridden": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
+ "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.16"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-overridden/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-overridden/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-discard-overridden/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-longhand": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
+ "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-longhand/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-longhand/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-longhand/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-rules": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
+ "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^1.5.2",
+ "caniuse-api": "^1.5.2",
+ "postcss": "^5.0.4",
+ "postcss-selector-parser": "^2.2.2",
+ "vendors": "^1.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-rules/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-rules/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-merge-rules/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-font-values": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
+ "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-font-values/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-font-values/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-font-values/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-gradients": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
+ "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.12",
+ "postcss-value-parser": "^3.3.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-gradients/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-gradients/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-gradients/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-params": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
+ "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.2",
+ "postcss-value-parser": "^3.0.2",
+ "uniqs": "^2.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-params/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-params/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-params/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-selectors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
+ "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.2",
+ "has": "^1.0.1",
+ "postcss": "^5.0.14",
+ "postcss-selector-parser": "^2.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-selectors/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-selectors/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-minify-selectors/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-charset": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
+ "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.5"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-charset/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-charset/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-charset/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-url": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
+ "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
+ "dev": true,
+ "dependencies": {
+ "is-absolute-url": "^2.0.0",
+ "normalize-url": "^1.4.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-url/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-url/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-normalize-url/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-ordered-values": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
+ "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.1"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-ordered-values/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-ordered-values/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-ordered-values/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-initial": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
+ "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^5.0.4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-initial/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-initial/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-initial/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-transforms": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
+ "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.8",
+ "postcss-value-parser": "^3.0.1"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-transforms/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-transforms/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-reduce-transforms/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-selector-parser": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+ "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+ "dev": true,
+ "dependencies": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-svgo": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
+ "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
+ "dev": true,
+ "dependencies": {
+ "is-svg": "^2.0.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3",
+ "svgo": "^0.7.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-svgo/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-svgo/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-svgo/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-unique-selectors": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
+ "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+ "dev": true,
+ "dependencies": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-unique-selectors/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-unique-selectors/node_modules/chalk/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-unique-selectors/node_modules/postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/postcss/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/rollup-plugin-postcss/node_modules/svgo": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
+ "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
+ "dev": true,
+ "dependencies": {
+ "coa": "~1.0.1",
+ "colors": "~1.1.2",
+ "csso": "~2.3.1",
+ "js-yaml": "~3.7.0",
+ "mkdirp": "~0.5.1",
+ "sax": "~1.2.1",
+ "whet.extend": "~0.9.9"
+ },
+ "bin": {
+ "svgo": "bin/svgo"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-preserve-shebang": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-preserve-shebang/-/rollup-plugin-preserve-shebang-0.1.6.tgz",
+ "integrity": "sha512-b+psdlXZOjmlnKmL6/YAkR8PR15VPcUNXdT35urBRJ8jE6UxHyb4HXeeN3qRZJbMJJaX1eRP72XwH6IvGFh5Jw==",
+ "dev": true,
+ "dependencies": {
+ "magic-string": "^0.22.4"
+ }
+ },
+ "node_modules/rollup-plugin-preserve-shebang/node_modules/magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "dev": true,
+ "dependencies": {
+ "vlq": "^0.2.2"
+ }
+ },
+ "node_modules/rollup-plugin-sizes": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-sizes/-/rollup-plugin-sizes-0.4.2.tgz",
+ "integrity": "sha512-6VsnWb4aBPcW++3IBMNPo4NLSheoaXh+itXk1OcaolLhYemoQFb7A9hVNocwa0j2BctdmPNFcP7UJ3g///VVaA==",
+ "dev": true,
+ "dependencies": {
+ "filesize": "^3.5.11",
+ "lodash.foreach": "^4.5.0",
+ "lodash.sumby": "^4.6.0",
+ "module-details-from-path": "^1.0.3"
+ }
+ },
+ "node_modules/rollup-plugin-terser": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-3.0.0.tgz",
+ "integrity": "sha512-Ed9zRD7OoCBnh0XGlEAJle5TCUsFXMLClwKzZWnS1zbNO4MelHjfCSdFZxCAdH70M40nhZ1nRrY2GZQJhSMcjA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "jest-worker": "^23.2.0",
+ "serialize-javascript": "^1.5.0",
+ "terser": "^3.8.2"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2": {
+ "version": "0.19.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.19.3.tgz",
+ "integrity": "sha512-lsRqfBCZhMl/tq9AT5YnQvzQWzXtnx3EQYFcHD72gul7nyyoOrzx5yCEH20smpw58v6UkHHZz03FbdLEPoHWjA==",
+ "dev": true,
+ "dependencies": {
+ "fs-extra": "7.0.1",
+ "resolve": "1.8.1",
+ "rollup-pluginutils": "2.3.3",
+ "tslib": "1.9.3"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "dependencies": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/estree-walker": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz",
+ "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==",
+ "dev": true
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "dependencies": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/resolve": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+ "dev": true,
+ "dependencies": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/rollup-pluginutils": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.3.tgz",
+ "integrity": "sha512-2XZwja7b6P5q4RZ5FhyX1+f46xi1Z3qBKigLRZ6VTZjwbN0K1IFGMlwm06Uu0Emcre2Z63l77nq/pzn+KxIEoA==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.5.2",
+ "micromatch": "^2.3.11"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/tslib": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+ "dev": true
+ },
+ "node_modules/rollup-pluginutils": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+ "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.1"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "dev": true,
+ "dependencies": {
+ "is-promise": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
+ "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.9.0"
+ },
+ "engines": {
+ "npm": ">=2.0.0"
+ }
+ },
+ "node_modules/sade": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
+ "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==",
+ "dev": true,
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/saucelabs": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-4.6.0.tgz",
+ "integrity": "sha512-GAytkfq2QTVzwMS4/A99YQ79wqZvq29hO1r7+JYvfExRD9UipuvzvqhzsAfS8fKg+OuRIbIDTk0Rd7aWXa06zw==",
+ "dev": true,
+ "dependencies": {
+ "bin-wrapper": "^4.1.0",
+ "change-case": "^4.1.1",
+ "form-data": "^3.0.0",
+ "got": "^11.7.0",
+ "hash.js": "^1.1.7",
+ "tunnel": "0.0.6",
+ "yargs": "^16.0.3"
+ },
+ "bin": {
+ "sl": "bin/sl"
+ }
+ },
+ "node_modules/saucelabs/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/saucelabs/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/saucelabs/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/saucelabs/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/saucelabs/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/saucelabs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/saucelabs/node_modules/form-data": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
+ "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/saucelabs/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/saucelabs/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/saucelabs/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/saucelabs/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/saucelabs/node_modules/y18n": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
+ "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/saucelabs/node_modules/yargs": {
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz",
+ "integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/saucelabs/node_modules/yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ },
+ "node_modules/seek-bzip": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz",
+ "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^2.8.1"
+ },
+ "bin": {
+ "seek-bunzip": "bin/seek-bunzip",
+ "seek-table": "bin/seek-bzip-table"
+ }
+ },
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
+ "dev": true
+ },
+ "node_modules/semver-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
+ "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/semver-truncate": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz",
+ "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=",
+ "dev": true,
+ "dependencies": {
+ "semver": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sentence-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.3.tgz",
+ "integrity": "sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==",
+ "dev": true,
+ "dependencies": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case-first": "^2.0.1"
+ }
+ },
+ "node_modules/serialize-error": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
+ "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.13.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
+ "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
+ "dev": true
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "dev": true
+ },
+ "node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
+ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
+ "dev": true
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "dev": true
+ },
+ "node_modules/simple-get": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
+ "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+ "dev": true,
+ "dependencies": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "dev": true
+ },
+ "node_modules/sinon": {
+ "version": "9.2.3",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.3.tgz",
+ "integrity": "sha512-m+DyAWvqVHZtjnjX/nuShasykFeiZ+nPuEfD4G3gpvKGkXRhkF/6NSt2qN2FjZhfrcHXFzUzI+NLnk+42fnLEw==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^1.8.1",
+ "@sinonjs/fake-timers": "^6.0.1",
+ "@sinonjs/samsam": "^5.3.0",
+ "diff": "^4.0.2",
+ "nise": "^4.0.4",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "node_modules/sinon-chai": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz",
+ "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==",
+ "dev": true
+ },
+ "node_modules/sinon/node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/sinon/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sinon/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/snake-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz",
+ "integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==",
+ "dev": true,
+ "dependencies": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/socket.io": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
+ "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "~4.1.0",
+ "engine.io": "~3.4.0",
+ "has-binary2": "~1.0.2",
+ "socket.io-adapter": "~1.1.0",
+ "socket.io-client": "2.3.0",
+ "socket.io-parser": "~3.4.0"
+ }
+ },
+ "node_modules/socket.io-adapter": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
+ "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
+ "dev": true
+ },
+ "node_modules/socket.io-client": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
+ "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
+ "dev": true,
+ "dependencies": {
+ "backo2": "1.0.2",
+ "base64-arraybuffer": "0.1.5",
+ "component-bind": "1.0.0",
+ "component-emitter": "1.2.1",
+ "debug": "~4.1.0",
+ "engine.io-client": "~3.4.0",
+ "has-binary2": "~1.0.2",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "object-component": "0.0.3",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "socket.io-parser": "~3.3.0",
+ "to-array": "0.1.4"
+ }
+ },
+ "node_modules/socket.io-client/node_modules/base64-arraybuffer": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/socket.io-client/node_modules/component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "node_modules/socket.io-client/node_modules/isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ },
+ "node_modules/socket.io-client/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/socket.io-client/node_modules/socket.io-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.1.tgz",
+ "integrity": "sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ==",
+ "dev": true,
+ "dependencies": {
+ "component-emitter": "~1.3.0",
+ "debug": "~3.1.0",
+ "isarray": "2.0.1"
+ }
+ },
+ "node_modules/socket.io-client/node_modules/socket.io-parser/node_modules/component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "node_modules/socket.io-client/node_modules/socket.io-parser/node_modules/debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/socket.io-parser": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
+ "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
+ "dev": true,
+ "dependencies": {
+ "component-emitter": "1.2.1",
+ "debug": "~4.1.0",
+ "isarray": "2.0.1"
+ }
+ },
+ "node_modules/socket.io-parser/node_modules/component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "node_modules/socket.io-parser/node_modules/isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ },
+ "node_modules/sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "dev": true,
+ "dependencies": {
+ "is-plain-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sort-keys-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
+ "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
+ "dev": true,
+ "dependencies": {
+ "sort-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
+ "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "dev": true
+ },
+ "node_modules/spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "node_modules/sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stable": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+ "dev": true
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/streamroller": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz",
+ "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==",
+ "dev": true,
+ "dependencies": {
+ "date-format": "^2.1.0",
+ "debug": "^4.1.1",
+ "fs-extra": "^8.1.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/streamroller/node_modules/date-format": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
+ "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/streamroller/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string-argv": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
+ "node_modules/string-hash": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
+ "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "dependencies": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/string.prototype.padend": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
+ "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.4.3",
+ "function-bind": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
+ "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "node_modules/string.prototype.trimleft": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
+ "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimright": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz",
+ "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
+ "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "node_modules/stringify-object": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+ "dev": true,
+ "dependencies": {
+ "get-own-enumerable-property-symbols": "^3.0.0",
+ "is-obj": "^1.0.1",
+ "is-regexp": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-dirs": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz",
+ "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==",
+ "dev": true,
+ "dependencies": {
+ "is-natural-number": "^4.0.1"
+ }
+ },
+ "node_modules/strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/style-inject": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz",
+ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==",
+ "dev": true
+ },
+ "node_modules/stylehacks": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
+ "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/stylehacks/node_modules/postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "dependencies": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/svgo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
+ "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "coa": "^2.0.2",
+ "css-select": "^2.0.0",
+ "css-select-base-adapter": "^0.1.1",
+ "css-tree": "1.0.0-alpha.37",
+ "csso": "^4.0.2",
+ "js-yaml": "^3.13.1",
+ "mkdirp": "~0.5.1",
+ "object.values": "^1.1.0",
+ "sax": "~1.2.4",
+ "stable": "^0.1.8",
+ "unquote": "~1.1.1",
+ "util.promisify": "~1.0.0"
+ },
+ "bin": {
+ "svgo": "bin/svgo"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/table/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/table/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dev": true,
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
+ "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar-stream/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/terser": {
+ "version": "3.17.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
+ "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^2.19.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.10"
+ },
+ "bin": {
+ "terser": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/terser/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "node_modules/timed-out": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
+ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/timsort": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
+ "dev": true
+ },
+ "node_modules/tiny-glob": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.8.tgz",
+ "integrity": "sha512-vkQP7qOslq63XRX9kMswlby99kyO5OvKptw7AMwBVMjXEI7Tb61eoI5DydyEMOseyGS5anDN1VPoVxEvH01q8w==",
+ "dev": true,
+ "dependencies": {
+ "globalyzer": "0.1.0",
+ "globrex": "^0.1.2"
+ }
+ },
+ "node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "dependencies": {
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/to-array": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+ "dev": true
+ },
+ "node_modules/to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+ "dev": true
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tough-cookie/node_modules/punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "node_modules/trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
+ "dev": true
+ },
+ "node_modules/tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+ }
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dev": true,
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/ua-parser-js": {
+ "version": "0.7.22",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
+ "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+ "dev": true,
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^1.0.4",
+ "unicode-property-aliases-ecmascript": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz",
+ "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz",
+ "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "node_modules/uniqs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
+ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
+ "dev": true
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/unquote": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
+ "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
+ "dev": true
+ },
+ "node_modules/upper-case": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.1.tgz",
+ "integrity": "sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.1.tgz",
+ "integrity": "sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+ "dev": true,
+ "dependencies": {
+ "prepend-http": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/url-parse-lax/node_modules/prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/url-to-options": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz",
+ "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "node_modules/util.promisify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
+ "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.2",
+ "has-symbols": "^1.0.1",
+ "object.getownpropertydescriptors": "^2.1.0"
+ }
+ },
+ "node_modules/util.promisify/node_modules/es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "dependencies": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/util.promisify/node_modules/is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/util.promisify/node_modules/is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/util.promisify/node_modules/object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "node_modules/util.promisify/node_modules/object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
+ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
+ "dev": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/vendors": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
+ "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==",
+ "dev": true
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/vlq": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
+ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
+ "dev": true
+ },
+ "node_modules/void-elements": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/webdriver": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-6.10.4.tgz",
+ "integrity": "sha512-N2FkEy22QWAJMeyz1219ik9wyt3/SOT/RtsY6JheEriZ1GptzZyK0OibkOnCoaIAt+nvSxnSmTTlmXQMGBE6Mw==",
+ "dev": true,
+ "dependencies": {
+ "@types/lodash.merge": "^4.6.6",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/protocols": "6.10.0",
+ "@wdio/utils": "6.10.4",
+ "got": "^11.0.2",
+ "lodash.merge": "^4.6.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/webdriverio": {
+ "version": "6.10.5",
+ "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-6.10.5.tgz",
+ "integrity": "sha512-TLIKVOOM0Oszn2mLxZcMQk0vq1bOWpsZNXMxMtpBXKLvcOCLedftxotwh0o1LqRiq8ODiubJ/vNOLgCN/oLFJQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/archiver": "^5.1.0",
+ "@types/atob": "^2.1.2",
+ "@types/fs-extra": "^9.0.2",
+ "@types/lodash.clonedeep": "^4.5.6",
+ "@types/lodash.isplainobject": "^4.0.6",
+ "@types/puppeteer-core": "^2.0.0",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/repl": "6.10.4",
+ "@wdio/utils": "6.10.4",
+ "archiver": "^5.0.0",
+ "atob": "^2.1.2",
+ "css-shorthand-properties": "^1.1.1",
+ "css-value": "^0.0.1",
+ "devtools": "6.10.4",
+ "fs-extra": "^9.0.1",
+ "get-port": "^5.1.1",
+ "grapheme-splitter": "^1.0.2",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.isobject": "^3.0.2",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.zip": "^4.2.0",
+ "minimatch": "^3.0.4",
+ "puppeteer-core": "^5.1.0",
+ "resq": "^1.9.1",
+ "rgb2hex": "^0.2.0",
+ "serialize-error": "^7.0.0",
+ "webdriver": "6.10.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/webdriverio/node_modules/fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/webdriverio/node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "node_modules/webdriverio/node_modules/jsonfile/node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/webdriverio/node_modules/universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/whet.extend": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
+ "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "node_modules/which-pm-runs": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
+ "dev": true
+ },
+ "node_modules/wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/workerpool": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz",
+ "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "node_modules/write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "dependencies": {
+ "mkdirp": "^0.5.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ws": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
+ "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.3.0"
+ }
+ },
+ "node_modules/xmlhttprequest-ssl": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
+ "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "node_modules/yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ },
+ "node_modules/yaml": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
+ "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/camelcase": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/yargs/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "node_modules/yeast": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+ "dev": true
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/zip-stream": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.4.tgz",
+ "integrity": "sha512-a65wQ3h5gcQ/nQGWV1mSZCEzCML6EK/vyVPcrPNynySP1j3VBbQKh3nhC8CbORb+jfl2vXvh56Ul5odP1bAHqw==",
+ "dev": true,
+ "dependencies": {
+ "archiver-utils": "^2.1.0",
+ "compress-commons": "^4.0.2",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/zip-stream/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ }
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/core": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.4.tgz",
+ "integrity": "sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.7.4",
+ "@babel/helpers": "^7.7.4",
+ "@babel/parser": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz",
+ "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-annotate-as-pure": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz",
+ "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz",
+ "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-explode-assignable-expression": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-builder-react-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.4.tgz",
+ "integrity": "sha512-kvbfHJNN9dg4rkEM4xn1s8d1/h6TYNvajy9L1wx4qLn9HFg0IkTsQi4rfBe92nxrPUFcMsHoMV+8rU7MJb3fCA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4",
+ "esutils": "^2.0.0"
+ }
+ },
+ "@babel/helper-call-delegate": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz",
+ "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-create-class-features-plugin": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz",
+ "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.10.4"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
+ "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.5",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+ "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+ "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz",
+ "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz",
+ "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz",
+ "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/traverse": "^7.12.5",
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+ "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.11.0"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
+ "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
+ "dev": true
+ },
+ "@babel/template": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
+ "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/parser": "^7.12.7",
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.12.9",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
+ "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/generator": "^7.12.5",
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-split-export-declaration": "^7.11.0",
+ "@babel/parser": "^7.12.7",
+ "@babel/types": "^7.12.7",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.19"
+ }
+ },
+ "@babel/types": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
+ "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ }
+ }
+ },
+ "@babel/helper-create-regexp-features-plugin": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz",
+ "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-regex": "^7.4.4",
+ "regexpu-core": "^4.6.0"
+ }
+ },
+ "@babel/helper-define-map": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz",
+ "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-explode-assignable-expression": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz",
+ "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==",
+ "dev": true,
+ "requires": {
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz",
+ "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz",
+ "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-hoist-variables": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz",
+ "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz",
+ "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz",
+ "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz",
+ "integrity": "sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-simple-access": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz",
+ "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+ "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
+ "dev": true
+ },
+ "@babel/helper-regex": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz",
+ "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-remap-async-to-generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz",
+ "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-wrap-function": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz",
+ "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.7.4",
+ "@babel/helper-optimise-call-expression": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz",
+ "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz",
+ "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "dev": true
+ },
+ "@babel/helper-wrap-function": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz",
+ "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz",
+ "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
+ "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==",
+ "dev": true
+ },
+ "@babel/plugin-proposal-async-generator-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz",
+ "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.7.4",
+ "@babel/plugin-syntax-async-generators": "^7.7.4"
+ }
+ },
+ "@babel/plugin-proposal-class-properties": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.2.1.tgz",
+ "integrity": "sha512-/4FKFChkQ2Jgb8lBDsvFX496YTi7UWTetVgS8oJUpX1e/DlaoeEK57At27ug8Hu2zI2g8bzkJ+8k9qrHZRPGPA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-class-features-plugin": "^7.2.1",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-proposal-dynamic-import": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz",
+ "integrity": "sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.7.4"
+ }
+ },
+ "@babel/plugin-proposal-json-strings": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz",
+ "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-json-strings": "^7.7.4"
+ }
+ },
+ "@babel/plugin-proposal-object-rest-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz",
+ "integrity": "sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-object-rest-spread": "^7.7.4"
+ }
+ },
+ "@babel/plugin-proposal-optional-catch-binding": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz",
+ "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.7.4"
+ }
+ },
+ "@babel/plugin-proposal-unicode-property-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz",
+ "integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-async-generators": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz",
+ "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-dynamic-import": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz",
+ "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-json-strings": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz",
+ "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz",
+ "integrity": "sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz",
+ "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz",
+ "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-top-level-await": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz",
+ "integrity": "sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-arrow-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz",
+ "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-async-to-generator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz",
+ "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.7.4"
+ }
+ },
+ "@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz",
+ "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-block-scoping": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz",
+ "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/plugin-transform-classes": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz",
+ "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-define-map": "^7.7.4",
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-optimise-call-expression": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "globals": "^11.1.0"
+ }
+ },
+ "@babel/plugin-transform-computed-properties": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz",
+ "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-destructuring": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz",
+ "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-dotall-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz",
+ "integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-duplicate-keys": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz",
+ "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz",
+ "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-for-of": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz",
+ "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-function-name": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz",
+ "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz",
+ "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-member-expression-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz",
+ "integrity": "sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-modules-amd": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz",
+ "integrity": "sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-commonjs": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz",
+ "integrity": "sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-simple-access": "^7.7.4",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-systemjs": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz",
+ "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-umd": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz",
+ "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz",
+ "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4"
+ }
+ },
+ "@babel/plugin-transform-new-target": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz",
+ "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-object-super": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz",
+ "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.7.4"
+ }
+ },
+ "@babel/plugin-transform-parameters": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz",
+ "integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-call-delegate": "^7.7.4",
+ "@babel/helper-get-function-arity": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-property-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz",
+ "integrity": "sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-react-jsx": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.4.tgz",
+ "integrity": "sha512-LixU4BS95ZTEAZdPaIuyg/k8FiiqN9laQ0dMHB4MlpydHY53uQdWCUrwjLr5o6ilS6fAgZey4Q14XBjl5tL6xw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-builder-react-jsx": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-jsx": "^7.7.4"
+ }
+ },
+ "@babel/plugin-transform-react-jsx-source": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.7.4.tgz",
+ "integrity": "sha512-5ZU9FnPhqtHsOXxutRtXZAzoEJwDaP32QcobbMP1/qt7NYcsCNK8XgzJcJfoEr/ZnzVvUNInNjIW22Z6I8p9mg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-jsx": "^7.7.4"
+ }
+ },
+ "@babel/plugin-transform-regenerator": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz",
+ "integrity": "sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw==",
+ "dev": true,
+ "requires": {
+ "regenerator-transform": "^0.14.0"
+ }
+ },
+ "@babel/plugin-transform-reserved-words": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz",
+ "integrity": "sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-shorthand-properties": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz",
+ "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-spread": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz",
+ "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-sticky-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz",
+ "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-template-literals": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz",
+ "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-typeof-symbol": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz",
+ "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-unicode-regex": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz",
+ "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/polyfill": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
+ "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.6.5",
+ "regenerator-runtime": "^0.13.4"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.13.7",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/preset-env": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.4.tgz",
+ "integrity": "sha512-Dg+ciGJjwvC1NIe/DGblMbcGq1HOtKbw8RLl4nIjlfcILKEOkWT/vRqPpumswABEBVudii6dnVwrBtzD7ibm4g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.7.4",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.7.4",
+ "@babel/plugin-proposal-dynamic-import": "^7.7.4",
+ "@babel/plugin-proposal-json-strings": "^7.7.4",
+ "@babel/plugin-proposal-object-rest-spread": "^7.7.4",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.7.4",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.7.4",
+ "@babel/plugin-syntax-async-generators": "^7.7.4",
+ "@babel/plugin-syntax-dynamic-import": "^7.7.4",
+ "@babel/plugin-syntax-json-strings": "^7.7.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.7.4",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.7.4",
+ "@babel/plugin-syntax-top-level-await": "^7.7.4",
+ "@babel/plugin-transform-arrow-functions": "^7.7.4",
+ "@babel/plugin-transform-async-to-generator": "^7.7.4",
+ "@babel/plugin-transform-block-scoped-functions": "^7.7.4",
+ "@babel/plugin-transform-block-scoping": "^7.7.4",
+ "@babel/plugin-transform-classes": "^7.7.4",
+ "@babel/plugin-transform-computed-properties": "^7.7.4",
+ "@babel/plugin-transform-destructuring": "^7.7.4",
+ "@babel/plugin-transform-dotall-regex": "^7.7.4",
+ "@babel/plugin-transform-duplicate-keys": "^7.7.4",
+ "@babel/plugin-transform-exponentiation-operator": "^7.7.4",
+ "@babel/plugin-transform-for-of": "^7.7.4",
+ "@babel/plugin-transform-function-name": "^7.7.4",
+ "@babel/plugin-transform-literals": "^7.7.4",
+ "@babel/plugin-transform-member-expression-literals": "^7.7.4",
+ "@babel/plugin-transform-modules-amd": "^7.7.4",
+ "@babel/plugin-transform-modules-commonjs": "^7.7.4",
+ "@babel/plugin-transform-modules-systemjs": "^7.7.4",
+ "@babel/plugin-transform-modules-umd": "^7.7.4",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4",
+ "@babel/plugin-transform-new-target": "^7.7.4",
+ "@babel/plugin-transform-object-super": "^7.7.4",
+ "@babel/plugin-transform-parameters": "^7.7.4",
+ "@babel/plugin-transform-property-literals": "^7.7.4",
+ "@babel/plugin-transform-regenerator": "^7.7.4",
+ "@babel/plugin-transform-reserved-words": "^7.7.4",
+ "@babel/plugin-transform-shorthand-properties": "^7.7.4",
+ "@babel/plugin-transform-spread": "^7.7.4",
+ "@babel/plugin-transform-sticky-regex": "^7.7.4",
+ "@babel/plugin-transform-template-literals": "^7.7.4",
+ "@babel/plugin-transform-typeof-symbol": "^7.7.4",
+ "@babel/plugin-transform-unicode-regex": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "browserslist": "^4.6.0",
+ "core-js-compat": "^3.1.1",
+ "invariant": "^2.2.2",
+ "js-levenshtein": "^1.1.3",
+ "semver": "^5.5.0"
+ }
+ },
+ "@babel/register": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.7.4.tgz",
+ "integrity": "sha512-/fmONZqL6ZMl9KJUYajetCrID6m0xmL4odX7v+Xvoxcv0DdbP/oO0TWIeLUCHqczQ6L6njDMqmqHFy2cp3FFsA==",
+ "dev": true,
+ "requires": {
+ "find-cache-dir": "^2.0.0",
+ "lodash": "^4.17.13",
+ "make-dir": "^2.1.0",
+ "pirates": "^4.0.0",
+ "source-map-support": "^0.5.16"
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz",
+ "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.2"
+ }
+ },
+ "@babel/template": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz",
+ "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz",
+ "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.5.5",
+ "@babel/generator": "^7.7.4",
+ "@babel/helper-function-name": "^7.7.4",
+ "@babel/helper-split-export-declaration": "^7.7.4",
+ "@babel/parser": "^7.7.4",
+ "@babel/types": "^7.7.4",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/types": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz",
+ "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@istanbuljs/load-nyc-config": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz",
+ "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ }
+ }
+ },
+ "@istanbuljs/schema": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
+ "dev": true
+ },
+ "@sindresorhus/is": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
+ "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
+ "dev": true
+ },
+ "@sinonjs/commons": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
+ "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
+ "dev": true,
+ "requires": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "@sinonjs/fake-timers": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
+ "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+ "dev": true,
+ "requires": {
+ "@sinonjs/commons": "^1.7.0"
+ }
+ },
+ "@sinonjs/samsam": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.0.tgz",
+ "integrity": "sha512-hXpcfx3aq+ETVBwPlRFICld5EnrkexXuXDwqUNhDdr5L8VjvMeSRwyOa0qL7XFmR+jVWR4rUZtnxlG7RX72sBg==",
+ "dev": true,
+ "requires": {
+ "@sinonjs/commons": "^1.6.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
+ },
+ "@sinonjs/text-encoding": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
+ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
+ "dev": true
+ },
+ "@szmarczak/http-timer": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
+ "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
+ "dev": true,
+ "requires": {
+ "defer-to-connect": "^2.0.0"
+ }
+ },
+ "@types/archiver": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.1.0.tgz",
+ "integrity": "sha512-baFOhanb/hxmcOd1Uey2TfFg43kTSmM6py1Eo7Rjbv/ivcl7PXLhY0QgXGf50Hx/eskGCFqPfhs/7IZLb15C5g==",
+ "dev": true,
+ "requires": {
+ "@types/glob": "*"
+ }
+ },
+ "@types/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@types/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-8GAYQ1jDRUQkSpHzJUqXwAkYFOxuWAOGLhIR4aPd/Y/yL12Q/9m7LsKpHKlfKdNE/362Hc9wPI1Yh6opDfxVJg==",
+ "dev": true
+ },
+ "@types/cacheable-request": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
+ "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==",
+ "dev": true,
+ "requires": {
+ "@types/http-cache-semantics": "*",
+ "@types/keyv": "*",
+ "@types/node": "*",
+ "@types/responselike": "*"
+ }
+ },
+ "@types/chai": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.5.tgz",
+ "integrity": "sha512-YvbLiIc0DbbhiANrfVObdkLEHJksQZVq0Uvfg550SRAKVYaEJy+V70j65BVe2WNp6E3HtKsUczeijHFCjba3og==",
+ "dev": true
+ },
+ "@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
+ "@types/fs-extra": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.4.tgz",
+ "integrity": "sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/http-cache-semantics": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
+ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==",
+ "dev": true
+ },
+ "@types/keyv": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
+ "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/lodash": {
+ "version": "4.14.165",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz",
+ "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==",
+ "dev": true
+ },
+ "@types/lodash.clonedeep": {
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz",
+ "integrity": "sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA==",
+ "dev": true,
+ "requires": {
+ "@types/lodash": "*"
+ }
+ },
+ "@types/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-8G41YFhmOl8Ck6NrwLK5hhnbz6ADfuDJP+zusDnX3PoYhfC60+H/rQE6zmdO4yFzPCPJPY4oGZK2spbXm6gYEA==",
+ "dev": true,
+ "requires": {
+ "@types/lodash": "*"
+ }
+ },
+ "@types/lodash.merge": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.6.tgz",
+ "integrity": "sha512-IB90krzMf7YpfgP3u/EvZEdXVvm4e3gJbUvh5ieuI+o+XqiNEt6fCzqNRaiLlPVScLI59RxIGZMQ3+Ko/DJ8vQ==",
+ "dev": true,
+ "requires": {
+ "@types/lodash": "*"
+ }
+ },
+ "@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+ "dev": true
+ },
+ "@types/mocha": {
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
+ "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "14.14.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
+ "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==",
+ "dev": true
+ },
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "@types/puppeteer": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.0.tgz",
+ "integrity": "sha512-zTYDLjnHjgzokrwKt7N0rgn7oZPYo1J0m8Ghu+gXqzLCEn8RWbELa2uprE2UFJ0jU/Sk0x9jXXdOH/5QQLFHhQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/puppeteer-core": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/puppeteer-core/-/puppeteer-core-2.0.0.tgz",
+ "integrity": "sha512-JvoEb7KgEkUet009ZDrtpUER3hheXoHgQByuYpJZ5WWT7LWwMH+0NTqGQXGgoOKzs+G5NA1T4DZwXK79Bhnejw==",
+ "dev": true,
+ "requires": {
+ "@types/puppeteer": "*"
+ }
+ },
+ "@types/q": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+ "dev": true
+ },
+ "@types/resolve": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
+ "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/responselike": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
+ "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/ua-parser-js": {
+ "version": "0.7.33",
+ "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
+ "integrity": "sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==",
+ "dev": true
+ },
+ "@types/uuid": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz",
+ "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==",
+ "dev": true
+ },
+ "@types/yauzl": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
+ "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@ungap/promise-all-settled": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "dev": true
+ },
+ "@wdio/config": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.10.4.tgz",
+ "integrity": "sha512-M22EunI+n/mmYOQqb9+BTVRqrfmPw+7rR1AHeD36vOXCnZ55Nrl4ZU4d6QzPHp9cLdMZqV786iDmkonnb6jb8w==",
+ "dev": true,
+ "requires": {
+ "@wdio/logger": "6.10.4",
+ "deepmerge": "^4.0.0",
+ "glob": "^7.1.2"
+ }
+ },
+ "@wdio/logger": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.10.4.tgz",
+ "integrity": "sha512-I+1I/5CtQigy59QJen56PHuwV0yiQdnZaOxmXIP6FzpWkeXLjcoUNaCRDuKwJx5GKrUSDqmGlMWSH53scwwzHg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0",
+ "loglevel": "^1.6.0",
+ "loglevel-plugin-prefix": "^0.8.4",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@wdio/protocols": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-6.10.0.tgz",
+ "integrity": "sha512-MaloMFtlZeeGoqHyy2g5QM8HHuQDZOAGjxotsQ6mVAzZpAFbwUGHPSRlwBbbsB3gHVALJVowViltJ95jgaFfZg==",
+ "dev": true
+ },
+ "@wdio/repl": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-6.10.4.tgz",
+ "integrity": "sha512-VwucPyUqAxU6CWWoEVf14asjtLGTgyaJwp47kEFegr06ZBG43zVQ6JqKFiGDxUJ+fZVRhdd7nRVHd+6UllK18w==",
+ "dev": true,
+ "requires": {
+ "@wdio/utils": "6.10.4"
+ }
+ },
+ "@wdio/utils": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-6.10.4.tgz",
+ "integrity": "sha512-DkFguYGKUcv9TmIYuuwS/pxpiGcgyv8gWUWRXffirt2OYpFXJNwB+S96CSQnjgb4B5MqSFgEti+gl8A2wsdDgQ==",
+ "dev": true,
+ "requires": {
+ "@wdio/logger": "6.10.4"
+ }
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "acorn": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+ "dev": true
+ },
+ "acorn-dynamic-import": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
+ "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==",
+ "dev": true
+ },
+ "after": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+ "dev": true
+ },
+ "agent-base": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true
+ },
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "alphanum-sort": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
+ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
+ "dev": true
+ },
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "arch": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
+ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
+ "dev": true
+ },
+ "archive-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz",
+ "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=",
+ "dev": true,
+ "requires": {
+ "file-type": "^4.2.0"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
+ "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=",
+ "dev": true
+ }
+ }
+ },
+ "archiver": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.1.0.tgz",
+ "integrity": "sha512-iKuQUP1nuKzBC2PFlGet5twENzCfyODmvkxwDV0cEFXavwcLrIW5ssTuHi9dyTPvpWr6Faweo2eQaQiLIwyXTA==",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^2.1.0",
+ "async": "^3.2.0",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.0.0",
+ "tar-stream": "^2.1.4",
+ "zip-stream": "^4.0.4"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "archiver-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.difference": "^4.5.0",
+ "lodash.flatten": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.union": "^4.6.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dev": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "array-includes": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
+ "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.7.0"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
+ "arraybuffer.slice": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
+ "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
+ "dev": true
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ },
+ "assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true
+ },
+ "async": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+ "dev": true
+ },
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "asyncro": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/asyncro/-/asyncro-3.0.0.tgz",
+ "integrity": "sha512-nEnWYfrBmA3taTiuiOoZYmgJ/CNrSoQLeLs29SeLcPu60yaw/mHDBHV0iOZ051fTvsTHxpCY+gXibqT9wbQYfg==",
+ "dev": true
+ },
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "autoprefixer": {
+ "version": "9.8.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
+ "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.12.0",
+ "caniuse-lite": "^1.0.30001109",
+ "colorette": "^1.2.1",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.32",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "4.14.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz",
+ "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001157",
+ "colorette": "^1.2.1",
+ "electron-to-chromium": "^1.3.591",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.66"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001163",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001163.tgz",
+ "integrity": "sha512-QQbOGkHWnvhn3Dlf4scPlXTZVhGOK+2qCOP5gPxqzXHhtn3tZHwNdH9qNcQRWN0f3tDYrsyXFJCFiP/GLzI5Vg==",
+ "dev": true
+ },
+ "electron-to-chromium": {
+ "version": "1.3.611",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.611.tgz",
+ "integrity": "sha512-YhqTzCXtEO2h0foGLGS60ortd6yY/yUQhqDEp1VWG3DIyHvckFFyaRwR41M0/M3m7Yb8Exqh+nzyb2TuxaoMTw==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "1.1.67",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
+ "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==",
+ "dev": true
+ }
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true
+ },
+ "aws4": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
+ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==",
+ "dev": true
+ },
+ "babel-eslint": {
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz",
+ "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/traverse": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "eslint-scope": "3.7.1",
+ "eslint-visitor-keys": "^1.0.0"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz",
+ "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "7.0.0-beta.44"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "7.0.0-beta.44",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.2.0",
+ "source-map": "^0.5.0",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz",
+ "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "7.0.0-beta.44",
+ "@babel/template": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz",
+ "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz",
+ "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "7.0.0-beta.44"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz",
+ "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.0"
+ }
+ },
+ "@babel/template": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz",
+ "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "lodash": "^4.2.0"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz",
+ "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.0.0-beta.44",
+ "@babel/generator": "7.0.0-beta.44",
+ "@babel/helper-function-name": "7.0.0-beta.44",
+ "@babel/helper-split-export-declaration": "7.0.0-beta.44",
+ "@babel/types": "7.0.0-beta.44",
+ "babylon": "7.0.0-beta.44",
+ "debug": "^3.1.0",
+ "globals": "^11.1.0",
+ "invariant": "^2.2.0",
+ "lodash": "^4.2.0"
+ }
+ },
+ "@babel/types": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.2.0",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "eslint-scope": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ }
+ }
+ },
+ "babel-plugin-dynamic-import-node": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz",
+ "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==",
+ "dev": true,
+ "requires": {
+ "object.assign": "^4.1.0"
+ }
+ },
+ "babel-plugin-istanbul": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz",
+ "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-instrument": "^4.0.0",
+ "test-exclude": "^6.0.0"
+ }
+ },
+ "babel-plugin-transform-async-to-promises": {
+ "version": "0.8.15",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-promises/-/babel-plugin-transform-async-to-promises-0.8.15.tgz",
+ "integrity": "sha512-fDXP68ZqcinZO2WCiimCL9zhGjGXOnn3D33zvbh+yheZ/qOrNVVDDIBtAaM3Faz8TRvQzHiRKsu3hfrBAhEncQ==",
+ "dev": true
+ },
+ "babel-plugin-transform-rename-properties": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-rename-properties/-/babel-plugin-transform-rename-properties-0.1.0.tgz",
+ "integrity": "sha512-uBSvAC8qH81TsXsWYD20ME4qg9ICflMLjsNfeuSxrKkJkym4Riqne1BrCCW15lcM/t9lfEiz4FJbVeUoaOVGWA==",
+ "dev": true
+ },
+ "babylon": {
+ "version": "7.0.0-beta.44",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+ "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
+ "dev": true
+ },
+ "backo2": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base64-arraybuffer": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
+ "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+ "dev": true
+ },
+ "base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "benchmark": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
+ "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.4",
+ "platform": "^1.3.3"
+ }
+ },
+ "better-assert": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+ "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+ "dev": true,
+ "requires": {
+ "callsite": "1.0.0"
+ }
+ },
+ "big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "dev": true
+ },
+ "bin-check": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz",
+ "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==",
+ "dev": true,
+ "requires": {
+ "execa": "^0.7.0",
+ "executable": "^4.1.0"
+ }
+ },
+ "bin-version": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz",
+ "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==",
+ "dev": true,
+ "requires": {
+ "execa": "^1.0.0",
+ "find-versions": "^3.0.0"
+ },
+ "dependencies": {
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ }
+ }
+ },
+ "bin-version-check": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz",
+ "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==",
+ "dev": true,
+ "requires": {
+ "bin-version": "^3.0.0",
+ "semver": "^5.6.0",
+ "semver-truncate": "^1.1.2"
+ }
+ },
+ "bin-wrapper": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz",
+ "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==",
+ "dev": true,
+ "requires": {
+ "bin-check": "^4.1.0",
+ "bin-version-check": "^4.0.0",
+ "download": "^7.1.0",
+ "import-lazy": "^3.1.0",
+ "os-filter-obj": "^2.0.0",
+ "pify": "^4.0.1"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+ "dev": true
+ },
+ "bl": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
+ "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "blob": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
+ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
+ "dev": true
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": true
+ }
+ }
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+ "dev": true
+ },
+ "boolean": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz",
+ "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "brotli-size": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-0.0.3.tgz",
+ "integrity": "sha512-bBIdd8uUGxKGldAVykxOqPegl+HlIm4FpXJamwWw5x77WCE8jO7AhXFE1YXOhOB28gS+2pTQete0FqRE6U5hQQ==",
+ "dev": true,
+ "requires": {
+ "duplexer": "^0.1.1",
+ "iltorb": "^2.0.5"
+ }
+ },
+ "browser-stdout": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+ "dev": true
+ },
+ "browserslist": {
+ "version": "4.7.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.3.tgz",
+ "integrity": "sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001010",
+ "electron-to-chromium": "^1.3.306",
+ "node-releases": "^1.1.40"
+ }
+ },
+ "buble": {
+ "version": "0.19.8",
+ "resolved": "https://registry.npmjs.org/buble/-/buble-0.19.8.tgz",
+ "integrity": "sha512-IoGZzrUTY5fKXVkgGHw3QeXFMUNBFv+9l8a4QJKG1JhG3nCMHTdEX1DCOg8568E2Q9qvAQIiSokv6Jsgx8p2cA==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.1.1",
+ "acorn-dynamic-import": "^4.0.0",
+ "acorn-jsx": "^5.0.1",
+ "chalk": "^2.4.2",
+ "magic-string": "^0.25.3",
+ "minimist": "^1.2.0",
+ "os-homedir": "^2.0.0",
+ "regexpu-core": "^4.5.4"
+ }
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dev": true,
+ "requires": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "dev": true
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true
+ },
+ "buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "builtin-modules": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
+ "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true
+ },
+ "cacheable-lookup": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz",
+ "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==",
+ "dev": true
+ },
+ "cacheable-request": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
+ "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=",
+ "dev": true,
+ "requires": {
+ "clone-response": "1.0.2",
+ "get-stream": "3.0.0",
+ "http-cache-semantics": "3.8.1",
+ "keyv": "3.0.0",
+ "lowercase-keys": "1.0.0",
+ "normalize-url": "2.0.1",
+ "responselike": "1.0.2"
+ },
+ "dependencies": {
+ "lowercase-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
+ "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz",
+ "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==",
+ "dev": true,
+ "requires": {
+ "prepend-http": "^2.0.0",
+ "query-string": "^5.0.1",
+ "sort-keys": "^2.0.0"
+ }
+ },
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true
+ },
+ "query-string": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
+ "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
+ "dev": true,
+ "requires": {
+ "decode-uri-component": "^0.2.0",
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "sort-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
+ "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ }
+ }
+ },
+ "call-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
+ "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.0"
+ }
+ },
+ "caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "dev": true,
+ "requires": {
+ "callsites": "^2.0.0"
+ },
+ "dependencies": {
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true
+ }
+ }
+ },
+ "caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "dev": true,
+ "requires": {
+ "caller-callsite": "^2.0.0"
+ }
+ },
+ "callsite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+ "dev": true
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camel-case": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
+ "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
+ "dev": true,
+ "requires": {
+ "pascal-case": "^3.1.1",
+ "tslib": "^1.10.0"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "caniuse-api": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
+ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "caniuse-lite": "^1.0.0",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
+ "caniuse-db": {
+ "version": "1.0.30001012",
+ "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001012.tgz",
+ "integrity": "sha512-fm4VZQo0F1WYTmJcaTsqGhRuqcbkUW1/1hx8n5xdkbJSyaJV3jZ1vPXHYNcn376cAcuhxUIcE9TpHlSAYtN6bA==",
+ "dev": true
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001012",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz",
+ "integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==",
+ "dev": true
+ },
+ "capital-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.3.tgz",
+ "integrity": "sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case-first": "^2.0.1"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "caw": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz",
+ "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==",
+ "dev": true,
+ "requires": {
+ "get-proxy": "^2.0.0",
+ "isurl": "^1.0.0-alpha5",
+ "tunnel-agent": "^0.6.0",
+ "url-to-options": "^1.0.1"
+ }
+ },
+ "chai": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
+ "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
+ "dev": true,
+ "requires": {
+ "assertion-error": "^1.1.0",
+ "check-error": "^1.0.2",
+ "deep-eql": "^3.0.1",
+ "get-func-name": "^2.0.0",
+ "pathval": "^1.1.0",
+ "type-detect": "^4.0.5"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "change-case": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.1.tgz",
+ "integrity": "sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==",
+ "dev": true,
+ "requires": {
+ "camel-case": "^4.1.1",
+ "capital-case": "^1.0.3",
+ "constant-case": "^3.0.3",
+ "dot-case": "^3.0.3",
+ "header-case": "^2.0.3",
+ "no-case": "^3.0.3",
+ "param-case": "^3.0.3",
+ "pascal-case": "^3.1.1",
+ "path-case": "^3.0.3",
+ "sentence-case": "^3.0.3",
+ "snake-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "dev": true
+ },
+ "check-export-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/check-export-map/-/check-export-map-1.0.1.tgz",
+ "integrity": "sha512-6nJK5v9fiUQjAACrLyVlIm8UlAak5zdvYxJhpl0zYa7IqUElInMU6lRL/+rTHjEmy+hbkn5Wphq4Rj9cRkEbqg==",
+ "dev": true,
+ "requires": {
+ "kolorist": "^1.2.3",
+ "mri": "^1.1.6"
+ }
+ },
+ "chokidar": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
+ "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.1.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ }
+ },
+ "chownr": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
+ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
+ "dev": true
+ },
+ "chrome-launcher": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz",
+ "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "escape-string-regexp": "^1.0.5",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^0.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "clap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+ "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "requires": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ }
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
+ },
+ "clone-response": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ },
+ "dependencies": {
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true
+ }
+ }
+ },
+ "coa": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
+ "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
+ "dev": true,
+ "requires": {
+ "@types/q": "^1.5.1",
+ "chalk": "^2.4.1",
+ "q": "^1.1.2"
+ }
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
+ "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.1",
+ "color-string": "^1.5.4"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "color-string": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz",
+ "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==",
+ "dev": true,
+ "requires": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "colorette": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+ "dev": true
+ },
+ "colormin": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
+ "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
+ "dev": true,
+ "requires": {
+ "color": "^0.11.0",
+ "css-color-names": "0.0.4",
+ "has": "^1.0.1"
+ },
+ "dependencies": {
+ "color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "color-string": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
+ "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
+ "dev": true,
+ "requires": {
+ "color-name": "^1.0.0"
+ }
+ }
+ }
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "dev": true
+ },
+ "compare-versions": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
+ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
+ "dev": true
+ },
+ "component-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "component-inherit": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+ "dev": true
+ },
+ "compress-commons": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.2.tgz",
+ "integrity": "sha512-qhd32a9xgzmpfoga1VQEiLEwdKZ6Plnpx5UCgIsf89FSolyJ7WnifY4Gtjgv5WR6hWAyRaHxC5MiEhU/38U70A==",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "^0.2.13",
+ "crc32-stream": "^4.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-with-sourcemaps": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+ "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "config-chain": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
+ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "constant-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.3.tgz",
+ "integrity": "sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case": "^2.0.1"
+ }
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true
+ },
+ "core-js": {
+ "version": "2.6.10",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
+ "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
+ "dev": true
+ },
+ "core-js-compat": {
+ "version": "3.4.5",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.5.tgz",
+ "integrity": "sha512-rYVvzvKJDKoefdAC+q6VP63vp5hMmeVONCi9pVUbU1qRrtVrmAk/nPhnRg+i+XFd775m1hpG2Yd5RY3X45ccuw==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.7.3",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "dependencies": {
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "dev": true,
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true
+ }
+ }
+ },
+ "coveralls": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz",
+ "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==",
+ "dev": true,
+ "requires": {
+ "js-yaml": "^3.13.1",
+ "lcov-parse": "^1.0.0",
+ "log-driver": "^1.2.7",
+ "minimist": "^1.2.0",
+ "request": "^2.88.0"
+ }
+ },
+ "crc-32": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
+ "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
+ "dev": true,
+ "requires": {
+ "exit-on-epipe": "~1.0.1",
+ "printj": "~1.1.0"
+ }
+ },
+ "crc32-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.1.tgz",
+ "integrity": "sha512-FN5V+weeO/8JaXsamelVYO1PHyeCsuL3HcG4cqsj0ceARcocxalaShCsohZMSAF+db7UYFwBy1rARK/0oFItUw==",
+ "dev": true,
+ "requires": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^3.4.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "cross-env": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
+ "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.1"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "css-color-names": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
+ "dev": true
+ },
+ "css-declaration-sorter": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz",
+ "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.1",
+ "timsort": "^0.3.0"
+ }
+ },
+ "css-modules-loader-core": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz",
+ "integrity": "sha1-WQhmgpShvs0mGuCkziGwtVHyHRY=",
+ "dev": true,
+ "requires": {
+ "icss-replace-symbols": "1.1.0",
+ "postcss": "6.0.1",
+ "postcss-modules-extract-imports": "1.1.0",
+ "postcss-modules-local-by-default": "1.2.0",
+ "postcss-modules-scope": "1.1.0",
+ "postcss-modules-values": "1.3.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.1.tgz",
+ "integrity": "sha1-AA29H47vIXqjaLmiEsX8QLKo8/I=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "css-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
+ "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
+ "dev": true,
+ "requires": {
+ "boolbase": "^1.0.0",
+ "css-what": "^3.2.1",
+ "domutils": "^1.7.0",
+ "nth-check": "^1.0.2"
+ }
+ },
+ "css-select-base-adapter": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
+ "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
+ "dev": true
+ },
+ "css-selector-tokenizer": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+ "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "css-shorthand-properties": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz",
+ "integrity": "sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==",
+ "dev": true
+ },
+ "css-tree": {
+ "version": "1.0.0-alpha.37",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
+ "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
+ "dev": true,
+ "requires": {
+ "mdn-data": "2.0.4",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "css-value": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz",
+ "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=",
+ "dev": true
+ },
+ "css-what": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
+ "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
+ "dev": true
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "cssnano": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
+ "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^5.0.0",
+ "cssnano-preset-default": "^4.0.7",
+ "is-resolvable": "^1.0.0",
+ "postcss": "^7.0.0"
+ }
+ },
+ "cssnano-preset-default": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz",
+ "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==",
+ "dev": true,
+ "requires": {
+ "css-declaration-sorter": "^4.0.1",
+ "cssnano-util-raw-cache": "^4.0.1",
+ "postcss": "^7.0.0",
+ "postcss-calc": "^7.0.1",
+ "postcss-colormin": "^4.0.3",
+ "postcss-convert-values": "^4.0.1",
+ "postcss-discard-comments": "^4.0.2",
+ "postcss-discard-duplicates": "^4.0.2",
+ "postcss-discard-empty": "^4.0.1",
+ "postcss-discard-overridden": "^4.0.1",
+ "postcss-merge-longhand": "^4.0.11",
+ "postcss-merge-rules": "^4.0.3",
+ "postcss-minify-font-values": "^4.0.2",
+ "postcss-minify-gradients": "^4.0.2",
+ "postcss-minify-params": "^4.0.2",
+ "postcss-minify-selectors": "^4.0.2",
+ "postcss-normalize-charset": "^4.0.1",
+ "postcss-normalize-display-values": "^4.0.2",
+ "postcss-normalize-positions": "^4.0.2",
+ "postcss-normalize-repeat-style": "^4.0.2",
+ "postcss-normalize-string": "^4.0.2",
+ "postcss-normalize-timing-functions": "^4.0.2",
+ "postcss-normalize-unicode": "^4.0.1",
+ "postcss-normalize-url": "^4.0.1",
+ "postcss-normalize-whitespace": "^4.0.2",
+ "postcss-ordered-values": "^4.1.2",
+ "postcss-reduce-initial": "^4.0.3",
+ "postcss-reduce-transforms": "^4.0.2",
+ "postcss-svgo": "^4.0.2",
+ "postcss-unique-selectors": "^4.0.1"
+ }
+ },
+ "cssnano-util-get-arguments": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
+ "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=",
+ "dev": true
+ },
+ "cssnano-util-get-match": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
+ "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=",
+ "dev": true
+ },
+ "cssnano-util-raw-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz",
+ "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "cssnano-util-same-parent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz",
+ "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==",
+ "dev": true
+ },
+ "csso": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
+ "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+ "dev": true,
+ "requires": {
+ "css-tree": "^1.1.2"
+ },
+ "dependencies": {
+ "css-tree": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz",
+ "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==",
+ "dev": true,
+ "requires": {
+ "mdn-data": "2.0.14",
+ "source-map": "^0.6.1"
+ }
+ },
+ "mdn-data": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "csstype": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz",
+ "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==",
+ "dev": true
+ },
+ "custom-event": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
+ "dev": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "date-format": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
+ "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "decompress": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz",
+ "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.0.0",
+ "decompress-tarbz2": "^4.0.0",
+ "decompress-targz": "^4.0.0",
+ "decompress-unzip": "^4.0.1",
+ "graceful-fs": "^4.1.10",
+ "make-dir": "^1.0.0",
+ "pify": "^2.3.0",
+ "strip-dirs": "^2.0.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ }
+ }
+ },
+ "decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^2.0.0"
+ }
+ },
+ "decompress-tar": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
+ "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
+ "dev": true,
+ "requires": {
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0",
+ "tar-stream": "^1.5.2"
+ },
+ "dependencies": {
+ "bl": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
+ "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true
+ },
+ "tar-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+ "dev": true,
+ "requires": {
+ "bl": "^1.0.0",
+ "buffer-alloc": "^1.2.0",
+ "end-of-stream": "^1.0.0",
+ "fs-constants": "^1.0.0",
+ "readable-stream": "^2.3.0",
+ "to-buffer": "^1.1.1",
+ "xtend": "^4.0.0"
+ }
+ }
+ }
+ },
+ "decompress-tarbz2": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz",
+ "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.1.0",
+ "file-type": "^6.1.0",
+ "is-stream": "^1.1.0",
+ "seek-bzip": "^1.0.5",
+ "unbzip2-stream": "^1.0.9"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz",
+ "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==",
+ "dev": true
+ }
+ }
+ },
+ "decompress-targz": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz",
+ "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
+ "dev": true,
+ "requires": {
+ "decompress-tar": "^4.1.1",
+ "file-type": "^5.2.0",
+ "is-stream": "^1.1.0"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
+ "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+ "dev": true
+ }
+ }
+ },
+ "decompress-unzip": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz",
+ "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=",
+ "dev": true,
+ "requires": {
+ "file-type": "^3.8.0",
+ "get-stream": "^2.2.0",
+ "pify": "^2.3.0",
+ "yauzl": "^2.4.2"
+ },
+ "dependencies": {
+ "file-type": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
+ "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
+ "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ }
+ }
+ },
+ "dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
+ "dev": true
+ },
+ "deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "dev": true,
+ "requires": {
+ "type-detect": "^4.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true
+ },
+ "defer-to-connect": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz",
+ "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==",
+ "dev": true
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "defined": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+ "dev": true
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "dev": true
+ },
+ "detect-node": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+ "dev": true
+ },
+ "devtools": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/devtools/-/devtools-6.10.4.tgz",
+ "integrity": "sha512-53LoeU2S4q4cLJGKgo2Or7WU9Kc5RQscC0DbBAZcodkot1lKFbMg/z6/cQTq+XKl4kgYr5VA/s5kzNU7ScBctQ==",
+ "dev": true,
+ "requires": {
+ "@types/puppeteer-core": "^2.0.0",
+ "@types/ua-parser-js": "^0.7.33",
+ "@types/uuid": "^8.3.0",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/protocols": "6.10.0",
+ "@wdio/utils": "6.10.4",
+ "chrome-launcher": "^0.13.1",
+ "edge-paths": "^2.1.0",
+ "puppeteer-core": "^5.1.0",
+ "ua-parser-js": "^0.7.21",
+ "uuid": "^8.0.0"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
+ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
+ "dev": true
+ }
+ }
+ },
+ "devtools-protocol": {
+ "version": "0.0.818844",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz",
+ "integrity": "sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==",
+ "dev": true
+ },
+ "di": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
+ "dev": true
+ },
+ "diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-serialize": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
+ "dev": true,
+ "requires": {
+ "custom-event": "~1.0.0",
+ "ent": "~2.2.0",
+ "extend": "^3.0.0",
+ "void-elements": "^2.0.0"
+ }
+ },
+ "dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz",
+ "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==",
+ "dev": true
+ }
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "domutils": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "dot-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
+ "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "requires": {
+ "is-obj": "^2.0.0"
+ },
+ "dependencies": {
+ "is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true
+ }
+ }
+ },
+ "download": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz",
+ "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==",
+ "dev": true,
+ "requires": {
+ "archive-type": "^4.0.0",
+ "caw": "^2.0.1",
+ "content-disposition": "^0.5.2",
+ "decompress": "^4.2.0",
+ "ext-name": "^5.0.0",
+ "file-type": "^8.1.0",
+ "filenamify": "^2.0.0",
+ "get-stream": "^3.0.0",
+ "got": "^8.3.1",
+ "make-dir": "^1.2.0",
+ "p-event": "^2.1.0",
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "got": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz",
+ "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/is": "^0.7.0",
+ "cacheable-request": "^2.1.1",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^3.0.0",
+ "into-stream": "^3.1.0",
+ "is-retry-allowed": "^1.1.0",
+ "isurl": "^1.0.0-alpha5",
+ "lowercase-keys": "^1.0.0",
+ "mimic-response": "^1.0.0",
+ "p-cancelable": "^0.4.0",
+ "p-timeout": "^2.0.1",
+ "pify": "^3.0.0",
+ "safe-buffer": "^5.1.1",
+ "timed-out": "^4.0.1",
+ "url-parse-lax": "^3.0.0",
+ "url-to-options": "^1.0.1"
+ }
+ },
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
+ "duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
+ "dev": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "edge-paths": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-2.1.0.tgz",
+ "integrity": "sha512-ZpIN1Vm5hlo9dkkST/1s8QqPNne2uwk3Plf6HcVUhnpfal0WnDRLdNj/wdQo3xRc+wnN3C25wPpPlV2E6aOunQ==",
+ "dev": true
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "electron-to-chromium": {
+ "version": "1.3.314",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz",
+ "integrity": "sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
+ "dev": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "engine.io": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz",
+ "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "0.3.1",
+ "debug": "~4.1.0",
+ "engine.io-parser": "~2.2.0",
+ "ws": "^7.1.2"
+ }
+ },
+ "engine.io-client": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz",
+ "integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "~1.3.0",
+ "component-inherit": "0.0.3",
+ "debug": "~3.1.0",
+ "engine.io-parser": "~2.2.0",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "parseqs": "0.0.6",
+ "parseuri": "0.0.6",
+ "ws": "~6.1.0",
+ "xmlhttprequest-ssl": "~1.5.4",
+ "yeast": "0.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "parseqs": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
+ "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
+ "dev": true
+ },
+ "parseuri": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
+ "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
+ "dev": true
+ },
+ "ws": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
+ "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
+ }
+ },
+ "engine.io-parser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
+ "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
+ "dev": true,
+ "requires": {
+ "after": "0.8.2",
+ "arraybuffer.slice": "~0.0.7",
+ "base64-arraybuffer": "0.1.4",
+ "blob": "0.0.5",
+ "has-binary2": "~1.0.2"
+ }
+ },
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ }
+ },
+ "ent": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
+ "dev": true
+ },
+ "entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "errorstacks": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/errorstacks/-/errorstacks-2.3.0.tgz",
+ "integrity": "sha512-VjCIUbEyLymy2N1M/uTniewz+j69YC2R7Sp1UiJn04RHwyIniBib6hUZwgmphAAZTOk7LRg/wryGFEJhblEd7Q==",
+ "dev": true
+ },
+ "es-abstract": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.2.tgz",
+ "integrity": "sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.1.4",
+ "is-regex": "^1.0.4",
+ "object-inspect": "^1.7.0",
+ "object-keys": "^1.1.1",
+ "string.prototype.trimleft": "^2.1.0",
+ "string.prototype.trimright": "^2.1.0"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true
+ },
+ "es6-promisify": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
+ "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==",
+ "dev": true
+ },
+ "esbuild": {
+ "version": "0.8.47",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.47.tgz",
+ "integrity": "sha512-4C9pInguP36c9CRDMSb6W1KrMfXrLIQVtI02Vglc43RBV0Dw49ODEnP6985mrz5iqCdQ2Cxmb9i670J/s3DBPA==",
+ "dev": true
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "eslint": {
+ "version": "5.15.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.15.1.tgz",
+ "integrity": "sha512-NTcm6vQ+PTgN3UBsALw5BMhgO6i5EpIjQF/Xb5tIh3sk9QhrFafujUOczGz4J24JBlzWclSB9Vmx8d+9Z6bFCg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.9.1",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^4.0.2",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.1",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.2.2",
+ "js-yaml": "^3.12.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.11",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0"
+ }
+ },
+ "eslint-config-developit": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-developit/-/eslint-config-developit-1.1.1.tgz",
+ "integrity": "sha512-Wc2jbDhWixq9IDfFBVcFHYaOo2i3qwdVH236jQKsiNpJlfErxm0KDT5SWZiDSWU/h6ppHsru94W3DGbUg/MjzA==",
+ "dev": true,
+ "requires": {
+ "babel-eslint": "^8.0.3",
+ "eslint-plugin-compat": "^2.1.0",
+ "eslint-plugin-jest": "^21.4.2",
+ "eslint-plugin-mocha": "^4.0.0",
+ "eslint-plugin-react": "^7.0.0"
+ }
+ },
+ "eslint-config-prettier": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz",
+ "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^6.0.0"
+ }
+ },
+ "eslint-plugin-compat": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-2.7.0.tgz",
+ "integrity": "sha512-3J4Ic1WS+SgF1smUOc62fdf7Cnrdsg0GNwKmGVPziPtWdrc2vV5Oq2ut4kG6SM5DJcxOoz/sWJIN7rkcsWh60Q==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.3.1",
+ "browserslist": "^4.4.1",
+ "caniuse-db": "^1.0.30000935",
+ "mdn-browser-compat-data": "^0.0.65"
+ }
+ },
+ "eslint-plugin-jest": {
+ "version": "21.27.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.27.2.tgz",
+ "integrity": "sha512-0E4OIgBJVlAmf1KfYFtZ3gYxgUzC5Eb3Jzmrc9ikI1OY+/cM8Kh72Ti7KfpeHNeD3HJNf9SmEfmvQLIz44Hrhw==",
+ "dev": true
+ },
+ "eslint-plugin-mocha": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.12.1.tgz",
+ "integrity": "sha512-hxWtYHvLA0p/PKymRfDYh9Mxt5dYkg2Goy1vZDarTEEYfELP9ksga7kKG1NUKSQy27C8Qjc7YrSWTLUhOEOksA==",
+ "dev": true,
+ "requires": {
+ "ramda": "^0.25.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.12.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz",
+ "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.0.3",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.0.1",
+ "object.fromentries": "^2.0.0",
+ "prop-types": "^15.6.2",
+ "resolve": "^1.9.0"
+ },
+ "dependencies": {
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ }
+ }
+ },
+ "eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+ "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+ "dev": true
+ },
+ "espree": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
+ "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.7",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true
+ },
+ "estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true
+ },
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "execa": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ }
+ }
+ },
+ "executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
+ "dev": true,
+ "requires": {
+ "pify": "^2.2.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ }
+ }
+ },
+ "exit-on-epipe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+ "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
+ "dev": true
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "^2.1.0"
+ },
+ "dependencies": {
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "requires": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ }
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "dev": true
+ },
+ "ext-list": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
+ "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
+ "dev": true,
+ "requires": {
+ "mime-db": "^1.28.0"
+ }
+ },
+ "ext-name": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
+ "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
+ "dev": true,
+ "requires": {
+ "ext-list": "^2.0.0",
+ "sort-keys-length": "^1.0.0"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ },
+ "dependencies": {
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ }
+ }
+ },
+ "extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "requires": {
+ "@types/yauzl": "^2.9.1",
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
+ "file-type": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz",
+ "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==",
+ "dev": true
+ },
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
+ "dev": true
+ },
+ "filenamify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz",
+ "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==",
+ "dev": true,
+ "requires": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.0",
+ "trim-repeated": "^1.0.0"
+ }
+ },
+ "filesize": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
+ "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "dev": true,
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "find-versions": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
+ "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
+ "dev": true,
+ "requires": {
+ "semver-regex": "^2.0.0"
+ }
+ },
+ "flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true
+ },
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ }
+ },
+ "flatted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
+ "dev": true
+ },
+ "flatten": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
+ "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
+ "dev": true
+ },
+ "flow-remove-types": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-1.2.3.tgz",
+ "integrity": "sha512-ypq/U3V+t9atYiOuSJd40tekCra03EHKoRsiK/wXGrsZimuum0kdwVY7Yv0HTaoXgHW1WiayomYd+Q3kkvPl9Q==",
+ "dev": true,
+ "requires": {
+ "babylon": "^6.15.0",
+ "vlq": "^0.2.1"
+ },
+ "dependencies": {
+ "babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true
+ }
+ }
+ },
+ "follow-redirects": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
+ "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
+ "dev": true
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
+ "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ }
+ }
+ },
+ "generic-names": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
+ "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.1.0"
+ }
+ },
+ "gensync": {
+ "version": "1.0.0-beta.1",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+ "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "dev": true
+ },
+ "get-intrinsic": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
+ "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "get-own-enumerable-property-symbols": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+ "dev": true
+ },
+ "get-port": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
+ "dev": true
+ },
+ "get-proxy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz",
+ "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==",
+ "dev": true,
+ "requires": {
+ "npm-conf": "^1.1.0"
+ }
+ },
+ "get-stdin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+ "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ }
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "global-agent": {
+ "version": "2.1.12",
+ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz",
+ "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==",
+ "dev": true,
+ "requires": {
+ "boolean": "^3.0.1",
+ "core-js": "^3.6.5",
+ "es6-error": "^4.1.1",
+ "matcher": "^3.0.0",
+ "roarr": "^2.15.3",
+ "semver": "^7.3.2",
+ "serialize-error": "^7.0.1"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.0.tgz",
+ "integrity": "sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true
+ }
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ },
+ "globalthis": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz",
+ "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3"
+ }
+ },
+ "globalyzer": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
+ "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
+ "dev": true
+ },
+ "globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+ "dev": true
+ },
+ "got": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz",
+ "integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/is": "^4.0.0",
+ "@szmarczak/http-timer": "^4.0.5",
+ "@types/cacheable-request": "^6.0.1",
+ "@types/responselike": "^1.0.0",
+ "cacheable-lookup": "^5.0.3",
+ "cacheable-request": "^7.0.1",
+ "decompress-response": "^6.0.0",
+ "http2-wrapper": "^1.0.0-beta.5.2",
+ "lowercase-keys": "^2.0.0",
+ "p-cancelable": "^2.0.0",
+ "responselike": "^2.0.0"
+ },
+ "dependencies": {
+ "@sindresorhus/is": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz",
+ "integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==",
+ "dev": true
+ },
+ "cacheable-request": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
+ "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
+ "dev": true,
+ "requires": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^4.1.0",
+ "responselike": "^2.0.0"
+ }
+ },
+ "decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^3.1.0"
+ }
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "http-cache-semantics": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
+ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
+ "dev": true
+ },
+ "json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "keyv": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz",
+ "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==",
+ "dev": true,
+ "requires": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "dev": true
+ },
+ "mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
+ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
+ "dev": true
+ },
+ "p-cancelable": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
+ "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==",
+ "dev": true
+ },
+ "responselike": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
+ "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
+ "dev": true,
+ "requires": {
+ "lowercase-keys": "^2.0.0"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+ "dev": true
+ },
+ "grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "growl": {
+ "version": "1.10.5",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+ "dev": true
+ },
+ "gzip-size": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
+ "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==",
+ "dev": true,
+ "requires": {
+ "duplexer": "^0.1.1",
+ "pify": "^4.0.1"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ }
+ }
+ },
+ "has-binary2": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
+ "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
+ "dev": true,
+ "requires": {
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ }
+ }
+ },
+ "has-cors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-symbol-support-x": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
+ "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "dev": true
+ },
+ "has-to-string-tag-x": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz",
+ "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==",
+ "dev": true,
+ "requires": {
+ "has-symbol-support-x": "^1.4.1"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "header-case": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz",
+ "integrity": "sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==",
+ "dev": true,
+ "requires": {
+ "capital-case": "^1.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "hex-color-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
+ "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==",
+ "dev": true
+ },
+ "hosted-git-info": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+ "dev": true
+ },
+ "hsl-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
+ "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=",
+ "dev": true
+ },
+ "hsla-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
+ "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=",
+ "dev": true
+ },
+ "html-comment-regex": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
+ "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
+ "dev": true
+ },
+ "html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true
+ },
+ "http-cache-semantics": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
+ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "dev": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ }
+ }
+ },
+ "http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "http2-wrapper": {
+ "version": "1.0.0-beta.5.2",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz",
+ "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==",
+ "dev": true,
+ "requires": {
+ "quick-lru": "^5.1.1",
+ "resolve-alpn": "^1.0.0"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "5",
+ "debug": "4"
+ }
+ },
+ "human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true
+ },
+ "husky": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz",
+ "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0",
+ "ci-info": "^2.0.0",
+ "compare-versions": "^3.6.0",
+ "cosmiconfig": "^7.0.0",
+ "find-versions": "^3.2.0",
+ "opencollective-postinstall": "^2.0.2",
+ "pkg-dir": "^4.2.0",
+ "please-upgrade-node": "^3.2.0",
+ "slash": "^3.0.0",
+ "which-pm-runs": "^1.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
+ "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "icss-replace-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+ "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "iltorb": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/iltorb/-/iltorb-2.4.5.tgz",
+ "integrity": "sha512-EMCMl3LnnNSZJS5QrxyZmMTaAC4+TJkM5woD+xbpm9RB+mFYCr7C05GFE3TEGCsVQSVHmjX+3sf5AiwsylNInQ==",
+ "dev": true,
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "nan": "^2.14.0",
+ "npmlog": "^4.1.2",
+ "prebuild-install": "^5.3.3",
+ "which-pm-runs": "^1.0.0"
+ }
+ },
+ "import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+ "dev": true,
+ "requires": {
+ "import-from": "^2.1.0"
+ }
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+ "dev": true,
+ "requires": {
+ "resolve-from": "^3.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+ "dev": true
+ }
+ }
+ },
+ "import-lazy": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz",
+ "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==",
+ "dev": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "inquirer": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+ "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.12",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "into-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
+ "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
+ "dev": true,
+ "requires": {
+ "from2": "^2.1.1",
+ "p-is-promise": "^1.1.0"
+ }
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "is-absolute-url": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
+ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
+ "dev": true
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+ "dev": true
+ },
+ "is-ci": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
+ "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
+ "dev": true,
+ "requires": {
+ "ci-info": "^1.5.0"
+ },
+ "dependencies": {
+ "ci-info": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
+ "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
+ "dev": true
+ }
+ }
+ },
+ "is-color-stop": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
+ "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
+ "dev": true,
+ "requires": {
+ "css-color-names": "^0.0.4",
+ "hex-color-regex": "^1.1.0",
+ "hsl-regex": "^1.0.0",
+ "hsla-regex": "^1.0.0",
+ "rgb-regex": "^1.0.1",
+ "rgba-regex": "^1.0.0"
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+ "dev": true
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+ "dev": true
+ },
+ "is-docker": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
+ "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
+ "dev": true
+ },
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "^2.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+ "dev": true
+ },
+ "is-natural-number": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
+ "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=",
+ "dev": true
+ },
+ "is-negative-zero": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
+ "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
+ "dev": true
+ },
+ "is-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
+ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+ "dev": true
+ },
+ "is-resolvable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+ "dev": true
+ },
+ "is-retry-allowed": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
+ "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true
+ },
+ "is-svg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
+ "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
+ "dev": true,
+ "requires": {
+ "html-comment-regex": "^1.1.0"
+ }
+ },
+ "is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "requires": {
+ "is-docker": "^2.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isbinaryfile": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz",
+ "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "istanbul-lib-coverage": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
+ "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
+ "dev": true
+ },
+ "istanbul-lib-instrument": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz",
+ "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.7.5",
+ "@babel/parser": "^7.7.5",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/core": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz",
+ "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helpers": "^7.8.4",
+ "@babel/parser": "^7.8.4",
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
+ "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
+ "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
+ "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ },
+ "dependencies": {
+ "@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ }
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
+ "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
+ "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz",
+ "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.4",
+ "@babel/types": "^7.8.3"
+ },
+ "dependencies": {
+ "@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
+ "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ }
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
+ "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
+ "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
+ "dev": true
+ },
+ "@babel/types": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
+ "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+ "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^3.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
+ "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
+ "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
+ "dev": true,
+ "requires": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ }
+ },
+ "isurl": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
+ "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
+ "dev": true,
+ "requires": {
+ "has-to-string-tag-x": "^1.2.0",
+ "is-object": "^1.0.1"
+ }
+ },
+ "jest-worker": {
+ "version": "23.2.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz",
+ "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=",
+ "dev": true,
+ "requires": {
+ "merge-stream": "^1.0.1"
+ },
+ "dependencies": {
+ "merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.1"
+ }
+ }
+ }
+ },
+ "js-base64": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
+ "dev": true
+ },
+ "js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true
+ },
+ "json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
+ "dev": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "json5": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+ "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "jsx-ast-utils": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz",
+ "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.0.3",
+ "object.assign": "^4.1.0"
+ }
+ },
+ "just-extend": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz",
+ "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==",
+ "dev": true
+ },
+ "karma": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/karma/-/karma-5.2.3.tgz",
+ "integrity": "sha512-tHdyFADhVVPBorIKCX8A37iLHxc6RBRphkSoQ+MLKdAtFn1k97tD8WUGi1KlEtDZKL3hui0qhsY9HXUfSNDYPQ==",
+ "dev": true,
+ "requires": {
+ "body-parser": "^1.19.0",
+ "braces": "^3.0.2",
+ "chokidar": "^3.4.2",
+ "colors": "^1.4.0",
+ "connect": "^3.7.0",
+ "di": "^0.0.1",
+ "dom-serialize": "^2.2.1",
+ "glob": "^7.1.6",
+ "graceful-fs": "^4.2.4",
+ "http-proxy": "^1.18.1",
+ "isbinaryfile": "^4.0.6",
+ "lodash": "^4.17.19",
+ "log4js": "^6.2.1",
+ "mime": "^2.4.5",
+ "minimatch": "^3.0.4",
+ "qjobs": "^1.2.0",
+ "range-parser": "^1.2.1",
+ "rimraf": "^3.0.2",
+ "socket.io": "^2.3.0",
+ "source-map": "^0.6.1",
+ "tmp": "0.2.1",
+ "ua-parser-js": "0.7.22",
+ "yargs": "^15.3.1"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "requires": {
+ "rimraf": "^3.0.0"
+ }
+ }
+ }
+ },
+ "karma-chai-sinon": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/karma-chai-sinon/-/karma-chai-sinon-0.1.5.tgz",
+ "integrity": "sha1-XDksqVJHgYlR1rV5AvAsNugDdTo=",
+ "dev": true
+ },
+ "karma-chrome-launcher": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz",
+ "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==",
+ "dev": true,
+ "requires": {
+ "which": "^1.2.1"
+ }
+ },
+ "karma-coverage": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.3.tgz",
+ "integrity": "sha512-atDvLQqvPcLxhED0cmXYdsPMCQuh6Asa9FMZW1bhNqlVEhJoB9qyZ2BY1gu7D/rr5GLGb5QzYO4siQskxaWP/g==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.1",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.0",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "karma-esbuild": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/karma-esbuild/-/karma-esbuild-2.2.0.tgz",
+ "integrity": "sha512-6dZSoKHod2YJzQSe5sbUhXFuuLR8TIJXGRRxf4ZOgBzk34WTtasBS7+eRDbVRjp/hryULvhD06Vx7bo/veg8Yw==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^3.5.1",
+ "source-map": "0.6.1"
+ },
+ "dependencies": {
+ "chokidar": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.1",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ }
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "karma-mocha": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz",
+ "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.3"
+ }
+ },
+ "karma-mocha-reporter": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz",
+ "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.1.0",
+ "log-symbols": "^2.1.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "karma-sauce-launcher": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/karma-sauce-launcher/-/karma-sauce-launcher-4.3.4.tgz",
+ "integrity": "sha512-sXka3l3Z9x+UhGMsg0fU+i+Jq82j7tfApMrAupM8JxO8ZskmSCozUM4cffLTwuzJPYjf0ffFNu3Up5Pzr26N/g==",
+ "dev": true,
+ "requires": {
+ "fs-extra": "^9.0.1",
+ "global-agent": "^2.1.12",
+ "saucelabs": "^4.5.1",
+ "webdriverio": "^6.7.0"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ },
+ "dependencies": {
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ }
+ }
+ },
+ "universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true
+ }
+ }
+ },
+ "karma-sinon": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz",
+ "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=",
+ "dev": true
+ },
+ "karma-sourcemap-loader": {
+ "version": "0.3.7",
+ "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz",
+ "integrity": "sha1-kTIsd/jxPUb+0GKwQuEAnUxFBdg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "keyv": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz",
+ "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==",
+ "dev": true,
+ "requires": {
+ "json-buffer": "3.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "kolorist": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.2.10.tgz",
+ "integrity": "sha512-S3QtGjCHyINclP4LSClgHw4gi/NxTFcSorqD9SWfrREHKtMyGfi6pyDCTbpQaqyZrMAjB4Exde8eco6kejkqQg==",
+ "dev": true
+ },
+ "lazystream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.5"
+ }
+ },
+ "lcov-parse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
+ "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lighthouse-logger": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz",
+ "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==",
+ "dev": true,
+ "requires": {
+ "debug": "^2.6.8",
+ "marky": "^1.2.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "lint-staged": {
+ "version": "10.5.2",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.2.tgz",
+ "integrity": "sha512-e8AYR1TDlzwB8VVd38Xu2lXDZf6BcshVqKVuBQThDJRaJLobqKnpbm4dkwJ2puypQNbLr9KF/9mfA649mAGvjA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "commander": "^6.2.0",
+ "cosmiconfig": "^7.0.0",
+ "debug": "^4.2.0",
+ "dedent": "^0.7.0",
+ "enquirer": "^2.3.6",
+ "execa": "^4.1.0",
+ "listr2": "^3.2.2",
+ "log-symbols": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "normalize-path": "^3.0.0",
+ "please-upgrade-node": "^3.2.0",
+ "string-argv": "0.3.1",
+ "stringify-object": "^3.3.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "commander": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
+ "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ }
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+ "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ }
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
+ "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "listr2": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.2.3.tgz",
+ "integrity": "sha512-vUb80S2dSUi8YxXahO8/I/s29GqnOL8ozgHVLjfWQXa03BNEeS1TpBLjh2ruaqq5ufx46BRGvfymdBSuoXET5w==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "cli-truncate": "^2.1.0",
+ "figures": "^3.2.0",
+ "indent-string": "^4.0.0",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rxjs": "^6.6.3",
+ "through": "^2.3.8"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "loader-utils": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
+ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^2.0.0",
+ "json5": "^1.0.1"
+ },
+ "dependencies": {
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ }
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+ "dev": true
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+ "dev": true
+ },
+ "lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
+ "dev": true
+ },
+ "lodash.difference": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+ "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=",
+ "dev": true
+ },
+ "lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
+ "dev": true
+ },
+ "lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=",
+ "dev": true
+ },
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
+ "dev": true
+ },
+ "lodash.isobject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
+ "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
+ "dev": true
+ },
+ "lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "dev": true
+ },
+ "lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
+ "dev": true
+ },
+ "lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "lodash.sumby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.sumby/-/lodash.sumby-4.6.0.tgz",
+ "integrity": "sha1-fYdzfdshbaL35efNLdnEA6eIc0Y=",
+ "dev": true
+ },
+ "lodash.union": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=",
+ "dev": true
+ },
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
+ "dev": true
+ },
+ "lodash.zip": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz",
+ "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=",
+ "dev": true
+ },
+ "log-driver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
+ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ },
+ "log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "dependencies": {
+ "ansi-escapes": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+ "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.11.0"
+ }
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ }
+ },
+ "type-fest": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+ "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+ "dev": true
+ }
+ }
+ },
+ "log4js": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz",
+ "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==",
+ "dev": true,
+ "requires": {
+ "date-format": "^3.0.0",
+ "debug": "^4.1.1",
+ "flatted": "^2.0.1",
+ "rfdc": "^1.1.4",
+ "streamroller": "^2.2.4"
+ }
+ },
+ "loglevel": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
+ "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==",
+ "dev": true
+ },
+ "loglevel-plugin-prefix": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz",
+ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "lower-case": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
+ "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.7",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+ "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+ "dev": true,
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "marky": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.1.tgz",
+ "integrity": "sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==",
+ "dev": true
+ },
+ "matcher": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
+ "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^4.0.0"
+ },
+ "dependencies": {
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ }
+ }
+ },
+ "math-expression-evaluator": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.3.tgz",
+ "integrity": "sha512-geKTlqoxnjqHoWqB71h0kchWIC23a3yfwwbZu4E2amjvGLF+fTjCCwBQOHkE0/oHc6KdnSVmMt3QB82KaPmKEA==",
+ "dev": true
+ },
+ "math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true
+ },
+ "maxmin": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
+ "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.0.0",
+ "figures": "^1.0.1",
+ "gzip-size": "^3.0.0",
+ "pretty-bytes": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "gzip-size": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+ "dev": true,
+ "requires": {
+ "duplexer": "^0.1.1"
+ }
+ },
+ "pretty-bytes": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
+ "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "mdn-browser-compat-data": {
+ "version": "0.0.65",
+ "resolved": "https://registry.npmjs.org/mdn-browser-compat-data/-/mdn-browser-compat-data-0.0.65.tgz",
+ "integrity": "sha512-OC27wWCLD2mw2aW6+8zZTwCv0+9WMTOFxuvTBfWoCx8f9gVFNUXHxGYA16mhKyso7hEa4tw1hY+ruCB/kg3EzQ==",
+ "dev": true,
+ "requires": {
+ "extend": "3.0.2"
+ }
+ },
+ "mdn-data": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
+ "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
+ "dev": true
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true
+ },
+ "memorystream": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+ "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
+ "dev": true
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "microbundle": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/microbundle/-/microbundle-0.11.0.tgz",
+ "integrity": "sha512-Lt2f8OhC2y2uKyJ5zA8lEEiDsIAbk6yllBuoAWLIdYVIXYqOdN9mO3DI7VW7x/fw87gdnCLIJdVtpP6kaI99LA==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.2.2",
+ "@babel/plugin-proposal-class-properties": "7.2.1",
+ "@babel/plugin-syntax-jsx": "^7.2.0",
+ "@babel/polyfill": "^7.0.0",
+ "asyncro": "^3.0.0",
+ "autoprefixer": "^9.0.0",
+ "babel-plugin-transform-async-to-promises": "^0.8.3",
+ "brotli-size": "^0.0.3",
+ "camelcase": "^5.0.0",
+ "chalk": "^2.4.0",
+ "cssnano": "^4.1.7",
+ "es6-promisify": "^6.0.1",
+ "gzip-size": "^5.0.0",
+ "pretty-bytes": "^5.1.0",
+ "rollup": "^0.67.3",
+ "rollup-plugin-alias": "^1.5.1",
+ "rollup-plugin-babel": "^4.1.0-0",
+ "rollup-plugin-buble": "^0.19.4",
+ "rollup-plugin-bundle-size": "^1.0.1",
+ "rollup-plugin-commonjs": "^9.0.0",
+ "rollup-plugin-es3": "^1.1.0",
+ "rollup-plugin-flow": "^1.1.1",
+ "rollup-plugin-json": "^3.1.0",
+ "rollup-plugin-node-resolve": "^4.0.0",
+ "rollup-plugin-postcss": "^1.6.1",
+ "rollup-plugin-preserve-shebang": "^0.1.6",
+ "rollup-plugin-sizes": "^0.4.2",
+ "rollup-plugin-terser": "^3.0.0",
+ "rollup-plugin-typescript2": "^0.19.0",
+ "sade": "^1.4.0",
+ "tiny-glob": "^0.2.6",
+ "tslib": "^1.9.0",
+ "typescript": ">=2.8.3"
+ }
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "mime": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
+ "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "1.42.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
+ "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.25",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
+ "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.42.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ },
+ "mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+ "dev": true
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "dev": true
+ },
+ "mocha": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz",
+ "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==",
+ "dev": true,
+ "requires": {
+ "@ungap/promise-all-settled": "1.1.2",
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.4.3",
+ "debug": "4.2.0",
+ "diff": "4.0.2",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.1.6",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "3.14.0",
+ "log-symbols": "4.0.0",
+ "minimatch": "3.0.4",
+ "ms": "2.1.2",
+ "nanoid": "3.1.12",
+ "serialize-javascript": "5.0.1",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "7.2.0",
+ "which": "2.0.2",
+ "wide-align": "1.1.3",
+ "workerpool": "6.0.2",
+ "yargs": "13.3.2",
+ "yargs-parser": "13.1.2",
+ "yargs-unparser": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "log-symbols": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+ "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ }
+ }
+ },
+ "yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
+ "module-details-from-path": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz",
+ "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=",
+ "dev": true
+ },
+ "mri": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
+ "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+ "dev": true
+ },
+ "nanoid": {
+ "version": "3.1.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz",
+ "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==",
+ "dev": true
+ },
+ "napi-build-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+ "dev": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "nise": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz",
+ "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==",
+ "dev": true,
+ "requires": {
+ "@sinonjs/commons": "^1.7.0",
+ "@sinonjs/fake-timers": "^6.0.0",
+ "@sinonjs/text-encoding": "^0.7.1",
+ "just-extend": "^4.0.2",
+ "path-to-regexp": "^1.7.0"
+ }
+ },
+ "no-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
+ "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
+ "dev": true,
+ "requires": {
+ "lower-case": "^2.0.1",
+ "tslib": "^1.10.0"
+ }
+ },
+ "node-abi": {
+ "version": "2.19.3",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz",
+ "integrity": "sha512-9xZrlyfvKhWme2EXFKQhZRp1yNWT/uI1luYPr3sFl+H4keYY4xR+1jO7mvTTijIsHf1M+QDe9uWuKeEpLInIlg==",
+ "dev": true,
+ "requires": {
+ "semver": "^5.4.1"
+ }
+ },
+ "node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
+ "dev": true
+ },
+ "node-modules-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
+ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "1.1.41",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.41.tgz",
+ "integrity": "sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "noop-logger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+ "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
+ "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
+ "dev": true
+ },
+ "npm-conf": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz",
+ "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
+ "dev": true,
+ "requires": {
+ "config-chain": "^1.1.11",
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "npm-merge-driver": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/npm-merge-driver/-/npm-merge-driver-2.3.6.tgz",
+ "integrity": "sha512-uPjCEWZ93f379zw0AMEgFtZIlpSSnpXc8BEIcs8yYHEZs5Y3d85OZHisLjNhjbYnbdAznxTq+VbyBWAQZDEm9w==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1",
+ "yargs": "^10.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "execa": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "get-caller-file": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
+ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+ "dev": true
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "dev": true,
+ "requires": {
+ "invert-kv": "^1.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
+ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "mem": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
+ "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
+ "dev": true
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "os-locale": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
+ "dev": true,
+ "requires": {
+ "execa": "^0.7.0",
+ "lcid": "^1.0.0",
+ "mem": "^1.1.0"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
+ "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=",
+ "dev": true
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
+ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ }
+ },
+ "y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+ "dev": true
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ },
+ "yargs": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz",
+ "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "find-up": "^2.1.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^2.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^8.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ },
+ "dependencies": {
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz",
+ "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^4.1.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ }
+ }
+ }
+ }
+ },
+ "npm-merge-driver-install": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/npm-merge-driver-install/-/npm-merge-driver-install-1.1.1.tgz",
+ "integrity": "sha512-QoEoJ1SAkkVPoZ9p84yel5xiMeXXqpkw1KwA8hP0iVO/NWZUYYgTUkXRL54YJ7HyLK3aTaiQrRVfpPpb9Cm/FA==",
+ "dev": true,
+ "requires": {
+ "find-root": "^1.1.0",
+ "is-ci": "^1.2.0",
+ "npm-merge-driver": "^2.3.5"
+ }
+ },
+ "npm-run-all": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
+ "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "chalk": "^2.4.1",
+ "cross-spawn": "^6.0.5",
+ "memorystream": "^0.3.1",
+ "minimatch": "^3.0.4",
+ "pidtree": "^0.3.0",
+ "read-pkg": "^3.0.0",
+ "shell-quote": "^1.6.1",
+ "string.prototype.padend": "^3.0.0"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "dev": true,
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dev": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+ "dev": true
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-component": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
+ "dev": true
+ },
+ "object-inspect": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
+ "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
+ "dev": true
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ }
+ },
+ "object.fromentries": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz",
+ "integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.15.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz",
+ "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ }
+ }
+ },
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ }
+ },
+ "object.values": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
+ "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has": "^1.0.3"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ }
+ }
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "dev": true
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "os-filter-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz",
+ "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==",
+ "dev": true,
+ "requires": {
+ "arch": "^2.1.0"
+ }
+ },
+ "os-homedir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-2.0.0.tgz",
+ "integrity": "sha512-saRNz0DSC5C/I++gFIaJTXoFJMRwiP5zHar5vV3xQ2TkgEw6hDCcU5F272JjUylpiVgBrZNQHnfjkLabTfb92Q==",
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "p-cancelable": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz",
+ "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==",
+ "dev": true
+ },
+ "p-event": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz",
+ "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==",
+ "dev": true,
+ "requires": {
+ "p-timeout": "^2.0.1"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+ "dev": true
+ },
+ "p-is-promise": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
+ "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+ "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "p-queue": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
+ "integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng==",
+ "dev": true
+ },
+ "p-timeout": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
+ "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+ "dev": true,
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "param-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz",
+ "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ },
+ "dependencies": {
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ }
+ }
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "parseqs": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+ "dev": true,
+ "requires": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "parseuri": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+ "dev": true,
+ "requires": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true
+ },
+ "pascal-case": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
+ "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "path-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.3.tgz",
+ "integrity": "sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "dev": true,
+ "requires": {
+ "isarray": "0.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ }
+ }
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ }
+ }
+ },
+ "pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+ "dev": true
+ },
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true
+ },
+ "pidtree": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
+ "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
+ "dev": true
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pirates": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
+ "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
+ "dev": true,
+ "requires": {
+ "node-modules-regexp": "^1.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "platform": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
+ "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==",
+ "dev": true
+ },
+ "please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dev": true,
+ "requires": {
+ "semver-compare": "^1.0.0"
+ }
+ },
+ "postcss": {
+ "version": "7.0.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+ "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-calc": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
+ "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.27",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "postcss-colormin": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz",
+ "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "color": "^3.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-convert-values": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz",
+ "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-discard-comments": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
+ "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-discard-duplicates": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz",
+ "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-discard-empty": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz",
+ "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-discard-overridden": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz",
+ "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-discard-unused": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
+ "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.14",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-filter-plugins": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
+ "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-load-config": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
+ "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0",
+ "postcss-load-options": "^1.2.0",
+ "postcss-load-plugins": "^2.3.0"
+ },
+ "dependencies": {
+ "cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ }
+ }
+ },
+ "postcss-load-options": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz",
+ "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0"
+ },
+ "dependencies": {
+ "cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ }
+ }
+ },
+ "postcss-load-plugins": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz",
+ "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^2.1.1",
+ "object-assign": "^4.1.0"
+ },
+ "dependencies": {
+ "cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "dev": true,
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-idents": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
+ "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.10",
+ "postcss-value-parser": "^3.1.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-longhand": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
+ "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==",
+ "dev": true,
+ "requires": {
+ "css-color-names": "0.0.4",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "stylehacks": "^4.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-merge-rules": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz",
+ "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "caniuse-api": "^3.0.0",
+ "cssnano-util-same-parent": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0",
+ "vendors": "^1.0.0"
+ },
+ "dependencies": {
+ "postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "requires": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ }
+ }
+ },
+ "postcss-message-helpers": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
+ "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
+ "dev": true
+ },
+ "postcss-minify-font-values": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz",
+ "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-minify-gradients": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz",
+ "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "is-color-stop": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-minify-params": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz",
+ "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.0",
+ "browserslist": "^4.0.0",
+ "cssnano-util-get-arguments": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-minify-selectors": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz",
+ "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "requires": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ }
+ }
+ },
+ "postcss-modules": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-1.5.0.tgz",
+ "integrity": "sha512-KiAihzcV0TxTTNA5OXreyIXctuHOfR50WIhqBpc8pe0Q5dcs/Uap9EVlifOI9am7zGGdGOJQ6B1MPYKo2UxgOg==",
+ "dev": true,
+ "requires": {
+ "css-modules-loader-core": "^1.1.0",
+ "generic-names": "^2.0.1",
+ "lodash.camelcase": "^4.3.0",
+ "postcss": "^7.0.1",
+ "string-hash": "^1.1.1"
+ }
+ },
+ "postcss-modules-extract-imports": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz",
+ "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
+ "dev": true,
+ "requires": {
+ "postcss": "^6.0.1"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
+ "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
+ "dev": true,
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
+ "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
+ "dev": true,
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-modules-values": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
+ "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
+ "dev": true,
+ "requires": {
+ "icss-replace-symbols": "^1.1.0",
+ "postcss": "^6.0.1"
+ },
+ "dependencies": {
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-charset": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz",
+ "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-normalize-display-values": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz",
+ "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-positions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz",
+ "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-repeat-style": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz",
+ "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-string": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz",
+ "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-timing-functions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz",
+ "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-match": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-unicode": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz",
+ "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-url": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz",
+ "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==",
+ "dev": true,
+ "requires": {
+ "is-absolute-url": "^2.0.0",
+ "normalize-url": "^3.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-normalize-whitespace": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz",
+ "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-ordered-values": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz",
+ "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-arguments": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-reduce-idents": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
+ "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-initial": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz",
+ "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "caniuse-api": "^3.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-reduce-transforms": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz",
+ "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==",
+ "dev": true,
+ "requires": {
+ "cssnano-util-get-match": "^4.0.0",
+ "has": "^1.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
+ "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "postcss-svgo": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz",
+ "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==",
+ "dev": true,
+ "requires": {
+ "is-svg": "^3.0.0",
+ "postcss": "^7.0.0",
+ "postcss-value-parser": "^3.0.0",
+ "svgo": "^1.0.0"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ }
+ }
+ },
+ "postcss-unique-selectors": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
+ "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.0",
+ "postcss": "^7.0.0",
+ "uniqs": "^2.0.0"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+ "dev": true
+ },
+ "postcss-zindex": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
+ "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "prebuild-install": {
+ "version": "5.3.6",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz",
+ "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==",
+ "dev": true,
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^2.7.0",
+ "noop-logger": "^0.1.1",
+ "npmlog": "^4.0.1",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^3.0.3",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0",
+ "which-pm-runs": "^1.0.0"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+ "dev": true
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
+ "prettier": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+ "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
+ "dev": true
+ },
+ "pretty-bytes": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
+ "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==",
+ "dev": true
+ },
+ "printj": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
+ "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
+ "dev": true
+ },
+ "private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "promise.series": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz",
+ "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=",
+ "dev": true
+ },
+ "prop-types": {
+ "version": "15.7.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
+ "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.8.1"
+ }
+ },
+ "proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+ "dev": true
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "psl": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
+ "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==",
+ "dev": true
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "puppeteer-core": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-5.5.0.tgz",
+ "integrity": "sha512-tlA+1n+ziW/Db03hVV+bAecDKse8ihFRXYiEypBe9IlLRvOCzYFG6qrCMBYK34HO/Q/Ecjc+tvkHRAfLVH+NgQ==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "devtools-protocol": "0.0.818844",
+ "extract-zip": "^2.0.0",
+ "https-proxy-agent": "^4.0.0",
+ "node-fetch": "^2.6.1",
+ "pkg-dir": "^4.2.0",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^3.0.2",
+ "tar-fs": "^2.0.0",
+ "unbzip2-stream": "^1.3.3",
+ "ws": "^7.2.3"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+ "dev": true
+ },
+ "qjobs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true
+ },
+ "ramda": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz",
+ "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==",
+ "dev": true
+ },
+ "randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "requires": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ }
+ }
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dev": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ }
+ },
+ "react-is": {
+ "version": "16.12.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
+ "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdir-glob": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz",
+ "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==",
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "readdirp": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "reduce-css-calc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
+ "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^0.4.2",
+ "math-expression-evaluator": "^1.2.14",
+ "reduce-function-call": "^1.0.1"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
+ "dev": true
+ }
+ }
+ },
+ "reduce-function-call": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz",
+ "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "regenerate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
+ "dev": true
+ },
+ "regenerate-unicode-properties": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz",
+ "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+ "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
+ "dev": true
+ },
+ "regenerator-transform": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz",
+ "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==",
+ "dev": true,
+ "requires": {
+ "private": "^0.1.6"
+ }
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "^0.1.3"
+ }
+ },
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": true
+ },
+ "regexpu-core": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz",
+ "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0",
+ "regenerate-unicode-properties": "^8.1.0",
+ "regjsgen": "^0.5.0",
+ "regjsparser": "^0.6.0",
+ "unicode-match-property-ecmascript": "^1.0.4",
+ "unicode-match-property-value-ecmascript": "^1.1.0"
+ }
+ },
+ "regjsgen": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz",
+ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==",
+ "dev": true
+ },
+ "regjsparser": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz",
+ "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==",
+ "dev": true,
+ "requires": {
+ "jsesc": "~0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true
+ }
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-from-string": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
+ "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "reserved-words": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz",
+ "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz",
+ "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-alpn": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz",
+ "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==",
+ "dev": true
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+ "dev": true,
+ "requires": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
+ "resq": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/resq/-/resq-1.10.0.tgz",
+ "integrity": "sha512-hCUd0xMalqtPDz4jXIqs0M5Wnv/LZXN8h7unFOo4/nvExT9dDPbhwd3udRxLlp0HgBnHcV009UlduE9NZi7A6w==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "rfdc": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
+ "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==",
+ "dev": true
+ },
+ "rgb-regex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
+ "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=",
+ "dev": true
+ },
+ "rgb2hex": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.3.tgz",
+ "integrity": "sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ==",
+ "dev": true
+ },
+ "rgba-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
+ "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "roarr": {
+ "version": "2.15.4",
+ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
+ "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
+ "dev": true,
+ "requires": {
+ "boolean": "^3.0.1",
+ "detect-node": "^2.0.4",
+ "globalthis": "^1.0.1",
+ "json-stringify-safe": "^5.0.1",
+ "semver-compare": "^1.0.0",
+ "sprintf-js": "^1.1.2"
+ },
+ "dependencies": {
+ "sprintf-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
+ }
+ }
+ },
+ "rollup": {
+ "version": "0.67.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.67.4.tgz",
+ "integrity": "sha512-AVuP73mkb4BBMUmksQ3Jw0jTrBTU1i7rLiUYjFxLZGb3xiFmtVEg40oByphkZAsiL0bJC3hRAJUQos/e5EBd+w==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "0.0.39",
+ "@types/node": "*"
+ }
+ },
+ "rollup-plugin-alias": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-alias/-/rollup-plugin-alias-1.5.2.tgz",
+ "integrity": "sha512-ODeZXhTxpD48sfcYLAFc1BGrsXKDj7o1CSNH3uYbdK3o0NxyMmaQPTNgW+ko+am92DLC8QSTe4kyxTuEkI5S5w==",
+ "dev": true,
+ "requires": {
+ "slash": "^3.0.0"
+ }
+ },
+ "rollup-plugin-babel": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz",
+ "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "rollup-pluginutils": "^2.8.1"
+ }
+ },
+ "rollup-plugin-buble": {
+ "version": "0.19.8",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-buble/-/rollup-plugin-buble-0.19.8.tgz",
+ "integrity": "sha512-8J4zPk2DQdk3rxeZvxgzhHh/rm5nJkjwgcsUYisCQg1QbT5yagW+hehYEW7ZNns/NVbDCTv4JQ7h4fC8qKGOKw==",
+ "dev": true,
+ "requires": {
+ "buble": "^0.19.8",
+ "rollup-pluginutils": "^2.3.3"
+ }
+ },
+ "rollup-plugin-bundle-size": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-bundle-size/-/rollup-plugin-bundle-size-1.0.3.tgz",
+ "integrity": "sha512-aWj0Pvzq90fqbI5vN1IvUrlf4utOqy+AERYxwWjegH1G8PzheMnrRIgQ5tkwKVtQMDP0bHZEACW/zLDF+XgfXQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "maxmin": "^2.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "rollup-plugin-commonjs": {
+ "version": "9.3.4",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-9.3.4.tgz",
+ "integrity": "sha512-DTZOvRoiVIHHLFBCL4pFxOaJt8pagxsVldEXBOn6wl3/V21wVaj17HFfyzTsQUuou3sZL3lEJZVWKPFblJfI6w==",
+ "dev": true,
+ "requires": {
+ "estree-walker": "^0.6.0",
+ "magic-string": "^0.25.2",
+ "resolve": "^1.10.0",
+ "rollup-pluginutils": "^2.6.0"
+ }
+ },
+ "rollup-plugin-es3": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-es3/-/rollup-plugin-es3-1.1.0.tgz",
+ "integrity": "sha512-jTMqQgMZ/tkjRW4scf4ln5c0OiTSi+Lx/IEyFd41ldgGoLvvg9AQxmVOl93+KaoyB7XRYToYjiHDvO40NPF/fA==",
+ "dev": true,
+ "requires": {
+ "magic-string": "^0.22.4"
+ },
+ "dependencies": {
+ "magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "dev": true,
+ "requires": {
+ "vlq": "^0.2.2"
+ }
+ }
+ }
+ },
+ "rollup-plugin-flow": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-flow/-/rollup-plugin-flow-1.1.1.tgz",
+ "integrity": "sha1-bOVo8d1Vlma3erdrS64lFAdSjbY=",
+ "dev": true,
+ "requires": {
+ "flow-remove-types": "^1.1.0",
+ "rollup-pluginutils": "^1.5.1"
+ },
+ "dependencies": {
+ "estree-walker": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz",
+ "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=",
+ "dev": true
+ },
+ "rollup-pluginutils": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz",
+ "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=",
+ "dev": true,
+ "requires": {
+ "estree-walker": "^0.2.1",
+ "minimatch": "^3.0.2"
+ }
+ }
+ }
+ },
+ "rollup-plugin-json": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-3.1.0.tgz",
+ "integrity": "sha512-BlYk5VspvGpjz7lAwArVzBXR60JK+4EKtPkCHouAWg39obk9S61hZYJDBfMK+oitPdoe11i69TlxKlMQNFC/Uw==",
+ "dev": true,
+ "requires": {
+ "rollup-pluginutils": "^2.3.1"
+ }
+ },
+ "rollup-plugin-node-resolve": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.2.4.tgz",
+ "integrity": "sha512-t/64I6l7fZ9BxqD3XlX4ZeO6+5RLKyfpwE2CiPNUKa+GocPlQhf/C208ou8y3AwtNsc6bjSk/8/6y/YAyxCIvw==",
+ "dev": true,
+ "requires": {
+ "@types/resolve": "0.0.8",
+ "builtin-modules": "^3.1.0",
+ "is-module": "^1.0.0",
+ "resolve": "^1.10.0"
+ }
+ },
+ "rollup-plugin-postcss": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-1.6.3.tgz",
+ "integrity": "sha512-se1qftVETua9ZGViud4A4gbgEQenjYnLPvjh3kTqbBZU+f0mQ9YvJptIuzPhEk5kZAHZhkwIkk2jk+byrn1XPA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "concat-with-sourcemaps": "^1.0.5",
+ "cssnano": "^3.10.0",
+ "fs-extra": "^5.0.0",
+ "import-cwd": "^2.1.0",
+ "p-queue": "^2.4.2",
+ "pify": "^3.0.0",
+ "postcss": "^6.0.21",
+ "postcss-load-config": "^1.2.0",
+ "postcss-modules": "^1.1.0",
+ "promise.series": "^0.2.0",
+ "reserved-words": "^0.1.2",
+ "resolve": "^1.5.0",
+ "rollup-pluginutils": "^2.0.1",
+ "style-inject": "^0.3.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "autoprefixer": {
+ "version": "6.7.7",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
+ "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
+ "dev": true,
+ "requires": {
+ "browserslist": "^1.7.6",
+ "caniuse-db": "^1.0.30000634",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^5.2.16",
+ "postcss-value-parser": "^3.2.3"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "dev": true,
+ "requires": {
+ "caniuse-db": "^1.0.30000639",
+ "electron-to-chromium": "^1.2.7"
+ }
+ },
+ "caniuse-api": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
+ "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
+ "dev": true,
+ "requires": {
+ "browserslist": "^1.3.6",
+ "caniuse-db": "^1.0.30000529",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
+ "coa": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+ "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+ "dev": true,
+ "requires": {
+ "q": "^1.1.2"
+ }
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "cssnano": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
+ "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+ "dev": true,
+ "requires": {
+ "autoprefixer": "^6.3.1",
+ "decamelize": "^1.1.2",
+ "defined": "^1.0.0",
+ "has": "^1.0.1",
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.14",
+ "postcss-calc": "^5.2.0",
+ "postcss-colormin": "^2.1.8",
+ "postcss-convert-values": "^2.3.4",
+ "postcss-discard-comments": "^2.0.4",
+ "postcss-discard-duplicates": "^2.0.1",
+ "postcss-discard-empty": "^2.0.1",
+ "postcss-discard-overridden": "^0.1.1",
+ "postcss-discard-unused": "^2.2.1",
+ "postcss-filter-plugins": "^2.0.0",
+ "postcss-merge-idents": "^2.1.5",
+ "postcss-merge-longhand": "^2.0.1",
+ "postcss-merge-rules": "^2.0.3",
+ "postcss-minify-font-values": "^1.0.2",
+ "postcss-minify-gradients": "^1.0.1",
+ "postcss-minify-params": "^1.0.4",
+ "postcss-minify-selectors": "^2.0.4",
+ "postcss-normalize-charset": "^1.1.0",
+ "postcss-normalize-url": "^3.0.7",
+ "postcss-ordered-values": "^2.1.0",
+ "postcss-reduce-idents": "^2.2.2",
+ "postcss-reduce-initial": "^1.0.0",
+ "postcss-reduce-transforms": "^1.0.3",
+ "postcss-svgo": "^2.1.1",
+ "postcss-unique-selectors": "^2.0.2",
+ "postcss-value-parser": "^3.2.3",
+ "postcss-zindex": "^2.0.1"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "csso": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
+ "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
+ "dev": true,
+ "requires": {
+ "clap": "^1.0.9",
+ "source-map": "^0.5.3"
+ }
+ },
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "is-svg": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
+ "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
+ "dev": true,
+ "requires": {
+ "html-comment-regex": "^1.1.0"
+ }
+ },
+ "js-yaml": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+ "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^2.6.0"
+ }
+ },
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-calc": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
+ "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.2",
+ "postcss-message-helpers": "^2.0.0",
+ "reduce-css-calc": "^1.2.6"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-colormin": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
+ "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
+ "dev": true,
+ "requires": {
+ "colormin": "^1.0.5",
+ "postcss": "^5.0.13",
+ "postcss-value-parser": "^3.2.3"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-convert-values": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
+ "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.11",
+ "postcss-value-parser": "^3.1.2"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-discard-comments": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
+ "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.14"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-discard-duplicates": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
+ "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-discard-empty": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
+ "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.14"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-discard-overridden": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
+ "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.16"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-merge-longhand": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
+ "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-merge-rules": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
+ "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
+ "dev": true,
+ "requires": {
+ "browserslist": "^1.5.2",
+ "caniuse-api": "^1.5.2",
+ "postcss": "^5.0.4",
+ "postcss-selector-parser": "^2.2.2",
+ "vendors": "^1.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-minify-font-values": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
+ "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-minify-gradients": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
+ "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.12",
+ "postcss-value-parser": "^3.3.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-minify-params": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
+ "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.2",
+ "postcss-value-parser": "^3.0.2",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-minify-selectors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
+ "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.2",
+ "has": "^1.0.1",
+ "postcss": "^5.0.14",
+ "postcss-selector-parser": "^2.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-normalize-charset": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
+ "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.5"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-normalize-url": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
+ "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
+ "dev": true,
+ "requires": {
+ "is-absolute-url": "^2.0.0",
+ "normalize-url": "^1.4.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-ordered-values": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
+ "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.1"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-reduce-initial": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
+ "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
+ "dev": true,
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-reduce-transforms": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
+ "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.8",
+ "postcss-value-parser": "^3.0.1"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+ "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+ "dev": true,
+ "requires": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-svgo": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
+ "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
+ "dev": true,
+ "requires": {
+ "is-svg": "^2.0.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3",
+ "svgo": "^0.7.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-unique-selectors": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
+ "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+ "dev": true,
+ "requires": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ }
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ },
+ "svgo": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
+ "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
+ "dev": true,
+ "requires": {
+ "coa": "~1.0.1",
+ "colors": "~1.1.2",
+ "csso": "~2.3.1",
+ "js-yaml": "~3.7.0",
+ "mkdirp": "~0.5.1",
+ "sax": "~1.2.1",
+ "whet.extend": "~0.9.9"
+ }
+ }
+ }
+ },
+ "rollup-plugin-preserve-shebang": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-preserve-shebang/-/rollup-plugin-preserve-shebang-0.1.6.tgz",
+ "integrity": "sha512-b+psdlXZOjmlnKmL6/YAkR8PR15VPcUNXdT35urBRJ8jE6UxHyb4HXeeN3qRZJbMJJaX1eRP72XwH6IvGFh5Jw==",
+ "dev": true,
+ "requires": {
+ "magic-string": "^0.22.4"
+ },
+ "dependencies": {
+ "magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "dev": true,
+ "requires": {
+ "vlq": "^0.2.2"
+ }
+ }
+ }
+ },
+ "rollup-plugin-sizes": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-sizes/-/rollup-plugin-sizes-0.4.2.tgz",
+ "integrity": "sha512-6VsnWb4aBPcW++3IBMNPo4NLSheoaXh+itXk1OcaolLhYemoQFb7A9hVNocwa0j2BctdmPNFcP7UJ3g///VVaA==",
+ "dev": true,
+ "requires": {
+ "filesize": "^3.5.11",
+ "lodash.foreach": "^4.5.0",
+ "lodash.sumby": "^4.6.0",
+ "module-details-from-path": "^1.0.3"
+ }
+ },
+ "rollup-plugin-terser": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-3.0.0.tgz",
+ "integrity": "sha512-Ed9zRD7OoCBnh0XGlEAJle5TCUsFXMLClwKzZWnS1zbNO4MelHjfCSdFZxCAdH70M40nhZ1nRrY2GZQJhSMcjA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "jest-worker": "^23.2.0",
+ "serialize-javascript": "^1.5.0",
+ "terser": "^3.8.2"
+ }
+ },
+ "rollup-plugin-typescript2": {
+ "version": "0.19.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.19.3.tgz",
+ "integrity": "sha512-lsRqfBCZhMl/tq9AT5YnQvzQWzXtnx3EQYFcHD72gul7nyyoOrzx5yCEH20smpw58v6UkHHZz03FbdLEPoHWjA==",
+ "dev": true,
+ "requires": {
+ "fs-extra": "7.0.1",
+ "resolve": "1.8.1",
+ "rollup-pluginutils": "2.3.3",
+ "tslib": "1.9.3"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "estree-walker": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz",
+ "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "resolve": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "rollup-pluginutils": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.3.tgz",
+ "integrity": "sha512-2XZwja7b6P5q4RZ5FhyX1+f46xi1Z3qBKigLRZ6VTZjwbN0K1IFGMlwm06Uu0Emcre2Z63l77nq/pzn+KxIEoA==",
+ "dev": true,
+ "requires": {
+ "estree-walker": "^0.5.2",
+ "micromatch": "^2.3.11"
+ }
+ },
+ "tslib": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+ "dev": true
+ }
+ }
+ },
+ "rollup-pluginutils": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+ "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+ "dev": true,
+ "requires": {
+ "estree-walker": "^0.6.1"
+ }
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "dev": true,
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "rxjs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
+ "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "sade": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
+ "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==",
+ "dev": true,
+ "requires": {
+ "mri": "^1.1.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "saucelabs": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-4.6.0.tgz",
+ "integrity": "sha512-GAytkfq2QTVzwMS4/A99YQ79wqZvq29hO1r7+JYvfExRD9UipuvzvqhzsAfS8fKg+OuRIbIDTk0Rd7aWXa06zw==",
+ "dev": true,
+ "requires": {
+ "bin-wrapper": "^4.1.0",
+ "change-case": "^4.1.1",
+ "form-data": "^3.0.0",
+ "got": "^11.7.0",
+ "hash.js": "^1.1.7",
+ "tunnel": "0.0.6",
+ "yargs": "^16.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "form-data": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
+ "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "y18n": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
+ "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "16.1.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz",
+ "integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==",
+ "dev": true,
+ "requires": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true
+ }
+ }
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ },
+ "seek-bzip": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz",
+ "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.8.1"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
+ "dev": true
+ },
+ "semver-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
+ "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==",
+ "dev": true
+ },
+ "semver-truncate": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz",
+ "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=",
+ "dev": true,
+ "requires": {
+ "semver": "^5.3.0"
+ }
+ },
+ "sentence-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.3.tgz",
+ "integrity": "sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.3",
+ "tslib": "^1.10.0",
+ "upper-case-first": "^2.0.1"
+ }
+ },
+ "serialize-error": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
+ "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.13.1"
+ }
+ },
+ "serialize-javascript": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
+ "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
+ "dev": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "shell-quote": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
+ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "dev": true
+ },
+ "simple-get": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
+ "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+ "dev": true,
+ "requires": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.3.1"
+ },
+ "dependencies": {
+ "is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "dev": true
+ }
+ }
+ },
+ "sinon": {
+ "version": "9.2.3",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.3.tgz",
+ "integrity": "sha512-m+DyAWvqVHZtjnjX/nuShasykFeiZ+nPuEfD4G3gpvKGkXRhkF/6NSt2qN2FjZhfrcHXFzUzI+NLnk+42fnLEw==",
+ "dev": true,
+ "requires": {
+ "@sinonjs/commons": "^1.8.1",
+ "@sinonjs/fake-timers": "^6.0.1",
+ "@sinonjs/samsam": "^5.3.0",
+ "diff": "^4.0.2",
+ "nise": "^4.0.4",
+ "supports-color": "^7.1.0"
+ },
+ "dependencies": {
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "sinon-chai": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.5.0.tgz",
+ "integrity": "sha512-IifbusYiQBpUxxFJkR3wTU68xzBN0+bxCScEaKMjBvAQERg6FnTTc1F17rseLb1tjmkJ23730AXpFI0c47FgAg==",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "snake-case": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz",
+ "integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.3",
+ "tslib": "^1.10.0"
+ }
+ },
+ "socket.io": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
+ "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
+ "dev": true,
+ "requires": {
+ "debug": "~4.1.0",
+ "engine.io": "~3.4.0",
+ "has-binary2": "~1.0.2",
+ "socket.io-adapter": "~1.1.0",
+ "socket.io-client": "2.3.0",
+ "socket.io-parser": "~3.4.0"
+ }
+ },
+ "socket.io-adapter": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
+ "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
+ "dev": true
+ },
+ "socket.io-client": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
+ "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
+ "dev": true,
+ "requires": {
+ "backo2": "1.0.2",
+ "base64-arraybuffer": "0.1.5",
+ "component-bind": "1.0.0",
+ "component-emitter": "1.2.1",
+ "debug": "~4.1.0",
+ "engine.io-client": "~3.4.0",
+ "has-binary2": "~1.0.2",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "object-component": "0.0.3",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "socket.io-parser": "~3.3.0",
+ "to-array": "0.1.4"
+ },
+ "dependencies": {
+ "base64-arraybuffer": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "socket.io-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.1.tgz",
+ "integrity": "sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "~1.3.0",
+ "debug": "~3.1.0",
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "socket.io-parser": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
+ "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "debug": "~4.1.0",
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ }
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ },
+ "sort-keys-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
+ "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
+ "dev": true,
+ "requires": {
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
+ "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "stable": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+ "dev": true
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "dev": true
+ },
+ "streamroller": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz",
+ "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==",
+ "dev": true,
+ "requires": {
+ "date-format": "^2.1.0",
+ "debug": "^4.1.1",
+ "fs-extra": "^8.1.0"
+ },
+ "dependencies": {
+ "date-format": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
+ "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ }
+ }
+ },
+ "strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "string-argv": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+ "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "dev": true
+ },
+ "string-hash": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
+ "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "string.prototype.padend": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
+ "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.4.3",
+ "function-bind": "^1.0.2"
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
+ "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "string.prototype.trimleft": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
+ "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "function-bind": "^1.1.1"
+ }
+ },
+ "string.prototype.trimright": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz",
+ "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "function-bind": "^1.1.1"
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
+ "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "stringify-object": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+ "dev": true,
+ "requires": {
+ "get-own-enumerable-property-symbols": "^3.0.0",
+ "is-obj": "^1.0.1",
+ "is-regexp": "^1.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "strip-dirs": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz",
+ "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==",
+ "dev": true,
+ "requires": {
+ "is-natural-number": "^4.0.1"
+ }
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+ "dev": true
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true
+ },
+ "strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
+ "style-inject": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz",
+ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==",
+ "dev": true
+ },
+ "stylehacks": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
+ "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.0.0",
+ "postcss": "^7.0.0",
+ "postcss-selector-parser": "^3.0.0"
+ },
+ "dependencies": {
+ "postcss-selector-parser": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+ "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+ "dev": true,
+ "requires": {
+ "dot-prop": "^5.2.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ }
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "svgo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
+ "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "coa": "^2.0.2",
+ "css-select": "^2.0.0",
+ "css-select-base-adapter": "^0.1.1",
+ "css-tree": "1.0.0-alpha.37",
+ "csso": "^4.0.2",
+ "js-yaml": "^3.13.1",
+ "mkdirp": "~0.5.1",
+ "object.values": "^1.1.0",
+ "sax": "~1.2.4",
+ "stable": "^0.1.8",
+ "unquote": "~1.1.1",
+ "util.promisify": "~1.0.0"
+ }
+ },
+ "table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dev": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "tar-stream": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
+ "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
+ "dev": true,
+ "requires": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "terser": {
+ "version": "3.17.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
+ "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.19.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.10"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "requires": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "timed-out": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
+ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
+ "dev": true
+ },
+ "timsort": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
+ "dev": true
+ },
+ "tiny-glob": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.8.tgz",
+ "integrity": "sha512-vkQP7qOslq63XRX9kMswlby99kyO5OvKptw7AMwBVMjXEI7Tb61eoI5DydyEMOseyGS5anDN1VPoVxEvH01q8w==",
+ "dev": true,
+ "requires": {
+ "globalyzer": "0.1.0",
+ "globrex": "^0.1.2"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "to-array": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+ "dev": true
+ },
+ "to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+ "dev": true
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "dev": true
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ }
+ }
+ },
+ "trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
+ "trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true
+ },
+ "tslib": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
+ "dev": true
+ },
+ "tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+ "dev": true
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+ "dev": true
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dev": true,
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+ "dev": true
+ },
+ "ua-parser-js": {
+ "version": "0.7.22",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
+ "integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==",
+ "dev": true
+ },
+ "unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
+ "unicode-canonical-property-names-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
+ "dev": true
+ },
+ "unicode-match-property-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+ "dev": true,
+ "requires": {
+ "unicode-canonical-property-names-ecmascript": "^1.0.4",
+ "unicode-property-aliases-ecmascript": "^1.0.4"
+ }
+ },
+ "unicode-match-property-value-ecmascript": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz",
+ "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==",
+ "dev": true
+ },
+ "unicode-property-aliases-ecmascript": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz",
+ "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
+ "dev": true
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "uniqs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
+ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
+ "dev": true
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true
+ },
+ "unquote": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
+ "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
+ "dev": true
+ },
+ "upper-case": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.1.tgz",
+ "integrity": "sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "upper-case-first": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.1.tgz",
+ "integrity": "sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+ "dev": true,
+ "requires": {
+ "prepend-http": "^2.0.0"
+ },
+ "dependencies": {
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true
+ }
+ }
+ },
+ "url-to-options": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz",
+ "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "util.promisify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
+ "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.2",
+ "has-symbols": "^1.0.1",
+ "object.getownpropertydescriptors": "^2.1.0"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ }
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
+ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
+ "dev": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "vendors": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
+ "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==",
+ "dev": true
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "vlq": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
+ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
+ "dev": true
+ },
+ "void-elements": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+ "dev": true
+ },
+ "webdriver": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-6.10.4.tgz",
+ "integrity": "sha512-N2FkEy22QWAJMeyz1219ik9wyt3/SOT/RtsY6JheEriZ1GptzZyK0OibkOnCoaIAt+nvSxnSmTTlmXQMGBE6Mw==",
+ "dev": true,
+ "requires": {
+ "@types/lodash.merge": "^4.6.6",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/protocols": "6.10.0",
+ "@wdio/utils": "6.10.4",
+ "got": "^11.0.2",
+ "lodash.merge": "^4.6.1"
+ }
+ },
+ "webdriverio": {
+ "version": "6.10.5",
+ "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-6.10.5.tgz",
+ "integrity": "sha512-TLIKVOOM0Oszn2mLxZcMQk0vq1bOWpsZNXMxMtpBXKLvcOCLedftxotwh0o1LqRiq8ODiubJ/vNOLgCN/oLFJQ==",
+ "dev": true,
+ "requires": {
+ "@types/archiver": "^5.1.0",
+ "@types/atob": "^2.1.2",
+ "@types/fs-extra": "^9.0.2",
+ "@types/lodash.clonedeep": "^4.5.6",
+ "@types/lodash.isplainobject": "^4.0.6",
+ "@types/puppeteer-core": "^2.0.0",
+ "@wdio/config": "6.10.4",
+ "@wdio/logger": "6.10.4",
+ "@wdio/repl": "6.10.4",
+ "@wdio/utils": "6.10.4",
+ "archiver": "^5.0.0",
+ "atob": "^2.1.2",
+ "css-shorthand-properties": "^1.1.1",
+ "css-value": "^0.0.1",
+ "devtools": "6.10.4",
+ "fs-extra": "^9.0.1",
+ "get-port": "^5.1.1",
+ "grapheme-splitter": "^1.0.2",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.isobject": "^3.0.2",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.zip": "^4.2.0",
+ "minimatch": "^3.0.4",
+ "puppeteer-core": "^5.1.0",
+ "resq": "^1.9.1",
+ "rgb2hex": "^0.2.0",
+ "serialize-error": "^7.0.0",
+ "webdriver": "6.10.4"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ },
+ "dependencies": {
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ }
+ }
+ },
+ "universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true
+ }
+ }
+ },
+ "whet.extend": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
+ "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "which-pm-runs": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
+ "dev": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
+ "workerpool": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz",
+ "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "ws": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
+ "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==",
+ "dev": true
+ },
+ "xmlhttprequest-ssl": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
+ "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ },
+ "yaml": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
+ "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
+ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true
+ }
+ }
+ },
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "yeast": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+ "dev": true
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ },
+ "zip-stream": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.4.tgz",
+ "integrity": "sha512-a65wQ3h5gcQ/nQGWV1mSZCEzCML6EK/vyVPcrPNynySP1j3VBbQKh3nhC8CbORb+jfl2vXvh56Ul5odP1bAHqw==",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^2.1.0",
+ "compress-commons": "^4.0.2",
+ "readable-stream": "^3.6.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/preact/package.json b/preact/package.json
new file mode 100644
index 0000000..bb50431
--- /dev/null
+++ b/preact/package.json
@@ -0,0 +1,270 @@
+{
+ "name": "preact",
+ "amdName": "preact",
+ "version": "10.5.14",
+ "private": false,
+ "description": "Fast 3kb React-compatible Virtual DOM library.",
+ "main": "dist/preact.js",
+ "module": "dist/preact.module.js",
+ "umd:main": "dist/preact.umd.js",
+ "unpkg": "dist/preact.min.js",
+ "source": "src/index.js",
+ "exports": {
+ ".": {
+ "browser": "./dist/preact.module.js",
+ "umd": "./dist/preact.umd.js",
+ "import": "./dist/preact.mjs",
+ "require": "./dist/preact.js"
+ },
+ "./compat": {
+ "browser": "./compat/dist/compat.module.js",
+ "umd": "./compat/dist/compat.umd.js",
+ "require": "./compat/dist/compat.js",
+ "import": "./compat/dist/compat.mjs"
+ },
+ "./debug": {
+ "browser": "./debug/dist/debug.module.js",
+ "umd": "./debug/dist/debug.umd.js",
+ "require": "./debug/dist/debug.js",
+ "import": "./debug/dist/debug.mjs"
+ },
+ "./devtools": {
+ "browser": "./devtools/dist/devtools.module.js",
+ "umd": "./devtools/dist/devtools.umd.js",
+ "require": "./devtools/dist/devtools.js",
+ "import": "./devtools/dist/devtools.mjs"
+ },
+ "./hooks": {
+ "browser": "./hooks/dist/hooks.module.js",
+ "umd": "./hooks/dist/hooks.umd.js",
+ "require": "./hooks/dist/hooks.js",
+ "import": "./hooks/dist/hooks.mjs"
+ },
+ "./test-utils": {
+ "browser": "./test-utils/dist/testUtils.module.js",
+ "umd": "./test-utils/dist/testUtils.umd.js",
+ "require": "./test-utils/dist/testUtils.js",
+ "import": "./test-utils/dist/testUtils.mjs"
+ },
+ "./jsx-runtime": {
+ "browser": "./jsx-runtime/dist/jsxRuntime.module.js",
+ "umd": "./jsx-runtime/dist/jsxRuntime.umd.js",
+ "require": "./jsx-runtime/dist/jsxRuntime.js",
+ "import": "./jsx-runtime/dist/jsxRuntime.mjs"
+ },
+ "./jsx-dev-runtime": {
+ "browser": "./jsx-runtime/dist/jsxRuntime.module.js",
+ "umd": "./jsx-runtime/dist/jsxRuntime.umd.js",
+ "require": "./jsx-runtime/dist/jsxRuntime.js",
+ "import": "./jsx-runtime/dist/jsxRuntime.mjs"
+ },
+ "./compat/server": {
+ "require": "./compat/server.js",
+ "import": "./compat/server.mjs"
+ },
+ "./compat/scheduler": {
+ "require": "./compat/scheduler.js",
+ "import": "./compat/scheduler.mjs"
+ },
+ "./package.json": "./package.json",
+ "./": "./"
+ },
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ },
+ "types": "src/index.d.ts",
+ "scripts": {
+ "prepare": "run-s build && check-export-map",
+ "build": "npm-run-all --parallel build:*",
+ "build:core": "microbundle build --raw",
+ "build:core-min": "microbundle build --raw -f iife src/cjs.js -o dist/preact.min.js",
+ "build:debug": "microbundle build --raw --cwd debug",
+ "build:devtools": "microbundle build --raw --cwd devtools",
+ "build:hooks": "microbundle build --raw --cwd hooks",
+ "build:test-utils": "microbundle build --raw --cwd test-utils",
+ "build:compat": "microbundle build src/index.js src/scheduler.js --raw --cwd compat --globals 'preact/hooks=preactHooks'",
+ "build:jsx": "microbundle build --raw --cwd jsx-runtime",
+ "postbuild": "node ./config/node-13-exports.js && node ./config/compat-entries.js",
+ "dev": "microbundle watch --raw --format cjs",
+ "dev:hooks": "microbundle watch --raw --format cjs --cwd hooks",
+ "dev:compat": "microbundle watch --raw --format cjs --cwd compat --globals 'preact/hooks=preactHooks'",
+ "test": "npm-run-all build lint test:unit",
+ "test:unit": "run-p test:mocha test:karma:minify test:ts",
+ "test:ts": "run-p test:ts:*",
+ "test:ts:core": "tsc -p test/ts/ && mocha --require \"@babel/register\" test/ts/**/*-test.js",
+ "test:ts:compat": "tsc -p compat/test/ts/",
+ "test:mocha": "mocha --recursive --require \"@babel/register\" test/shared test/node",
+ "test:mocha:watch": "npm run test:mocha -- --watch",
+ "test:karma": "cross-env COVERAGE=true BABEL_NO_MODULES=true karma start karma.conf.js --single-run",
+ "test:karma:minify": "cross-env COVERAGE=true MINIFY=true BABEL_NO_MODULES=true karma start karma.conf.js --single-run",
+ "test:karma:watch": "cross-env BABEL_NO_MODULES=true karma start karma.conf.js --no-single-run",
+ "test:karma:hooks": "cross-env COVERAGE=false BABEL_NO_MODULES=true karma start karma.conf.js --grep=hooks/test/browser/**.js --no-single-run",
+ "test:karma:test-utils": "cross-env PERFORMANCE=false COVERAGE=false BABEL_NO_MODULES=true karma start karma.conf.js --grep=test-utils/test/shared/**.js --no-single-run",
+ "test:karma:bench": "cross-env PERFORMANCE=true COVERAGE=false BABEL_NO_MODULES=true karma start karma.conf.js --grep=test/benchmarks/**.js --single-run",
+ "benchmark": "npm run test:karma:bench -- no-single-run",
+ "lint": "eslint src test debug compat hooks test-utils"
+ },
+ "eslintConfig": {
+ "extends": [
+ "developit",
+ "prettier"
+ ],
+ "settings": {
+ "react": {
+ "pragma": "createElement"
+ }
+ },
+ "rules": {
+ "camelcase": [
+ 1,
+ {
+ "allow": [
+ "__test__*",
+ "unstable_*",
+ "UNSAFE_*"
+ ]
+ }
+ ],
+ "no-unused-vars": [
+ 2,
+ {
+ "args": "none",
+ "varsIgnorePattern": "^h|React$"
+ }
+ ],
+ "prefer-rest-params": 0,
+ "prefer-spread": 0,
+ "no-cond-assign": 0,
+ "react/jsx-no-bind": 0,
+ "react/no-danger": "off",
+ "react/prefer-stateless-function": 0,
+ "react/sort-comp": 0,
+ "jest/valid-expect": 0,
+ "jest/no-disabled-tests": 0,
+ "react/no-find-dom-node": 0
+ }
+ },
+ "eslintIgnore": [
+ "test/fixtures",
+ "test/ts/",
+ "*.ts",
+ "dist"
+ ],
+ "prettier": {
+ "singleQuote": true,
+ "trailingComma": "none",
+ "useTabs": true,
+ "tabWidth": 2
+ },
+ "lint-staged": {
+ "**/*.{js,jsx,ts,tsx,yml}": [
+ "prettier --write"
+ ]
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "files": [
+ "src",
+ "dist",
+ "compat/dist",
+ "compat/src",
+ "compat/server.js",
+ "compat/server.mjs",
+ "compat/scheduler.js",
+ "compat/scheduler.mjs",
+ "compat/test-utils.js",
+ "compat/jsx-runtime.js",
+ "compat/jsx-runtime.mjs",
+ "compat/jsx-dev-runtime.js",
+ "compat/jsx-dev-runtime.mjs",
+ "compat/package.json",
+ "debug/dist",
+ "debug/src",
+ "debug/package.json",
+ "devtools/dist",
+ "devtools/src",
+ "devtools/package.json",
+ "hooks/dist",
+ "hooks/src",
+ "hooks/package.json",
+ "jsx-runtime/dist",
+ "jsx-runtime/src",
+ "jsx-runtime/package.json",
+ "test-utils/src",
+ "test-utils/package.json",
+ "test-utils/dist"
+ ],
+ "keywords": [
+ "preact",
+ "react",
+ "ui",
+ "user interface",
+ "virtual dom",
+ "vdom",
+ "components",
+ "dom diff",
+ "front-end",
+ "framework"
+ ],
+ "authors": [
+ "The Preact Authors (https://github.com/preactjs/preact/contributors)"
+ ],
+ "repository": "preactjs/preact",
+ "bugs": "https://github.com/preactjs/preact/issues",
+ "homepage": "https://preactjs.com",
+ "devDependencies": {
+ "@babel/core": "^7.7.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.6.2",
+ "@babel/plugin-transform-react-jsx": "^7.7.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.7.4",
+ "@babel/preset-env": "^7.7.1",
+ "@babel/register": "^7.7.0",
+ "@types/chai": "^4.1.2",
+ "@types/mocha": "^5.0.0",
+ "@types/node": "^14.14.10",
+ "babel-plugin-istanbul": "^6.0.0",
+ "babel-plugin-transform-async-to-promises": "^0.8.15",
+ "babel-plugin-transform-rename-properties": "0.1.0",
+ "benchmark": "^2.1.4",
+ "chai": "^4.1.2",
+ "check-export-map": "^1.0.1",
+ "coveralls": "^3.0.0",
+ "cross-env": "^7.0.2",
+ "csstype": "^3.0.5",
+ "diff": "^5.0.0",
+ "errorstacks": "^2.3.0",
+ "esbuild": "^0.8.47",
+ "eslint": "5.15.1",
+ "eslint-config-developit": "^1.1.1",
+ "eslint-config-prettier": "^6.5.0",
+ "eslint-plugin-react": "7.12.4",
+ "husky": "^4.3.0",
+ "karma": "^5.2.3",
+ "karma-chai-sinon": "^0.1.5",
+ "karma-chrome-launcher": "^3.1.0",
+ "karma-coverage": "^2.0.3",
+ "karma-esbuild": "^2.2.0",
+ "karma-mocha": "^2.0.1",
+ "karma-mocha-reporter": "^2.2.5",
+ "karma-sauce-launcher": "^4.3.4",
+ "karma-sinon": "^1.0.5",
+ "karma-sourcemap-loader": "^0.3.7",
+ "kolorist": "^1.2.10",
+ "lint-staged": "^10.5.2",
+ "lodash": "^4.17.20",
+ "microbundle": "^0.11.0",
+ "mocha": "^8.2.1",
+ "npm-merge-driver-install": "^1.1.1",
+ "npm-run-all": "^4.0.0",
+ "prettier": "^1.18.2",
+ "prop-types": "^15.7.2",
+ "sinon": "^9.2.3",
+ "sinon-chai": "^3.5.0",
+ "typescript": "3.5.3"
+ }
+}
diff --git a/preact/sizereport.config.js b/preact/sizereport.config.js
new file mode 100644
index 0000000..36c9d2d
--- /dev/null
+++ b/preact/sizereport.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ repo: 'preactjs/preact',
+ path: ['./{compat,debug,hooks,}/dist/**/!(*.map)'],
+ branch: 'master'
+};
diff --git a/preact/src/cjs.js b/preact/src/cjs.js
new file mode 100644
index 0000000..b4721b1
--- /dev/null
+++ b/preact/src/cjs.js
@@ -0,0 +1,3 @@
+import * as preact from './index.js';
+if (typeof module < 'u') module.exports = preact;
+else self.preact = preact;
diff --git a/preact/src/clone-element.js b/preact/src/clone-element.js
new file mode 100644
index 0000000..4cff226
--- /dev/null
+++ b/preact/src/clone-element.js
@@ -0,0 +1,34 @@
+import { assign, slice } from './util';
+import { createVNode } from './create-element';
+
+/**
+ * Clones the given VNode, optionally adding attributes/props and replacing its children.
+ * @param {import('./internal').VNode} vnode The virtual DOM element to clone
+ * @param {object} props Attributes/props to add when cloning
+ * @param {Array<import('./internal').ComponentChildren>} rest Any additional arguments will be used as replacement children.
+ * @returns {import('./internal').VNode}
+ */
+export function cloneElement(vnode, props, children) {
+ let normalizedProps = assign({}, vnode.props),
+ key,
+ ref,
+ i;
+ for (i in props) {
+ if (i == 'key') key = props[i];
+ else if (i == 'ref') ref = props[i];
+ else normalizedProps[i] = props[i];
+ }
+
+ if (arguments.length > 2) {
+ normalizedProps.children =
+ arguments.length > 3 ? slice.call(arguments, 2) : children;
+ }
+
+ return createVNode(
+ vnode.type,
+ normalizedProps,
+ key || vnode.key,
+ ref || vnode.ref,
+ null
+ );
+}
diff --git a/preact/src/component.js b/preact/src/component.js
new file mode 100644
index 0000000..c2043af
--- /dev/null
+++ b/preact/src/component.js
@@ -0,0 +1,225 @@
+import { assign } from './util';
+import { diff, commitRoot } from './diff/index';
+import options from './options';
+import { Fragment } from './create-element';
+
+/**
+ * Base Component class. Provides `setState()` and `forceUpdate()`, which
+ * trigger rendering
+ * @param {object} props The initial component props
+ * @param {object} context The initial context from parent components'
+ * getChildContext
+ */
+export function Component(props, context) {
+ this.props = props;
+ this.context = context;
+}
+
+/**
+ * Update component state and schedule a re-render.
+ * @this {import('./internal').Component}
+ * @param {object | ((s: object, p: object) => object)} update A hash of state
+ * properties to update with new values or a function that given the current
+ * state and props returns a new partial state
+ * @param {() => void} [callback] A function to be called once component state is
+ * updated
+ */
+Component.prototype.setState = function(update, callback) {
+ // only clone state when copying to nextState the first time.
+ let s;
+ if (this._nextState != null && this._nextState !== this.state) {
+ s = this._nextState;
+ } else {
+ s = this._nextState = assign({}, this.state);
+ }
+
+ if (typeof update == 'function') {
+ // Some libraries like `immer` mark the current state as readonly,
+ // preventing us from mutating it, so we need to clone it. See #2716
+ update = update(assign({}, s), this.props);
+ }
+
+ if (update) {
+ assign(s, update);
+ }
+
+ // Skip update if updater function returned null
+ if (update == null) return;
+
+ if (this._vnode) {
+ if (callback) this._renderCallbacks.push(callback);
+ enqueueRender(this);
+ }
+};
+
+/**
+ * Immediately perform a synchronous re-render of the component
+ * @this {import('./internal').Component}
+ * @param {() => void} [callback] A function to be called after component is
+ * re-rendered
+ */
+Component.prototype.forceUpdate = function(callback) {
+ if (this._vnode) {
+ // Set render mode so that we can differentiate where the render request
+ // is coming from. We need this because forceUpdate should never call
+ // shouldComponentUpdate
+ this._force = true;
+ if (callback) this._renderCallbacks.push(callback);
+ enqueueRender(this);
+ }
+};
+
+/**
+ * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
+ * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
+ * @param {object} props Props (eg: JSX attributes) received from parent
+ * element/component
+ * @param {object} state The component's current state
+ * @param {object} context Context object, as returned by the nearest
+ * ancestor's `getChildContext()`
+ * @returns {import('./index').ComponentChildren | void}
+ */
+Component.prototype.render = Fragment;
+
+/**
+ * @param {import('./internal').VNode} vnode
+ * @param {number | null} [childIndex]
+ */
+export function getDomSibling(vnode, childIndex) {
+ if (childIndex == null) {
+ // Use childIndex==null as a signal to resume the search from the vnode's sibling
+ return vnode._parent
+ ? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
+ : null;
+ }
+
+ let sibling;
+ for (; childIndex < vnode._children.length; childIndex++) {
+ sibling = vnode._children[childIndex];
+
+ if (sibling != null && sibling._dom != null) {
+ // Since updateParentDomPointers keeps _dom pointer correct,
+ // we can rely on _dom to tell us if this subtree contains a
+ // rendered DOM node, and what the first rendered DOM node is
+ return sibling._dom;
+ }
+ }
+
+ // If we get here, we have not found a DOM node in this vnode's children.
+ // We must resume from this vnode's sibling (in it's parent _children array)
+ // Only climb up and search the parent if we aren't searching through a DOM
+ // VNode (meaning we reached the DOM parent of the original vnode that began
+ // the search)
+ return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
+}
+
+/**
+ * Trigger in-place re-rendering of a component.
+ * @param {import('./internal').Component} component The component to rerender
+ */
+function renderComponent(component) {
+ let vnode = component._vnode,
+ oldDom = vnode._dom,
+ parentDom = component._parentDom;
+
+ if (parentDom) {
+ let commitQueue = [];
+ const oldVNode = assign({}, vnode);
+ oldVNode._original = vnode._original + 1;
+
+ diff(
+ parentDom,
+ vnode,
+ oldVNode,
+ component._globalContext,
+ parentDom.ownerSVGElement !== undefined,
+ vnode._hydrating != null ? [oldDom] : null,
+ commitQueue,
+ oldDom == null ? getDomSibling(vnode) : oldDom,
+ vnode._hydrating
+ );
+ commitRoot(commitQueue, vnode);
+
+ if (vnode._dom != oldDom) {
+ updateParentDomPointers(vnode);
+ }
+ }
+}
+
+/**
+ * @param {import('./internal').VNode} vnode
+ */
+function updateParentDomPointers(vnode) {
+ if ((vnode = vnode._parent) != null && vnode._component != null) {
+ vnode._dom = vnode._component.base = null;
+ for (let i = 0; i < vnode._children.length; i++) {
+ let child = vnode._children[i];
+ if (child != null && child._dom != null) {
+ vnode._dom = vnode._component.base = child._dom;
+ break;
+ }
+ }
+
+ return updateParentDomPointers(vnode);
+ }
+}
+
+/**
+ * The render queue
+ * @type {Array<import('./internal').Component>}
+ */
+let rerenderQueue = [];
+
+/**
+ * Asynchronously schedule a callback
+ * @type {(cb: () => void) => void}
+ */
+/* istanbul ignore next */
+// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
+const defer =
+ typeof Promise == 'function'
+ ? Promise.prototype.then.bind(Promise.resolve())
+ : setTimeout;
+
+/*
+ * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
+ * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
+ * do, and when their effects will be applied. See the links below for some further reading on designing
+ * asynchronous APIs.
+ * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
+ * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
+ */
+
+let prevDebounce;
+
+/**
+ * Enqueue a rerender of a component
+ * @param {import('./internal').Component} c The component to rerender
+ */
+export function enqueueRender(c) {
+ if (
+ (!c._dirty &&
+ (c._dirty = true) &&
+ rerenderQueue.push(c) &&
+ !process._rerenderCount++) ||
+ prevDebounce !== options.debounceRendering
+ ) {
+ prevDebounce = options.debounceRendering;
+ (prevDebounce || defer)(process);
+ }
+}
+
+/** Flush the render queue by rerendering all queued components */
+function process() {
+ let queue;
+ while ((process._rerenderCount = rerenderQueue.length)) {
+ queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
+ rerenderQueue = [];
+ // Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
+ // process() calls from getting scheduled while `queue` is still being consumed.
+ queue.some(c => {
+ if (c._dirty) renderComponent(c);
+ });
+ }
+}
+process._rerenderCount = 0;
diff --git a/preact/src/constants.js b/preact/src/constants.js
new file mode 100644
index 0000000..dddc9a3
--- /dev/null
+++ b/preact/src/constants.js
@@ -0,0 +1,3 @@
+export const EMPTY_OBJ = {};
+export const EMPTY_ARR = [];
+export const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
diff --git a/preact/src/create-context.js b/preact/src/create-context.js
new file mode 100644
index 0000000..750517d
--- /dev/null
+++ b/preact/src/create-context.js
@@ -0,0 +1,68 @@
+import { enqueueRender } from './component';
+
+export let i = 0;
+
+export function createContext(defaultValue, contextId) {
+ contextId = '__cC' + i++;
+
+ const context = {
+ _id: contextId,
+ _defaultValue: defaultValue,
+ /** @type {import('./internal').FunctionComponent} */
+ Consumer(props, contextValue) {
+ // return props.children(
+ // context[contextId] ? context[contextId].props.value : defaultValue
+ // );
+ return props.children(contextValue);
+ },
+ /** @type {import('./internal').FunctionComponent} */
+ Provider(props) {
+ if (!this.getChildContext) {
+ let subs = [];
+ let ctx = {};
+ ctx[contextId] = this;
+
+ this.getChildContext = () => ctx;
+
+ this.shouldComponentUpdate = function(_props) {
+ if (this.props.value !== _props.value) {
+ // I think the forced value propagation here was only needed when `options.debounceRendering` was being bypassed:
+ // https://github.com/preactjs/preact/commit/4d339fb803bea09e9f198abf38ca1bf8ea4b7771#diff-54682ce380935a717e41b8bfc54737f6R358
+ // In those cases though, even with the value corrected, we're double-rendering all nodes.
+ // It might be better to just tell folks not to use force-sync mode.
+ // Currently, using `useContext()` in a class component will overwrite its `this.context` value.
+ // subs.some(c => {
+ // c.context = _props.value;
+ // enqueueRender(c);
+ // });
+
+ // subs.some(c => {
+ // c.context[contextId] = _props.value;
+ // enqueueRender(c);
+ // });
+ subs.some(enqueueRender);
+ }
+ };
+
+ this.sub = c => {
+ subs.push(c);
+ let old = c.componentWillUnmount;
+ c.componentWillUnmount = () => {
+ subs.splice(subs.indexOf(c), 1);
+ if (old) old.call(c);
+ };
+ };
+ }
+
+ return props.children;
+ }
+ };
+
+ // Devtools needs access to the context object when it
+ // encounters a Provider. This is necessary to support
+ // setting `displayName` on the context object instead
+ // of on the component itself. See:
+ // https://reactjs.org/docs/context.html#contextdisplayname
+
+ return (context.Provider._contextRef = context.Consumer.contextType = context);
+}
diff --git a/preact/src/create-element.js b/preact/src/create-element.js
new file mode 100644
index 0000000..90ee753
--- /dev/null
+++ b/preact/src/create-element.js
@@ -0,0 +1,97 @@
+import { slice } from './util';
+import options from './options';
+
+let vnodeId = 0;
+
+/**
+ * Create an virtual node (used for JSX)
+ * @param {import('./internal').VNode["type"]} type The node name or Component
+ * constructor for this virtual node
+ * @param {object | null | undefined} [props] The properties of the virtual node
+ * @param {Array<import('.').ComponentChildren>} [children] The children of the virtual node
+ * @returns {import('./internal').VNode}
+ */
+export function createElement(type, props, children) {
+ let normalizedProps = {},
+ key,
+ ref,
+ i;
+ for (i in props) {
+ if (i == 'key') key = props[i];
+ else if (i == 'ref') ref = props[i];
+ else normalizedProps[i] = props[i];
+ }
+
+ if (arguments.length > 2) {
+ normalizedProps.children =
+ arguments.length > 3 ? slice.call(arguments, 2) : children;
+ }
+
+ // If a Component VNode, check for and apply defaultProps
+ // Note: type may be undefined in development, must never error here.
+ if (typeof type == 'function' && type.defaultProps != null) {
+ for (i in type.defaultProps) {
+ if (normalizedProps[i] === undefined) {
+ normalizedProps[i] = type.defaultProps[i];
+ }
+ }
+ }
+
+ return createVNode(type, normalizedProps, key, ref, null);
+}
+
+/**
+ * Create a VNode (used internally by Preact)
+ * @param {import('./internal').VNode["type"]} type The node name or Component
+ * Constructor for this virtual node
+ * @param {object | string | number | null} props The properties of this virtual node.
+ * If this virtual node represents a text node, this is the text of the node (string or number).
+ * @param {string | number | null} key The key for this virtual node, used when
+ * diffing it against its children
+ * @param {import('./internal').VNode["ref"]} ref The ref property that will
+ * receive a reference to its created child
+ * @returns {import('./internal').VNode}
+ */
+export function createVNode(type, props, key, ref, original) {
+ // V8 seems to be better at detecting type shapes if the object is allocated from the same call site
+ // Do not inline into createElement and coerceToVNode!
+ const vnode = {
+ type,
+ props,
+ key,
+ ref,
+ _children: null,
+ _parent: null,
+ _depth: 0,
+ _dom: null,
+ // _nextDom must be initialized to undefined b/c it will eventually
+ // be set to dom.nextSibling which can return `null` and it is important
+ // to be able to distinguish between an uninitialized _nextDom and
+ // a _nextDom that has been set to `null`
+ _nextDom: undefined,
+ _component: null,
+ _hydrating: null,
+ constructor: undefined,
+ _original: original == null ? ++vnodeId : original
+ };
+
+ if (options.vnode != null) options.vnode(vnode);
+
+ return vnode;
+}
+
+export function createRef() {
+ return { current: null };
+}
+
+export function Fragment(props) {
+ return props.children;
+}
+
+/**
+ * Check if a the argument is a valid Preact VNode.
+ * @param {*} vnode
+ * @returns {vnode is import('./internal').VNode}
+ */
+export const isValidElement = vnode =>
+ vnode != null && vnode.constructor === undefined;
diff --git a/preact/src/diff/catch-error.js b/preact/src/diff/catch-error.js
new file mode 100644
index 0000000..893a076
--- /dev/null
+++ b/preact/src/diff/catch-error.js
@@ -0,0 +1,38 @@
+/**
+ * Find the closest error boundary to a thrown error and call it
+ * @param {object} error The thrown value
+ * @param {import('../internal').VNode} vnode The vnode that threw
+ * the error that was caught (except for unmounting when this parameter
+ * is the highest parent that was being unmounted)
+ */
+export function _catchError(error, vnode) {
+ /** @type {import('../internal').Component} */
+ let component, ctor, handled;
+
+ for (; (vnode = vnode._parent); ) {
+ if ((component = vnode._component) && !component._processingException) {
+ try {
+ ctor = component.constructor;
+
+ if (ctor && ctor.getDerivedStateFromError != null) {
+ component.setState(ctor.getDerivedStateFromError(error));
+ handled = component._dirty;
+ }
+
+ if (component.componentDidCatch != null) {
+ component.componentDidCatch(error);
+ handled = component._dirty;
+ }
+
+ // This is an error boundary. Mark it as having bailed out, and whether it was mid-hydration.
+ if (handled) {
+ return (component._pendingError = component);
+ }
+ } catch (e) {
+ error = e;
+ }
+ }
+ }
+
+ throw error;
+}
diff --git a/preact/src/diff/children.js b/preact/src/diff/children.js
new file mode 100644
index 0000000..204e3e4
--- /dev/null
+++ b/preact/src/diff/children.js
@@ -0,0 +1,347 @@
+import { diff, unmount, applyRef } from './index';
+import { createVNode, Fragment } from '../create-element';
+import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
+import { getDomSibling } from '../component';
+
+/**
+ * Diff the children of a virtual node
+ * @param {import('../internal').PreactElement} parentDom The DOM element whose
+ * children are being diffed
+ * @param {import('../internal').ComponentChildren[]} renderResult
+ * @param {import('../internal').VNode} newParentVNode The new virtual
+ * node whose children should be diff'ed against oldParentVNode
+ * @param {import('../internal').VNode} oldParentVNode The old virtual
+ * node whose children should be diff'ed against newParentVNode
+ * @param {object} globalContext The current context object - modified by getChildContext
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node
+ * @param {Array<import('../internal').PreactElement>} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').PreactElement} oldDom The current attached DOM
+ * element any new dom elements should be placed around. Likely `null` on first
+ * render (except when hydrating). Can be a sibling DOM element when diffing
+ * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
+ * @param {boolean} isHydrating Whether or not we are in hydration
+ */
+export function diffChildren(
+ parentDom,
+ renderResult,
+ newParentVNode,
+ oldParentVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+) {
+ let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
+
+ // This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
+ // as EMPTY_OBJ._children should be `undefined`.
+ let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
+
+ let oldChildrenLength = oldChildren.length;
+
+ newParentVNode._children = [];
+ for (i = 0; i < renderResult.length; i++) {
+ childVNode = renderResult[i];
+
+ if (childVNode == null || typeof childVNode == 'boolean') {
+ childVNode = newParentVNode._children[i] = null;
+ }
+ // If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
+ // or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
+ // it's own DOM & etc. pointers
+ else if (
+ typeof childVNode == 'string' ||
+ typeof childVNode == 'number' ||
+ // eslint-disable-next-line valid-typeof
+ typeof childVNode == 'bigint'
+ ) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ null,
+ childVNode,
+ null,
+ null,
+ childVNode
+ );
+ } else if (Array.isArray(childVNode)) {
+ childVNode = newParentVNode._children[i] = createVNode(
+ Fragment,
+ { children: childVNode },
+ null,
+ null,
+ null
+ );
+ } else if (childVNode._depth > 0) {
+ // VNode is already in use, clone it. This can happen in the following
+ // scenario:
+ // const reuse = <div />
+ // <div>{reuse}<span />{reuse}</div>
+ childVNode = newParentVNode._children[i] = createVNode(
+ childVNode.type,
+ childVNode.props,
+ childVNode.key,
+ null,
+ childVNode._original
+ );
+ } else {
+ childVNode = newParentVNode._children[i] = childVNode;
+ }
+
+ // Terser removes the `continue` here and wraps the loop body
+ // in a `if (childVNode) { ... } condition
+ if (childVNode == null) {
+ continue;
+ }
+
+ childVNode._parent = newParentVNode;
+ childVNode._depth = newParentVNode._depth + 1;
+
+ // Check if we find a corresponding element in oldChildren.
+ // If found, delete the array item by setting to `undefined`.
+ // We use `undefined`, as `null` is reserved for empty placeholders
+ // (holes).
+ oldVNode = oldChildren[i];
+
+ if (
+ oldVNode === null ||
+ (oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type)
+ ) {
+ oldChildren[i] = undefined;
+ } else {
+ // Either oldVNode === undefined or oldChildrenLength > 0,
+ // so after this loop oldVNode == null or oldVNode is a valid value.
+ for (j = 0; j < oldChildrenLength; j++) {
+ oldVNode = oldChildren[j];
+ // If childVNode is unkeyed, we only match similarly unkeyed nodes, otherwise we match by key.
+ // We always match by type (in either case).
+ if (
+ oldVNode &&
+ childVNode.key == oldVNode.key &&
+ childVNode.type === oldVNode.type
+ ) {
+ oldChildren[j] = undefined;
+ break;
+ }
+ oldVNode = null;
+ }
+ }
+
+ oldVNode = oldVNode || EMPTY_OBJ;
+
+ // Morph the old element into the new one, but don't append it to the dom yet
+ diff(
+ parentDom,
+ childVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+ );
+
+ newDom = childVNode._dom;
+
+ if ((j = childVNode.ref) && oldVNode.ref != j) {
+ if (!refs) refs = [];
+ if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
+ refs.push(j, childVNode._component || newDom, childVNode);
+ }
+
+ if (newDom != null) {
+ if (firstChildDom == null) {
+ firstChildDom = newDom;
+ }
+
+ if (
+ typeof childVNode.type == 'function' &&
+ childVNode._children != null && // Can be null if childVNode suspended
+ childVNode._children === oldVNode._children
+ ) {
+ childVNode._nextDom = oldDom = reorderChildren(
+ childVNode,
+ oldDom,
+ parentDom
+ );
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+ );
+ }
+
+ // Browsers will infer an option's `value` from `textContent` when
+ // no value is present. This essentially bypasses our code to set it
+ // later in `diff()`. It works fine in all browsers except for IE11
+ // where it breaks setting `select.value`. There it will be always set
+ // to an empty string. Re-applying an options value will fix that, so
+ // there are probably some internal data structures that aren't
+ // updated properly.
+ //
+ // To fix it we make sure to reset the inferred value, so that our own
+ // value check in `diff()` won't be skipped.
+ if (!isHydrating && newParentVNode.type === 'option') {
+ // @ts-ignore We have validated that the type of parentDOM is 'option'
+ // in the above check
+ parentDom.value = '';
+ } else if (typeof newParentVNode.type == 'function') {
+ // Because the newParentVNode is Fragment-like, we need to set it's
+ // _nextDom property to the nextSibling of its last child DOM node.
+ //
+ // `oldDom` contains the correct value here because if the last child
+ // is a Fragment-like, then oldDom has already been set to that child's _nextDom.
+ // If the last child is a DOM VNode, then oldDom will be set to that DOM
+ // node's nextSibling.
+ newParentVNode._nextDom = oldDom;
+ }
+ } else if (
+ oldDom &&
+ oldVNode._dom == oldDom &&
+ oldDom.parentNode != parentDom
+ ) {
+ // The above condition is to handle null placeholders. See test in placeholder.test.js:
+ // `efficiently replace null placeholders in parent rerenders`
+ oldDom = getDomSibling(oldVNode);
+ }
+ }
+
+ newParentVNode._dom = firstChildDom;
+
+ // Remove remaining oldChildren if there are any.
+ for (i = oldChildrenLength; i--; ) {
+ if (oldChildren[i] != null) {
+ if (
+ typeof newParentVNode.type == 'function' &&
+ oldChildren[i]._dom != null &&
+ oldChildren[i]._dom == newParentVNode._nextDom
+ ) {
+ // If the newParentVNode.__nextDom points to a dom node that is about to
+ // be unmounted, then get the next sibling of that vnode and set
+ // _nextDom to it
+ newParentVNode._nextDom = getDomSibling(oldParentVNode, i + 1);
+ }
+
+ unmount(oldChildren[i], oldChildren[i]);
+ }
+ }
+
+ // Set refs only after unmount
+ if (refs) {
+ for (i = 0; i < refs.length; i++) {
+ applyRef(refs[i], refs[++i], refs[++i]);
+ }
+ }
+}
+
+function reorderChildren(childVNode, oldDom, parentDom) {
+ for (let tmp = 0; tmp < childVNode._children.length; tmp++) {
+ let vnode = childVNode._children[tmp];
+ if (vnode) {
+ // We typically enter this code path on sCU bailout, where we copy
+ // oldVNode._children to newVNode._children. If that is the case, we need
+ // to update the old children's _parent pointer to point to the newVNode
+ // (childVNode here).
+ vnode._parent = childVNode;
+
+ if (typeof vnode.type == 'function') {
+ oldDom = reorderChildren(vnode, oldDom, parentDom);
+ } else {
+ oldDom = placeChild(
+ parentDom,
+ vnode,
+ vnode,
+ childVNode._children,
+ vnode._dom,
+ oldDom
+ );
+ }
+ }
+ }
+
+ return oldDom;
+}
+
+/**
+ * Flatten and loop through the children of a virtual node
+ * @param {import('../index').ComponentChildren} children The unflattened
+ * children of a virtual node
+ * @returns {import('../internal').VNode[]}
+ */
+export function toChildArray(children, out) {
+ out = out || [];
+ if (children == null || typeof children == 'boolean') {
+ } else if (Array.isArray(children)) {
+ children.some(child => {
+ toChildArray(child, out);
+ });
+ } else {
+ out.push(children);
+ }
+ return out;
+}
+
+function placeChild(
+ parentDom,
+ childVNode,
+ oldVNode,
+ oldChildren,
+ newDom,
+ oldDom
+) {
+ let nextDom;
+ if (childVNode._nextDom !== undefined) {
+ // Only Fragments or components that return Fragment like VNodes will
+ // have a non-undefined _nextDom. Continue the diff from the sibling
+ // of last DOM child of this child VNode
+ nextDom = childVNode._nextDom;
+
+ // Eagerly cleanup _nextDom. We don't need to persist the value because
+ // it is only used by `diffChildren` to determine where to resume the diff after
+ // diffing Components and Fragments. Once we store it the nextDOM local var, we
+ // can clean up the property
+ childVNode._nextDom = undefined;
+ } else if (
+ oldVNode == null ||
+ newDom != oldDom ||
+ newDom.parentNode == null
+ ) {
+ outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
+ parentDom.appendChild(newDom);
+ nextDom = null;
+ } else {
+ // `j<oldChildrenLength; j+=2` is an alternative to `j++<oldChildrenLength/2`
+ for (
+ let sibDom = oldDom, j = 0;
+ (sibDom = sibDom.nextSibling) && j < oldChildren.length;
+ j += 2
+ ) {
+ if (sibDom == newDom) {
+ break outer;
+ }
+ }
+ parentDom.insertBefore(newDom, oldDom);
+ nextDom = oldDom;
+ }
+ }
+
+ // If we have pre-calculated the nextDOM node, use it. Else calculate it now
+ // Strictly check for `undefined` here cuz `null` is a valid value of `nextDom`.
+ // See more detail in create-element.js:createVNode
+ if (nextDom !== undefined) {
+ oldDom = nextDom;
+ } else {
+ oldDom = newDom.nextSibling;
+ }
+
+ return oldDom;
+}
diff --git a/preact/src/diff/index.js b/preact/src/diff/index.js
new file mode 100644
index 0000000..de63843
--- /dev/null
+++ b/preact/src/diff/index.js
@@ -0,0 +1,514 @@
+import { EMPTY_OBJ } from '../constants';
+import { Component, getDomSibling } from '../component';
+import { Fragment } from '../create-element';
+import { diffChildren } from './children';
+import { diffProps, setProperty } from './props';
+import { assign, removeNode, slice } from '../util';
+import options from '../options';
+
+/**
+ * Diff two virtual nodes and apply proper changes to the DOM
+ * @param {import('../internal').PreactElement} parentDom The parent of the DOM element
+ * @param {import('../internal').VNode} newVNode The new virtual node
+ * @param {import('../internal').VNode} oldVNode The old virtual node
+ * @param {object} globalContext The current context object. Modified by getChildContext
+ * @param {boolean} isSvg Whether or not this element is an SVG node
+ * @param {Array<import('../internal').PreactElement>} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').PreactElement} oldDom The current attached DOM
+ * element any new dom elements should be placed around. Likely `null` on first
+ * render (except when hydrating). Can be a sibling DOM element when diffing
+ * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
+ * @param {boolean} [isHydrating] Whether or not we are in hydration
+ */
+export function diff(
+ parentDom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+) {
+ let tmp,
+ newType = newVNode.type;
+
+ // When passing through createElement it assigns the object
+ // constructor as undefined. This to prevent JSON-injection.
+ if (newVNode.constructor !== undefined) return null;
+
+ // If the previous diff bailed out, resume creating/hydrating.
+ if (oldVNode._hydrating != null) {
+ isHydrating = oldVNode._hydrating;
+ oldDom = newVNode._dom = oldVNode._dom;
+ // if we resume, we want the tree to be "unlocked"
+ newVNode._hydrating = null;
+ excessDomChildren = [oldDom];
+ }
+
+ if ((tmp = options._diff)) tmp(newVNode);
+
+ try {
+ outer: if (typeof newType == 'function') {
+ let c, isNew, oldProps, oldState, snapshot, clearProcessingException;
+ let newProps = newVNode.props;
+
+ // Necessary for createContext api. Setting this property will pass
+ // the context value as `this.context` just for this component.
+ tmp = newType.contextType;
+ let provider = tmp && globalContext[tmp._id];
+ let componentContext = tmp
+ ? provider
+ ? provider.props.value
+ : tmp._defaultValue
+ : globalContext;
+
+ // Get component and set it to `c`
+ if (oldVNode._component) {
+ c = newVNode._component = oldVNode._component;
+ clearProcessingException = c._processingException = c._pendingError;
+ } else {
+ // Instantiate the new component
+ if ('prototype' in newType && newType.prototype.render) {
+ // @ts-ignore The check above verifies that newType is suppose to be constructed
+ newVNode._component = c = new newType(newProps, componentContext); // eslint-disable-line new-cap
+ } else {
+ // @ts-ignore Trust me, Component implements the interface we want
+ newVNode._component = c = new Component(newProps, componentContext);
+ c.constructor = newType;
+ c.render = doRender;
+ }
+ if (provider) provider.sub(c);
+
+ c.props = newProps;
+ if (!c.state) c.state = {};
+ c.context = componentContext;
+ c._globalContext = globalContext;
+ isNew = c._dirty = true;
+ c._renderCallbacks = [];
+ }
+
+ // Invoke getDerivedStateFromProps
+ if (c._nextState == null) {
+ c._nextState = c.state;
+ }
+ if (newType.getDerivedStateFromProps != null) {
+ if (c._nextState == c.state) {
+ c._nextState = assign({}, c._nextState);
+ }
+
+ assign(
+ c._nextState,
+ newType.getDerivedStateFromProps(newProps, c._nextState)
+ );
+ }
+
+ oldProps = c.props;
+ oldState = c.state;
+
+ // Invoke pre-render lifecycle methods
+ if (isNew) {
+ if (
+ newType.getDerivedStateFromProps == null &&
+ c.componentWillMount != null
+ ) {
+ c.componentWillMount();
+ }
+
+ if (c.componentDidMount != null) {
+ c._renderCallbacks.push(c.componentDidMount);
+ }
+ } else {
+ if (
+ newType.getDerivedStateFromProps == null &&
+ newProps !== oldProps &&
+ c.componentWillReceiveProps != null
+ ) {
+ c.componentWillReceiveProps(newProps, componentContext);
+ }
+
+ if (
+ (!c._force &&
+ c.shouldComponentUpdate != null &&
+ c.shouldComponentUpdate(
+ newProps,
+ c._nextState,
+ componentContext
+ ) === false) ||
+ newVNode._original === oldVNode._original
+ ) {
+ c.props = newProps;
+ c.state = c._nextState;
+ // More info about this here: https://gist.github.com/JoviDeCroock/bec5f2ce93544d2e6070ef8e0036e4e8
+ if (newVNode._original !== oldVNode._original) c._dirty = false;
+ c._vnode = newVNode;
+ newVNode._dom = oldVNode._dom;
+ newVNode._children = oldVNode._children;
+ newVNode._children.forEach(vnode => {
+ if (vnode) vnode._parent = newVNode;
+ });
+ if (c._renderCallbacks.length) {
+ commitQueue.push(c);
+ }
+
+ break outer;
+ }
+
+ if (c.componentWillUpdate != null) {
+ c.componentWillUpdate(newProps, c._nextState, componentContext);
+ }
+
+ if (c.componentDidUpdate != null) {
+ c._renderCallbacks.push(() => {
+ c.componentDidUpdate(oldProps, oldState, snapshot);
+ });
+ }
+ }
+
+ c.context = componentContext;
+ c.props = newProps;
+ c.state = c._nextState;
+
+ if ((tmp = options._render)) tmp(newVNode);
+
+ c._dirty = false;
+ c._vnode = newVNode;
+ c._parentDom = parentDom;
+
+ tmp = c.render(c.props, c.state, c.context);
+
+ // Handle setState called in render, see #2553
+ c.state = c._nextState;
+
+ if (c.getChildContext != null) {
+ globalContext = assign(assign({}, globalContext), c.getChildContext());
+ }
+
+ if (!isNew && c.getSnapshotBeforeUpdate != null) {
+ snapshot = c.getSnapshotBeforeUpdate(oldProps, oldState);
+ }
+
+ let isTopLevelFragment =
+ tmp != null && tmp.type === Fragment && tmp.key == null;
+ let renderResult = isTopLevelFragment ? tmp.props.children : tmp;
+
+ diffChildren(
+ parentDom,
+ Array.isArray(renderResult) ? renderResult : [renderResult],
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ oldDom,
+ isHydrating
+ );
+
+ c.base = newVNode._dom;
+
+ // We successfully rendered this VNode, unset any stored hydration/bailout state:
+ newVNode._hydrating = null;
+
+ if (c._renderCallbacks.length) {
+ commitQueue.push(c);
+ }
+
+ if (clearProcessingException) {
+ c._pendingError = c._processingException = null;
+ }
+
+ c._force = false;
+ } else if (
+ excessDomChildren == null &&
+ newVNode._original === oldVNode._original
+ ) {
+ newVNode._children = oldVNode._children;
+ newVNode._dom = oldVNode._dom;
+ } else {
+ newVNode._dom = diffElementNodes(
+ oldVNode._dom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ isHydrating
+ );
+ }
+
+ if ((tmp = options.diffed)) tmp(newVNode);
+ } catch (e) {
+ newVNode._original = null;
+ // if hydrating or creating initial tree, bailout preserves DOM:
+ if (isHydrating || excessDomChildren != null) {
+ newVNode._dom = oldDom;
+ newVNode._hydrating = !!isHydrating;
+ excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
+ // ^ could possibly be simplified to:
+ // excessDomChildren.length = 0;
+ }
+ options._catchError(e, newVNode, oldVNode);
+ }
+}
+
+/**
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {import('../internal').VNode} root
+ */
+export function commitRoot(commitQueue, root) {
+ if (options._commit) options._commit(root, commitQueue);
+
+ commitQueue.some(c => {
+ try {
+ // @ts-ignore Reuse the commitQueue variable here so the type changes
+ commitQueue = c._renderCallbacks;
+ c._renderCallbacks = [];
+ commitQueue.some(cb => {
+ // @ts-ignore See above ts-ignore on commitQueue
+ cb.call(c);
+ });
+ } catch (e) {
+ options._catchError(e, c._vnode);
+ }
+ });
+}
+
+/**
+ * Diff two virtual nodes representing DOM element
+ * @param {import('../internal').PreactElement} dom The DOM element representing
+ * the virtual nodes being diffed
+ * @param {import('../internal').VNode} newVNode The new virtual node
+ * @param {import('../internal').VNode} oldVNode The old virtual node
+ * @param {object} globalContext The current context object
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node
+ * @param {*} excessDomChildren
+ * @param {Array<import('../internal').Component>} commitQueue List of components
+ * which have callbacks to invoke in commitRoot
+ * @param {boolean} isHydrating Whether or not we are in hydration
+ * @returns {import('../internal').PreactElement}
+ */
+function diffElementNodes(
+ dom,
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg,
+ excessDomChildren,
+ commitQueue,
+ isHydrating
+) {
+ let oldProps = oldVNode.props;
+ let newProps = newVNode.props;
+ let nodeType = newVNode.type;
+ let i = 0;
+
+ // Tracks entering and exiting SVG namespace when descending through the tree.
+ if (nodeType === 'svg') isSvg = true;
+
+ if (excessDomChildren != null) {
+ for (; i < excessDomChildren.length; i++) {
+ const child = excessDomChildren[i];
+
+ // if newVNode matches an element in excessDomChildren or the `dom`
+ // argument matches an element in excessDomChildren, remove it from
+ // excessDomChildren so it isn't later removed in diffChildren
+ if (
+ child &&
+ (child === dom ||
+ (nodeType ? child.localName == nodeType : child.nodeType == 3))
+ ) {
+ dom = child;
+ excessDomChildren[i] = null;
+ break;
+ }
+ }
+ }
+
+ if (dom == null) {
+ if (nodeType === null) {
+ // @ts-ignore createTextNode returns Text, we expect PreactElement
+ return document.createTextNode(newProps);
+ }
+
+ if (isSvg) {
+ dom = document.createElementNS(
+ 'http://www.w3.org/2000/svg',
+ // @ts-ignore We know `newVNode.type` is a string
+ nodeType
+ );
+ } else {
+ dom = document.createElement(
+ // @ts-ignore We know `newVNode.type` is a string
+ nodeType,
+ newProps.is && newProps
+ );
+ }
+
+ // we created a new parent, so none of the previously attached children can be reused:
+ excessDomChildren = null;
+ // we are creating a new node, so we can assume this is a new subtree (in case we are hydrating), this deopts the hydrate
+ isHydrating = false;
+ }
+
+ if (nodeType === null) {
+ // During hydration, we still have to split merged text from SSR'd HTML.
+ if (oldProps !== newProps && (!isHydrating || dom.data !== newProps)) {
+ dom.data = newProps;
+ }
+ } else {
+ // If excessDomChildren was not null, repopulate it with the current element's children:
+ excessDomChildren = excessDomChildren && slice.call(dom.childNodes);
+
+ oldProps = oldVNode.props || EMPTY_OBJ;
+
+ let oldHtml = oldProps.dangerouslySetInnerHTML;
+ let newHtml = newProps.dangerouslySetInnerHTML;
+
+ // During hydration, props are not diffed at all (including dangerouslySetInnerHTML)
+ // @TODO we should warn in debug mode when props don't match here.
+ if (!isHydrating) {
+ // But, if we are in a situation where we are using existing DOM (e.g. replaceNode)
+ // we should read the existing DOM attributes to diff them
+ if (excessDomChildren != null) {
+ oldProps = {};
+ for (i = 0; i < dom.attributes.length; i++) {
+ oldProps[dom.attributes[i].name] = dom.attributes[i].value;
+ }
+ }
+
+ if (newHtml || oldHtml) {
+ // Avoid re-applying the same '__html' if it did not changed between re-render
+ if (
+ !newHtml ||
+ ((!oldHtml || newHtml.__html != oldHtml.__html) &&
+ newHtml.__html !== dom.innerHTML)
+ ) {
+ dom.innerHTML = (newHtml && newHtml.__html) || '';
+ }
+ }
+ }
+
+ diffProps(dom, newProps, oldProps, isSvg, isHydrating);
+
+ // If the new vnode didn't have dangerouslySetInnerHTML, diff its children
+ if (newHtml) {
+ newVNode._children = [];
+ } else {
+ i = newVNode.props.children;
+ diffChildren(
+ dom,
+ Array.isArray(i) ? i : [i],
+ newVNode,
+ oldVNode,
+ globalContext,
+ isSvg && nodeType !== 'foreignObject',
+ excessDomChildren,
+ commitQueue,
+ excessDomChildren
+ ? excessDomChildren[0]
+ : oldVNode._children && getDomSibling(oldVNode, 0),
+ isHydrating
+ );
+
+ // Remove children that are not part of any vnode.
+ if (excessDomChildren != null) {
+ for (i = excessDomChildren.length; i--; ) {
+ if (excessDomChildren[i] != null) removeNode(excessDomChildren[i]);
+ }
+ }
+ }
+
+ // (as above, don't diff props during hydration)
+ if (!isHydrating) {
+ if (
+ 'value' in newProps &&
+ (i = newProps.value) !== undefined &&
+ // #2756 For the <progress>-element the initial value is 0,
+ // despite the attribute not being present. When the attribute
+ // is missing the progress bar is treated as indeterminate.
+ // To fix that we'll always update it when it is 0 for progress elements
+ (i !== dom.value || (nodeType === 'progress' && !i))
+ ) {
+ setProperty(dom, 'value', i, oldProps.value, false);
+ }
+ if (
+ 'checked' in newProps &&
+ (i = newProps.checked) !== undefined &&
+ i !== dom.checked
+ ) {
+ setProperty(dom, 'checked', i, oldProps.checked, false);
+ }
+ }
+ }
+
+ return dom;
+}
+
+/**
+ * Invoke or update a ref, depending on whether it is a function or object ref.
+ * @param {object|function} ref
+ * @param {any} value
+ * @param {import('../internal').VNode} vnode
+ */
+export function applyRef(ref, value, vnode) {
+ try {
+ if (typeof ref == 'function') ref(value);
+ else ref.current = value;
+ } catch (e) {
+ options._catchError(e, vnode);
+ }
+}
+
+/**
+ * Unmount a virtual node from the tree and apply DOM changes
+ * @param {import('../internal').VNode} vnode The virtual node to unmount
+ * @param {import('../internal').VNode} parentVNode The parent of the VNode that
+ * initiated the unmount
+ * @param {boolean} [skipRemove] Flag that indicates that a parent node of the
+ * current element is already detached from the DOM.
+ */
+export function unmount(vnode, parentVNode, skipRemove) {
+ let r;
+ if (options.unmount) options.unmount(vnode);
+
+ if ((r = vnode.ref)) {
+ if (!r.current || r.current === vnode._dom) applyRef(r, null, parentVNode);
+ }
+
+ if ((r = vnode._component) != null) {
+ if (r.componentWillUnmount) {
+ try {
+ r.componentWillUnmount();
+ } catch (e) {
+ options._catchError(e, parentVNode);
+ }
+ }
+
+ r.base = r._parentDom = null;
+ }
+
+ if ((r = vnode._children)) {
+ for (let i = 0; i < r.length; i++) {
+ if (r[i]) {
+ unmount(r[i], parentVNode, typeof vnode.type != 'function');
+ }
+ }
+ }
+
+ if (!skipRemove && vnode._dom != null) removeNode(vnode._dom);
+
+ // Must be set to `undefined` to properly clean up `_nextDom`
+ // for which `null` is a valid value. See comment in `create-element.js`
+ vnode._dom = vnode._nextDom = undefined;
+}
+
+/** The `.render()` method for a PFC backing instance. */
+function doRender(props, state, context) {
+ return this.constructor(props, context);
+}
diff --git a/preact/src/diff/props.js b/preact/src/diff/props.js
new file mode 100644
index 0000000..472d997
--- /dev/null
+++ b/preact/src/diff/props.js
@@ -0,0 +1,158 @@
+import { IS_NON_DIMENSIONAL } from '../constants';
+import options from '../options';
+
+/**
+ * Diff the old and new properties of a VNode and apply changes to the DOM node
+ * @param {import('../internal').PreactElement} dom The DOM node to apply
+ * changes to
+ * @param {object} newProps The new props
+ * @param {object} oldProps The old props
+ * @param {boolean} isSvg Whether or not this node is an SVG node
+ * @param {boolean} hydrate Whether or not we are in hydration mode
+ */
+export function diffProps(dom, newProps, oldProps, isSvg, hydrate) {
+ let i;
+
+ for (i in oldProps) {
+ if (i !== 'children' && i !== 'key' && !(i in newProps)) {
+ setProperty(dom, i, null, oldProps[i], isSvg);
+ }
+ }
+
+ for (i in newProps) {
+ if (
+ (!hydrate || typeof newProps[i] == 'function') &&
+ i !== 'children' &&
+ i !== 'key' &&
+ i !== 'value' &&
+ i !== 'checked' &&
+ oldProps[i] !== newProps[i]
+ ) {
+ setProperty(dom, i, newProps[i], oldProps[i], isSvg);
+ }
+ }
+}
+
+function setStyle(style, key, value) {
+ if (key[0] === '-') {
+ style.setProperty(key, value);
+ } else if (value == null) {
+ style[key] = '';
+ } else if (typeof value != 'number' || IS_NON_DIMENSIONAL.test(key)) {
+ style[key] = value;
+ } else {
+ style[key] = value + 'px';
+ }
+}
+
+/**
+ * Set a property value on a DOM node
+ * @param {import('../internal').PreactElement} dom The DOM node to modify
+ * @param {string} name The name of the property to set
+ * @param {*} value The value to set the property to
+ * @param {*} oldValue The old value the property had
+ * @param {boolean} isSvg Whether or not this DOM node is an SVG node or not
+ */
+export function setProperty(dom, name, value, oldValue, isSvg) {
+ let useCapture;
+
+ o: if (name === 'style') {
+ if (typeof value == 'string') {
+ dom.style.cssText = value;
+ } else {
+ if (typeof oldValue == 'string') {
+ dom.style.cssText = oldValue = '';
+ }
+
+ if (oldValue) {
+ for (name in oldValue) {
+ if (!(value && name in value)) {
+ setStyle(dom.style, name, '');
+ }
+ }
+ }
+
+ if (value) {
+ for (name in value) {
+ if (!oldValue || value[name] !== oldValue[name]) {
+ setStyle(dom.style, name, value[name]);
+ }
+ }
+ }
+ }
+ }
+ // Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6
+ else if (name[0] === 'o' && name[1] === 'n') {
+ useCapture = name !== (name = name.replace(/Capture$/, ''));
+
+ // Infer correct casing for DOM built-in events:
+ if (name.toLowerCase() in dom) name = name.toLowerCase().slice(2);
+ else name = name.slice(2);
+
+ if (!dom._listeners) dom._listeners = {};
+ dom._listeners[name + useCapture] = value;
+
+ if (value) {
+ if (!oldValue) {
+ const handler = useCapture ? eventProxyCapture : eventProxy;
+ dom.addEventListener(name, handler, useCapture);
+ }
+ } else {
+ const handler = useCapture ? eventProxyCapture : eventProxy;
+ dom.removeEventListener(name, handler, useCapture);
+ }
+ } else if (name !== 'dangerouslySetInnerHTML') {
+ if (isSvg) {
+ // Normalize incorrect prop usage for SVG:
+ // - xlink:href / xlinkHref --> href (xlink:href was removed from SVG and isn't needed)
+ // - className --> class
+ name = name.replace(/xlink[H:h]/, 'h').replace(/sName$/, 's');
+ } else if (
+ name !== 'href' &&
+ name !== 'list' &&
+ name !== 'form' &&
+ // Default value in browsers is `-1` and an empty string is
+ // cast to `0` instead
+ name !== 'tabIndex' &&
+ name !== 'download' &&
+ name in dom
+ ) {
+ try {
+ dom[name] = value == null ? '' : value;
+ // labelled break is 1b smaller here than a return statement (sorry)
+ break o;
+ } catch (e) {}
+ }
+
+ // ARIA-attributes have a different notion of boolean values.
+ // The value `false` is different from the attribute not
+ // existing on the DOM, so we can't remove it. For non-boolean
+ // ARIA-attributes we could treat false as a removal, but the
+ // amount of exceptions would cost us too many bytes. On top of
+ // that other VDOM frameworks also always stringify `false`.
+
+ if (typeof value === 'function') {
+ // never serialize functions as attribute values
+ } else if (
+ value != null &&
+ (value !== false || (name[0] === 'a' && name[1] === 'r'))
+ ) {
+ dom.setAttribute(name, value);
+ } else {
+ dom.removeAttribute(name);
+ }
+ }
+}
+
+/**
+ * Proxy an event to hooked event handlers
+ * @param {Event} e The event object from the browser
+ * @private
+ */
+function eventProxy(e) {
+ this._listeners[e.type + false](options.event ? options.event(e) : e);
+}
+
+function eventProxyCapture(e) {
+ this._listeners[e.type + true](options.event ? options.event(e) : e);
+}
diff --git a/preact/src/index.d.ts b/preact/src/index.d.ts
new file mode 100644
index 0000000..e55f978
--- /dev/null
+++ b/preact/src/index.d.ts
@@ -0,0 +1,310 @@
+export as namespace preact;
+
+import { JSXInternal } from './jsx';
+
+export import JSX = JSXInternal;
+
+//
+// Preact Virtual DOM
+// -----------------------------------
+
+export interface VNode<P = {}> {
+ type: ComponentType<P> | string;
+ props: P & { children: ComponentChildren };
+ key: Key;
+ /**
+ * ref is not guaranteed by React.ReactElement, for compatibility reasons
+ * with popular react libs we define it as optional too
+ */
+ ref?: Ref<any> | null;
+ /**
+ * The time this `vnode` started rendering. Will only be set when
+ * the devtools are attached.
+ * Default value: `0`
+ */
+ startTime?: number;
+ /**
+ * The time that the rendering of this `vnode` was completed. Will only be
+ * set when the devtools are attached.
+ * Default value: `-1`
+ */
+ endTime?: number;
+}
+
+//
+// Preact Component interface
+// -----------------------------------
+
+export type Key = string | number | any;
+
+export type RefObject<T> = { current: T | null };
+export type RefCallback<T> = (instance: T | null) => void;
+export type Ref<T> = RefObject<T> | RefCallback<T>;
+
+export type ComponentChild =
+ | VNode<any>
+ | object
+ | string
+ | number
+ | bigint
+ | boolean
+ | null
+ | undefined;
+export type ComponentChildren = ComponentChild[] | ComponentChild;
+
+export interface Attributes {
+ key?: Key;
+ jsx?: boolean;
+}
+
+export interface ClassAttributes<T> extends Attributes {
+ ref?: Ref<T>;
+}
+
+export interface PreactDOMAttributes {
+ children?: ComponentChildren;
+ dangerouslySetInnerHTML?: {
+ __html: string;
+ };
+}
+
+export type RenderableProps<P, RefType = any> = P &
+ Readonly<Attributes & { children?: ComponentChildren; ref?: Ref<RefType> }>;
+
+export type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
+export type ComponentFactory<P = {}> = ComponentType<P>;
+
+export type ComponentProps<
+ C extends ComponentType<any> | keyof JSXInternal.IntrinsicElements
+> = C extends ComponentType<infer P>
+ ? P
+ : C extends keyof JSXInternal.IntrinsicElements
+ ? JSXInternal.IntrinsicElements[C]
+ : never;
+
+export interface FunctionComponent<P = {}> {
+ (props: RenderableProps<P>, context?: any): VNode<any> | null;
+ displayName?: string;
+ defaultProps?: Partial<P>;
+}
+export interface FunctionalComponent<P = {}> extends FunctionComponent<P> {}
+
+export interface ComponentClass<P = {}, S = {}> {
+ new (props: P, context?: any): Component<P, S>;
+ displayName?: string;
+ defaultProps?: Partial<P>;
+ contextType?: Context<any>;
+ getDerivedStateFromProps?(
+ props: Readonly<P>,
+ state: Readonly<S>
+ ): Partial<S> | null;
+ getDerivedStateFromError?(error: any): Partial<S> | null;
+}
+export interface ComponentConstructor<P = {}, S = {}>
+ extends ComponentClass<P, S> {}
+
+// Type alias for a component instance considered generally, whether stateless or stateful.
+export type AnyComponent<P = {}, S = {}> =
+ | FunctionComponent<P>
+ | Component<P, S>;
+
+export interface Component<P = {}, S = {}> {
+ componentWillMount?(): void;
+ componentDidMount?(): void;
+ componentWillUnmount?(): void;
+ getChildContext?(): object;
+ componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
+ shouldComponentUpdate?(
+ nextProps: Readonly<P>,
+ nextState: Readonly<S>,
+ nextContext: any
+ ): boolean;
+ componentWillUpdate?(
+ nextProps: Readonly<P>,
+ nextState: Readonly<S>,
+ nextContext: any
+ ): void;
+ getSnapshotBeforeUpdate?(oldProps: Readonly<P>, oldState: Readonly<S>): any;
+ componentDidUpdate?(
+ previousProps: Readonly<P>,
+ previousState: Readonly<S>,
+ snapshot: any
+ ): void;
+ componentDidCatch?(error: any, errorInfo: any): void;
+}
+
+export abstract class Component<P, S> {
+ constructor(props?: P, context?: any);
+
+ static displayName?: string;
+ static defaultProps?: any;
+ static contextType?: Context<any>;
+
+ // Static members cannot reference class type parameters. This is not
+ // supported in TypeScript. Reusing the same type arguments from `Component`
+ // will lead to an impossible state where one cannot satisfy the type
+ // constraint under no circumstances, see #1356.In general type arguments
+ // seem to be a bit buggy and not supported well at the time of this
+ // writing with TS 3.3.3333.
+ static getDerivedStateFromProps?(
+ props: Readonly<object>,
+ state: Readonly<object>
+ ): object | null;
+ static getDerivedStateFromError?(error: any): object | null;
+
+ state: Readonly<S>;
+ props: RenderableProps<P>;
+ context: any;
+ base?: Element | Text;
+
+ // From https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e836acc75a78cf0655b5dfdbe81d69fdd4d8a252/types/react/index.d.ts#L402
+ // // We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
+ // // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
+ setState<K extends keyof S>(
+ state:
+ | ((
+ prevState: Readonly<S>,
+ props: Readonly<P>
+ ) => Pick<S, K> | Partial<S> | null)
+ | (Pick<S, K> | Partial<S> | null),
+ callback?: () => void
+ ): void;
+
+ forceUpdate(callback?: () => void): void;
+
+ abstract render(
+ props?: RenderableProps<P>,
+ state?: Readonly<S>,
+ context?: any
+ ): ComponentChild;
+}
+
+//
+// Preact createElement
+// -----------------------------------
+
+export function createElement(
+ type: string,
+ props:
+ | (JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any>)
+ | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function createElement<P>(
+ type: ComponentType<P>,
+ props: (Attributes & P) | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export namespace createElement {
+ export import JSX = JSXInternal;
+}
+
+export function h(
+ type: string,
+ props:
+ | (JSXInternal.HTMLAttributes &
+ JSXInternal.SVGAttributes &
+ Record<string, any>)
+ | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function h<P>(
+ type: ComponentType<P>,
+ props: (Attributes & P) | null,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export namespace h {
+ export import JSX = JSXInternal;
+}
+
+//
+// Preact render
+// -----------------------------------
+
+export function render(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment,
+ replaceNode?: Element | Text
+): void;
+export function hydrate(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment
+): void;
+export function cloneElement(
+ vnode: VNode<any>,
+ props?: any,
+ ...children: ComponentChildren[]
+): VNode<any>;
+export function cloneElement<P>(
+ vnode: VNode<P>,
+ props?: any,
+ ...children: ComponentChildren[]
+): VNode<P>;
+
+//
+// Preact Built-in Components
+// -----------------------------------
+
+// TODO: Revisit what the public type of this is...
+export const Fragment: ComponentClass<{}, {}>;
+
+//
+// Preact options
+// -----------------------------------
+
+/**
+ * Global options for preact
+ */
+export interface Options {
+ /** Attach a hook that is invoked whenever a VNode is created. */
+ vnode?(vnode: VNode): void;
+ /** Attach a hook that is invoked immediately before a vnode is unmounted. */
+ unmount?(vnode: VNode): void;
+ /** Attach a hook that is invoked after a vnode has rendered. */
+ diffed?(vnode: VNode): void;
+ event?(e: Event): any;
+ requestAnimationFrame?: typeof requestAnimationFrame;
+ debounceRendering?(cb: () => void): void;
+ useDebugValue?(value: string | number): void;
+ _addHookName?(name: string | number): void;
+ __suspenseDidResolve?(vnode: VNode, cb: () => void): void;
+ // __canSuspenseResolve?(vnode: VNode, cb: () => void): void;
+}
+
+export const options: Options;
+
+//
+// Preact helpers
+// -----------------------------------
+export function createRef<T = any>(): RefObject<T>;
+export function toChildArray(
+ children: ComponentChildren
+): Array<VNode | string | number>;
+export function isValidElement(vnode: any): vnode is VNode;
+
+//
+// Context
+// -----------------------------------
+export interface Consumer<T>
+ extends FunctionComponent<{
+ children: (value: T) => ComponentChildren;
+ }> {}
+export interface PreactConsumer<T> extends Consumer<T> {}
+
+export interface Provider<T>
+ extends FunctionComponent<{
+ value: T;
+ children: ComponentChildren;
+ }> {}
+export interface PreactProvider<T> extends Provider<T> {}
+
+export interface Context<T> {
+ Consumer: Consumer<T>;
+ Provider: Provider<T>;
+ displayName?: string;
+}
+export interface PreactContext<T> extends Context<T> {}
+
+export function createContext<T>(defaultValue: T): Context<T>;
diff --git a/preact/src/index.js b/preact/src/index.js
new file mode 100644
index 0000000..ae76ccb
--- /dev/null
+++ b/preact/src/index.js
@@ -0,0 +1,13 @@
+export { render, hydrate } from './render';
+export {
+ createElement,
+ createElement as h,
+ Fragment,
+ createRef,
+ isValidElement
+} from './create-element';
+export { Component } from './component';
+export { cloneElement } from './clone-element';
+export { createContext } from './create-context';
+export { toChildArray } from './diff/children';
+export { default as options } from './options';
diff --git a/preact/src/internal.d.ts b/preact/src/internal.d.ts
new file mode 100644
index 0000000..4592143
--- /dev/null
+++ b/preact/src/internal.d.ts
@@ -0,0 +1,146 @@
+import * as preact from './index';
+
+export enum HookType {
+ useState = 1,
+ useReducer = 2,
+ useEffect = 3,
+ useLayoutEffect = 4,
+ useRef = 5,
+ useImperativeHandle = 6,
+ useMemo = 7,
+ useCallback = 8,
+ useContext = 9,
+ useErrorBoundary = 10,
+ // Not a real hook, but the devtools treat is as such
+ useDebugvalue = 11
+}
+
+export interface DevSource {
+ fileName: string;
+ lineNumber: number;
+}
+
+export interface Options extends preact.Options {
+ /** Attach a hook that is invoked before render, mainly to check the arguments. */
+ _root?(
+ vnode: ComponentChild,
+ parent: Element | Document | ShadowRoot | DocumentFragment
+ ): void;
+ /** Attach a hook that is invoked before a vnode is diffed. */
+ _diff?(vnode: VNode): void;
+ /** Attach a hook that is invoked after a tree was mounted or was updated. */
+ _commit?(vnode: VNode, commitQueue: Component[]): void;
+ /** Attach a hook that is invoked before a vnode has rendered. */
+ _render?(vnode: VNode): void;
+ /** Attach a hook that is invoked before a hook's state is queried. */
+ _hook?(component: Component, index: number, type: HookType): void;
+ /** Bypass effect execution. Currenty only used in devtools for hooks inspection */
+ _skipEffects?: boolean;
+ /** Attach a hook that is invoked after an error is caught in a component but before calling lifecycle hooks */
+ _catchError(error: any, vnode: VNode, oldVNode?: VNode | undefined): void;
+}
+
+export type ComponentChild =
+ | VNode<any>
+ | string
+ | number
+ | boolean
+ | null
+ | undefined;
+export type ComponentChildren = ComponentChild[] | ComponentChild;
+
+export interface FunctionComponent<P = {}> extends preact.FunctionComponent<P> {
+ // Internally, createContext uses `contextType` on a Function component to
+ // implement the Consumer component
+ contextType?: PreactContext;
+
+ // Internally, createContext stores a ref to the context object on the Provider
+ // Function component to help devtools
+ _contextRef?: PreactContext;
+
+ // Define these properties as undefined on FunctionComponent to get rid of
+ // some errors in `diff()`
+ getDerivedStateFromProps?: undefined;
+ getDerivedStateFromError?: undefined;
+}
+
+export interface ComponentClass<P = {}> extends preact.ComponentClass<P> {
+ _contextRef?: any;
+
+ // Override public contextType with internal PreactContext type
+ contextType?: PreactContext;
+}
+
+// Redefine ComponentType using our new internal FunctionComponent interface above
+export type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
+
+export interface PreactElement extends HTMLElement {
+ _children?: VNode<any> | null;
+ /** Event listeners to support event delegation */
+ _listeners?: Record<string, (e: Event) => void>;
+
+ // Preact uses this attribute to detect SVG nodes
+ ownerSVGElement?: SVGElement | null;
+
+ // style: HTMLElement["style"]; // From HTMLElement
+
+ data?: string | number; // From Text node
+}
+
+// We use the `current` property to differentiate between the two kinds of Refs so
+// internally we'll define `current` on both to make TypeScript happy
+type RefObject<T> = { current: T | null };
+type RefCallback<T> = { (instance: T | null): void; current: undefined };
+type Ref<T> = RefObject<T> | RefCallback<T>;
+
+export interface VNode<P = {}> extends preact.VNode<P> {
+ // Redefine type here using our internal ComponentType type
+ type: string | ComponentType<P>;
+ props: P & { children: ComponentChildren };
+ ref?: Ref<any> | null;
+ _children: Array<VNode<any>> | null;
+ _parent: VNode | null;
+ _depth: number | null;
+ /**
+ * The [first (for Fragments)] DOM child of a VNode
+ */
+ _dom: PreactElement | null;
+ /**
+ * The last dom child of a Fragment, or components that return a Fragment
+ */
+ _nextDom: PreactElement | null;
+ _component: Component | null;
+ _hydrating: boolean | null;
+ constructor: undefined;
+ _original: number;
+}
+
+export interface Component<P = {}, S = {}> extends preact.Component<P, S> {
+ // When component is functional component, this is reset to functional component
+ constructor: ComponentType<P>;
+ state: S; // Override Component["state"] to not be readonly for internal use, specifically Hooks
+ base?: PreactElement;
+
+ _dirty: boolean;
+ _force?: boolean;
+ _renderCallbacks: Array<() => void>; // Only class components
+ _globalContext?: any;
+ _vnode?: VNode<P> | null;
+ _nextState?: S | null; // Only class components
+ /** Only used in the devtools to later dirty check if state has changed */
+ _prevState?: S | null;
+ /**
+ * Pointer to the parent dom node. This is only needed for top-level Fragment
+ * components or array returns.
+ */
+ _parentDom?: PreactElement | null;
+ // Always read, set only when handling error
+ _processingException?: Component<any, any> | null;
+ // Always read, set only when handling error. This is used to indicate at diffTime to set _processingException
+ _pendingError?: Component<any, any> | null;
+}
+
+export interface PreactContext extends preact.Context<any> {
+ _id: string;
+ _defaultValue: any;
+}
diff --git a/preact/src/jsx.d.ts b/preact/src/jsx.d.ts
new file mode 100644
index 0000000..7533435
--- /dev/null
+++ b/preact/src/jsx.d.ts
@@ -0,0 +1,974 @@
+// Users who only use Preact for SSR might not specify "dom" in their lib in tsconfig.json
+/// <reference lib="dom" />
+
+import {
+ ClassAttributes,
+ Component,
+ PreactDOMAttributes,
+ VNode
+} from './index';
+
+type Defaultize<Props, Defaults> =
+ // Distribute over unions
+ Props extends any // Make any properties included in Default optional
+ ? Partial<Pick<Props, Extract<keyof Props, keyof Defaults>>> & // Include the remaining properties from Props
+ Pick<Props, Exclude<keyof Props, keyof Defaults>>
+ : never;
+
+export namespace JSXInternal {
+ export type LibraryManagedAttributes<Component, Props> = Component extends {
+ defaultProps: infer Defaults;
+ }
+ ? Defaultize<Props, Defaults>
+ : Props;
+
+ export interface IntrinsicAttributes {
+ key?: any;
+ }
+
+ export interface Element extends VNode<any> {}
+
+ export interface ElementClass extends Component<any, any> {}
+
+ export interface ElementAttributesProperty {
+ props: any;
+ }
+
+ export interface ElementChildrenAttribute {
+ children: any;
+ }
+
+ export type DOMCSSProperties = {
+ [key in keyof Omit<
+ CSSStyleDeclaration,
+ | 'item'
+ | 'setProperty'
+ | 'removeProperty'
+ | 'getPropertyValue'
+ | 'getPropertyPriority'
+ >]?: string | number | null | undefined;
+ };
+ export type AllCSSProperties = {
+ [key: string]: string | number | null | undefined;
+ };
+ export interface CSSProperties extends AllCSSProperties, DOMCSSProperties {
+ cssText?: string | null;
+ }
+
+ export interface SVGAttributes<Target extends EventTarget = SVGElement>
+ extends HTMLAttributes<Target> {
+ accentHeight?: number | string;
+ accumulate?: 'none' | 'sum';
+ additive?: 'replace' | 'sum';
+ alignmentBaseline?:
+ | 'auto'
+ | 'baseline'
+ | 'before-edge'
+ | 'text-before-edge'
+ | 'middle'
+ | 'central'
+ | 'after-edge'
+ | 'text-after-edge'
+ | 'ideographic'
+ | 'alphabetic'
+ | 'hanging'
+ | 'mathematical'
+ | 'inherit';
+ allowReorder?: 'no' | 'yes';
+ alphabetic?: number | string;
+ amplitude?: number | string;
+ arabicForm?: 'initial' | 'medial' | 'terminal' | 'isolated';
+ ascent?: number | string;
+ attributeName?: string;
+ attributeType?: string;
+ autoReverse?: number | string;
+ azimuth?: number | string;
+ baseFrequency?: number | string;
+ baselineShift?: number | string;
+ baseProfile?: number | string;
+ bbox?: number | string;
+ begin?: number | string;
+ bias?: number | string;
+ by?: number | string;
+ calcMode?: number | string;
+ capHeight?: number | string;
+ clip?: number | string;
+ clipPath?: string;
+ clipPathUnits?: number | string;
+ clipRule?: number | string;
+ colorInterpolation?: number | string;
+ colorInterpolationFilters?: 'auto' | 'sRGB' | 'linearRGB' | 'inherit';
+ colorProfile?: number | string;
+ colorRendering?: number | string;
+ contentScriptType?: number | string;
+ contentStyleType?: number | string;
+ cursor?: number | string;
+ cx?: number | string;
+ cy?: number | string;
+ d?: string;
+ decelerate?: number | string;
+ descent?: number | string;
+ diffuseConstant?: number | string;
+ direction?: number | string;
+ display?: number | string;
+ divisor?: number | string;
+ dominantBaseline?: number | string;
+ dur?: number | string;
+ dx?: number | string;
+ dy?: number | string;
+ edgeMode?: number | string;
+ elevation?: number | string;
+ enableBackground?: number | string;
+ end?: number | string;
+ exponent?: number | string;
+ externalResourcesRequired?: number | string;
+ fill?: string;
+ fillOpacity?: number | string;
+ fillRule?: 'nonzero' | 'evenodd' | 'inherit';
+ filter?: string;
+ filterRes?: number | string;
+ filterUnits?: number | string;
+ floodColor?: number | string;
+ floodOpacity?: number | string;
+ focusable?: number | string;
+ fontFamily?: string;
+ fontSize?: number | string;
+ fontSizeAdjust?: number | string;
+ fontStretch?: number | string;
+ fontStyle?: number | string;
+ fontVariant?: number | string;
+ fontWeight?: number | string;
+ format?: number | string;
+ from?: number | string;
+ fx?: number | string;
+ fy?: number | string;
+ g1?: number | string;
+ g2?: number | string;
+ glyphName?: number | string;
+ glyphOrientationHorizontal?: number | string;
+ glyphOrientationVertical?: number | string;
+ glyphRef?: number | string;
+ gradientTransform?: string;
+ gradientUnits?: string;
+ hanging?: number | string;
+ horizAdvX?: number | string;
+ horizOriginX?: number | string;
+ ideographic?: number | string;
+ imageRendering?: number | string;
+ in2?: number | string;
+ in?: string;
+ intercept?: number | string;
+ k1?: number | string;
+ k2?: number | string;
+ k3?: number | string;
+ k4?: number | string;
+ k?: number | string;
+ kernelMatrix?: number | string;
+ kernelUnitLength?: number | string;
+ kerning?: number | string;
+ keyPoints?: number | string;
+ keySplines?: number | string;
+ keyTimes?: number | string;
+ lengthAdjust?: number | string;
+ letterSpacing?: number | string;
+ lightingColor?: number | string;
+ limitingConeAngle?: number | string;
+ local?: number | string;
+ markerEnd?: string;
+ markerHeight?: number | string;
+ markerMid?: string;
+ markerStart?: string;
+ markerUnits?: number | string;
+ markerWidth?: number | string;
+ mask?: string;
+ maskContentUnits?: number | string;
+ maskUnits?: number | string;
+ mathematical?: number | string;
+ mode?: number | string;
+ numOctaves?: number | string;
+ offset?: number | string;
+ opacity?: number | string;
+ operator?: number | string;
+ order?: number | string;
+ orient?: number | string;
+ orientation?: number | string;
+ origin?: number | string;
+ overflow?: number | string;
+ overlinePosition?: number | string;
+ overlineThickness?: number | string;
+ paintOrder?: number | string;
+ panose1?: number | string;
+ pathLength?: number | string;
+ patternContentUnits?: string;
+ patternTransform?: number | string;
+ patternUnits?: string;
+ pointerEvents?: number | string;
+ points?: string;
+ pointsAtX?: number | string;
+ pointsAtY?: number | string;
+ pointsAtZ?: number | string;
+ preserveAlpha?: number | string;
+ preserveAspectRatio?: string;
+ primitiveUnits?: number | string;
+ r?: number | string;
+ radius?: number | string;
+ refX?: number | string;
+ refY?: number | string;
+ renderingIntent?: number | string;
+ repeatCount?: number | string;
+ repeatDur?: number | string;
+ requiredExtensions?: number | string;
+ requiredFeatures?: number | string;
+ restart?: number | string;
+ result?: string;
+ rotate?: number | string;
+ rx?: number | string;
+ ry?: number | string;
+ scale?: number | string;
+ seed?: number | string;
+ shapeRendering?: number | string;
+ slope?: number | string;
+ spacing?: number | string;
+ specularConstant?: number | string;
+ specularExponent?: number | string;
+ speed?: number | string;
+ spreadMethod?: string;
+ startOffset?: number | string;
+ stdDeviation?: number | string;
+ stemh?: number | string;
+ stemv?: number | string;
+ stitchTiles?: number | string;
+ stopColor?: string;
+ stopOpacity?: number | string;
+ strikethroughPosition?: number | string;
+ strikethroughThickness?: number | string;
+ string?: number | string;
+ stroke?: string;
+ strokeDasharray?: string | number;
+ strokeDashoffset?: string | number;
+ strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
+ strokeLinejoin?: 'miter' | 'round' | 'bevel' | 'inherit';
+ strokeMiterlimit?: string | number;
+ strokeOpacity?: number | string;
+ strokeWidth?: number | string;
+ surfaceScale?: number | string;
+ systemLanguage?: number | string;
+ tableValues?: number | string;
+ targetX?: number | string;
+ targetY?: number | string;
+ textAnchor?: string;
+ textDecoration?: number | string;
+ textLength?: number | string;
+ textRendering?: number | string;
+ to?: number | string;
+ transform?: string;
+ u1?: number | string;
+ u2?: number | string;
+ underlinePosition?: number | string;
+ underlineThickness?: number | string;
+ unicode?: number | string;
+ unicodeBidi?: number | string;
+ unicodeRange?: number | string;
+ unitsPerEm?: number | string;
+ vAlphabetic?: number | string;
+ values?: string;
+ vectorEffect?: number | string;
+ version?: string;
+ vertAdvY?: number | string;
+ vertOriginX?: number | string;
+ vertOriginY?: number | string;
+ vHanging?: number | string;
+ vIdeographic?: number | string;
+ viewBox?: string;
+ viewTarget?: number | string;
+ visibility?: number | string;
+ vMathematical?: number | string;
+ widths?: number | string;
+ wordSpacing?: number | string;
+ writingMode?: number | string;
+ x1?: number | string;
+ x2?: number | string;
+ x?: number | string;
+ xChannelSelector?: string;
+ xHeight?: number | string;
+ xlinkActuate?: string;
+ xlinkArcrole?: string;
+ xlinkHref?: string;
+ xlinkRole?: string;
+ xlinkShow?: string;
+ xlinkTitle?: string;
+ xlinkType?: string;
+ xmlBase?: string;
+ xmlLang?: string;
+ xmlns?: string;
+ xmlnsXlink?: string;
+ xmlSpace?: string;
+ y1?: number | string;
+ y2?: number | string;
+ y?: number | string;
+ yChannelSelector?: string;
+ z?: number | string;
+ zoomAndPan?: string;
+ }
+
+ export interface PathAttributes {
+ d: string;
+ }
+
+ export type TargetedEvent<
+ Target extends EventTarget = EventTarget,
+ TypedEvent extends Event = Event
+ > = Omit<TypedEvent, 'currentTarget'> & {
+ readonly currentTarget: Target;
+ };
+
+ export type TargetedAnimationEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, AnimationEvent>;
+ export type TargetedClipboardEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, ClipboardEvent>;
+ export type TargetedCompositionEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, CompositionEvent>;
+ export type TargetedDragEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ DragEvent
+ >;
+ export type TargetedFocusEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ FocusEvent
+ >;
+ export type TargetedKeyboardEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ KeyboardEvent
+ >;
+ export type TargetedMouseEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ MouseEvent
+ >;
+ export type TargetedPointerEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ PointerEvent
+ >;
+ export type TargetedTouchEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ TouchEvent
+ >;
+ export type TargetedTransitionEvent<
+ Target extends EventTarget
+ > = TargetedEvent<Target, TransitionEvent>;
+ export type TargetedUIEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ UIEvent
+ >;
+ export type TargetedWheelEvent<Target extends EventTarget> = TargetedEvent<
+ Target,
+ WheelEvent
+ >;
+
+ export interface EventHandler<E extends TargetedEvent> {
+ /**
+ * The `this` keyword always points to the DOM element the event handler
+ * was invoked on. See: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers#Event_handlers_parameters_this_binding_and_the_return_value
+ */
+ (this: never, event: E): void;
+ }
+
+ export type AnimationEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedAnimationEvent<Target>
+ >;
+ export type ClipboardEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedClipboardEvent<Target>
+ >;
+ export type CompositionEventHandler<
+ Target extends EventTarget
+ > = EventHandler<TargetedCompositionEvent<Target>>;
+ export type DragEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedDragEvent<Target>
+ >;
+ export type FocusEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedFocusEvent<Target>
+ >;
+ export type GenericEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedEvent<Target>
+ >;
+ export type KeyboardEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedKeyboardEvent<Target>
+ >;
+ export type MouseEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedMouseEvent<Target>
+ >;
+ export type PointerEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedPointerEvent<Target>
+ >;
+ export type TouchEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedTouchEvent<Target>
+ >;
+ export type TransitionEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedTransitionEvent<Target>
+ >;
+ export type UIEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedUIEvent<Target>
+ >;
+ export type WheelEventHandler<Target extends EventTarget> = EventHandler<
+ TargetedWheelEvent<Target>
+ >;
+
+ export interface DOMAttributes<Target extends EventTarget>
+ extends PreactDOMAttributes {
+ // Image Events
+ onLoad?: GenericEventHandler<Target>;
+ onLoadCapture?: GenericEventHandler<Target>;
+ onError?: GenericEventHandler<Target>;
+ onErrorCapture?: GenericEventHandler<Target>;
+
+ // Clipboard Events
+ onCopy?: ClipboardEventHandler<Target>;
+ onCopyCapture?: ClipboardEventHandler<Target>;
+ onCut?: ClipboardEventHandler<Target>;
+ onCutCapture?: ClipboardEventHandler<Target>;
+ onPaste?: ClipboardEventHandler<Target>;
+ onPasteCapture?: ClipboardEventHandler<Target>;
+
+ // Composition Events
+ onCompositionEnd?: CompositionEventHandler<Target>;
+ onCompositionEndCapture?: CompositionEventHandler<Target>;
+ onCompositionStart?: CompositionEventHandler<Target>;
+ onCompositionStartCapture?: CompositionEventHandler<Target>;
+ onCompositionUpdate?: CompositionEventHandler<Target>;
+ onCompositionUpdateCapture?: CompositionEventHandler<Target>;
+
+ // Details Events
+ onToggle?: GenericEventHandler<Target>;
+
+ // Focus Events
+ onFocus?: FocusEventHandler<Target>;
+ onFocusCapture?: FocusEventHandler<Target>;
+ onBlur?: FocusEventHandler<Target>;
+ onBlurCapture?: FocusEventHandler<Target>;
+
+ // Form Events
+ onChange?: GenericEventHandler<Target>;
+ onChangeCapture?: GenericEventHandler<Target>;
+ onInput?: GenericEventHandler<Target>;
+ onInputCapture?: GenericEventHandler<Target>;
+ onSearch?: GenericEventHandler<Target>;
+ onSearchCapture?: GenericEventHandler<Target>;
+ onSubmit?: GenericEventHandler<Target>;
+ onSubmitCapture?: GenericEventHandler<Target>;
+ onInvalid?: GenericEventHandler<Target>;
+ onInvalidCapture?: GenericEventHandler<Target>;
+ onReset?: GenericEventHandler<Target>;
+ onResetCapture?: GenericEventHandler<Target>;
+ onFormData?: GenericEventHandler<Target>;
+ onFormDataCapture?: GenericEventHandler<Target>;
+
+ // Keyboard Events
+ onKeyDown?: KeyboardEventHandler<Target>;
+ onKeyDownCapture?: KeyboardEventHandler<Target>;
+ onKeyPress?: KeyboardEventHandler<Target>;
+ onKeyPressCapture?: KeyboardEventHandler<Target>;
+ onKeyUp?: KeyboardEventHandler<Target>;
+ onKeyUpCapture?: KeyboardEventHandler<Target>;
+
+ // Media Events
+ onAbort?: GenericEventHandler<Target>;
+ onAbortCapture?: GenericEventHandler<Target>;
+ onCanPlay?: GenericEventHandler<Target>;
+ onCanPlayCapture?: GenericEventHandler<Target>;
+ onCanPlayThrough?: GenericEventHandler<Target>;
+ onCanPlayThroughCapture?: GenericEventHandler<Target>;
+ onDurationChange?: GenericEventHandler<Target>;
+ onDurationChangeCapture?: GenericEventHandler<Target>;
+ onEmptied?: GenericEventHandler<Target>;
+ onEmptiedCapture?: GenericEventHandler<Target>;
+ onEncrypted?: GenericEventHandler<Target>;
+ onEncryptedCapture?: GenericEventHandler<Target>;
+ onEnded?: GenericEventHandler<Target>;
+ onEndedCapture?: GenericEventHandler<Target>;
+ onLoadedData?: GenericEventHandler<Target>;
+ onLoadedDataCapture?: GenericEventHandler<Target>;
+ onLoadedMetadata?: GenericEventHandler<Target>;
+ onLoadedMetadataCapture?: GenericEventHandler<Target>;
+ onLoadStart?: GenericEventHandler<Target>;
+ onLoadStartCapture?: GenericEventHandler<Target>;
+ onPause?: GenericEventHandler<Target>;
+ onPauseCapture?: GenericEventHandler<Target>;
+ onPlay?: GenericEventHandler<Target>;
+ onPlayCapture?: GenericEventHandler<Target>;
+ onPlaying?: GenericEventHandler<Target>;
+ onPlayingCapture?: GenericEventHandler<Target>;
+ onProgress?: GenericEventHandler<Target>;
+ onProgressCapture?: GenericEventHandler<Target>;
+ onRateChange?: GenericEventHandler<Target>;
+ onRateChangeCapture?: GenericEventHandler<Target>;
+ onSeeked?: GenericEventHandler<Target>;
+ onSeekedCapture?: GenericEventHandler<Target>;
+ onSeeking?: GenericEventHandler<Target>;
+ onSeekingCapture?: GenericEventHandler<Target>;
+ onStalled?: GenericEventHandler<Target>;
+ onStalledCapture?: GenericEventHandler<Target>;
+ onSuspend?: GenericEventHandler<Target>;
+ onSuspendCapture?: GenericEventHandler<Target>;
+ onTimeUpdate?: GenericEventHandler<Target>;
+ onTimeUpdateCapture?: GenericEventHandler<Target>;
+ onVolumeChange?: GenericEventHandler<Target>;
+ onVolumeChangeCapture?: GenericEventHandler<Target>;
+ onWaiting?: GenericEventHandler<Target>;
+ onWaitingCapture?: GenericEventHandler<Target>;
+
+ // MouseEvents
+ onClick?: MouseEventHandler<Target>;
+ onClickCapture?: MouseEventHandler<Target>;
+ onContextMenu?: MouseEventHandler<Target>;
+ onContextMenuCapture?: MouseEventHandler<Target>;
+ onDblClick?: MouseEventHandler<Target>;
+ onDblClickCapture?: MouseEventHandler<Target>;
+ onDrag?: DragEventHandler<Target>;
+ onDragCapture?: DragEventHandler<Target>;
+ onDragEnd?: DragEventHandler<Target>;
+ onDragEndCapture?: DragEventHandler<Target>;
+ onDragEnter?: DragEventHandler<Target>;
+ onDragEnterCapture?: DragEventHandler<Target>;
+ onDragExit?: DragEventHandler<Target>;
+ onDragExitCapture?: DragEventHandler<Target>;
+ onDragLeave?: DragEventHandler<Target>;
+ onDragLeaveCapture?: DragEventHandler<Target>;
+ onDragOver?: DragEventHandler<Target>;
+ onDragOverCapture?: DragEventHandler<Target>;
+ onDragStart?: DragEventHandler<Target>;
+ onDragStartCapture?: DragEventHandler<Target>;
+ onDrop?: DragEventHandler<Target>;
+ onDropCapture?: DragEventHandler<Target>;
+ onMouseDown?: MouseEventHandler<Target>;
+ onMouseDownCapture?: MouseEventHandler<Target>;
+ onMouseEnter?: MouseEventHandler<Target>;
+ onMouseEnterCapture?: MouseEventHandler<Target>;
+ onMouseLeave?: MouseEventHandler<Target>;
+ onMouseLeaveCapture?: MouseEventHandler<Target>;
+ onMouseMove?: MouseEventHandler<Target>;
+ onMouseMoveCapture?: MouseEventHandler<Target>;
+ onMouseOut?: MouseEventHandler<Target>;
+ onMouseOutCapture?: MouseEventHandler<Target>;
+ onMouseOver?: MouseEventHandler<Target>;
+ onMouseOverCapture?: MouseEventHandler<Target>;
+ onMouseUp?: MouseEventHandler<Target>;
+ onMouseUpCapture?: MouseEventHandler<Target>;
+
+ // Selection Events
+ onSelect?: GenericEventHandler<Target>;
+ onSelectCapture?: GenericEventHandler<Target>;
+
+ // Touch Events
+ onTouchCancel?: TouchEventHandler<Target>;
+ onTouchCancelCapture?: TouchEventHandler<Target>;
+ onTouchEnd?: TouchEventHandler<Target>;
+ onTouchEndCapture?: TouchEventHandler<Target>;
+ onTouchMove?: TouchEventHandler<Target>;
+ onTouchMoveCapture?: TouchEventHandler<Target>;
+ onTouchStart?: TouchEventHandler<Target>;
+ onTouchStartCapture?: TouchEventHandler<Target>;
+
+ // Pointer Events
+ onPointerOver?: PointerEventHandler<Target>;
+ onPointerOverCapture?: PointerEventHandler<Target>;
+ onPointerEnter?: PointerEventHandler<Target>;
+ onPointerEnterCapture?: PointerEventHandler<Target>;
+ onPointerDown?: PointerEventHandler<Target>;
+ onPointerDownCapture?: PointerEventHandler<Target>;
+ onPointerMove?: PointerEventHandler<Target>;
+ onPointerMoveCapture?: PointerEventHandler<Target>;
+ onPointerUp?: PointerEventHandler<Target>;
+ onPointerUpCapture?: PointerEventHandler<Target>;
+ onPointerCancel?: PointerEventHandler<Target>;
+ onPointerCancelCapture?: PointerEventHandler<Target>;
+ onPointerOut?: PointerEventHandler<Target>;
+ onPointerOutCapture?: PointerEventHandler<Target>;
+ onPointerLeave?: PointerEventHandler<Target>;
+ onPointerLeaveCapture?: PointerEventHandler<Target>;
+ onGotPointerCapture?: PointerEventHandler<Target>;
+ onGotPointerCaptureCapture?: PointerEventHandler<Target>;
+ onLostPointerCapture?: PointerEventHandler<Target>;
+ onLostPointerCaptureCapture?: PointerEventHandler<Target>;
+
+ // UI Events
+ onScroll?: UIEventHandler<Target>;
+ onScrollCapture?: UIEventHandler<Target>;
+
+ // Wheel Events
+ onWheel?: WheelEventHandler<Target>;
+ onWheelCapture?: WheelEventHandler<Target>;
+
+ // Animation Events
+ onAnimationStart?: AnimationEventHandler<Target>;
+ onAnimationStartCapture?: AnimationEventHandler<Target>;
+ onAnimationEnd?: AnimationEventHandler<Target>;
+ onAnimationEndCapture?: AnimationEventHandler<Target>;
+ onAnimationIteration?: AnimationEventHandler<Target>;
+ onAnimationIterationCapture?: AnimationEventHandler<Target>;
+
+ // Transition Events
+ onTransitionEnd?: TransitionEventHandler<Target>;
+ onTransitionEndCapture?: TransitionEventHandler<Target>;
+ }
+
+ export interface HTMLAttributes<RefType extends EventTarget = EventTarget>
+ extends ClassAttributes<RefType>,
+ DOMAttributes<RefType> {
+ // Standard HTML Attributes
+ accept?: string;
+ acceptCharset?: string;
+ accessKey?: string;
+ action?: string;
+ allowFullScreen?: boolean;
+ allowTransparency?: boolean;
+ alt?: string;
+ as?: string;
+ async?: boolean;
+ autocomplete?: string;
+ autoComplete?: string;
+ autocorrect?: string;
+ autoCorrect?: string;
+ autofocus?: boolean;
+ autoFocus?: boolean;
+ autoPlay?: boolean;
+ capture?: boolean | string;
+ cellPadding?: number | string;
+ cellSpacing?: number | string;
+ charSet?: string;
+ challenge?: string;
+ checked?: boolean;
+ class?: string;
+ className?: string;
+ cols?: number;
+ colSpan?: number;
+ content?: string;
+ contentEditable?: boolean;
+ contextMenu?: string;
+ controls?: boolean;
+ controlsList?: string;
+ coords?: string;
+ crossOrigin?: string;
+ data?: string;
+ dateTime?: string;
+ default?: boolean;
+ defer?: boolean;
+ dir?: 'auto' | 'rtl' | 'ltr';
+ disabled?: boolean;
+ disableRemotePlayback?: boolean;
+ download?: any;
+ decoding?: 'sync' | 'async' | 'auto';
+ draggable?: boolean;
+ encType?: string;
+ form?: string;
+ formAction?: string;
+ formEncType?: string;
+ formMethod?: string;
+ formNoValidate?: boolean;
+ formTarget?: string;
+ frameBorder?: number | string;
+ headers?: string;
+ height?: number | string;
+ hidden?: boolean;
+ high?: number;
+ href?: string;
+ hrefLang?: string;
+ for?: string;
+ htmlFor?: string;
+ httpEquiv?: string;
+ icon?: string;
+ id?: string;
+ inputMode?: string;
+ integrity?: string;
+ is?: string;
+ keyParams?: string;
+ keyType?: string;
+ kind?: string;
+ label?: string;
+ lang?: string;
+ list?: string;
+ loading?: 'eager' | 'lazy';
+ loop?: boolean;
+ low?: number;
+ manifest?: string;
+ marginHeight?: number;
+ marginWidth?: number;
+ max?: number | string;
+ maxLength?: number;
+ media?: string;
+ mediaGroup?: string;
+ method?: string;
+ min?: number | string;
+ minLength?: number;
+ multiple?: boolean;
+ muted?: boolean;
+ name?: string;
+ nonce?: string;
+ noValidate?: boolean;
+ open?: boolean;
+ optimum?: number;
+ pattern?: string;
+ placeholder?: string;
+ playsInline?: boolean;
+ poster?: string;
+ preload?: string;
+ radioGroup?: string;
+ readonly?: boolean;
+ readOnly?: boolean;
+ rel?: string;
+ required?: boolean;
+ role?: string;
+ rows?: number;
+ rowSpan?: number;
+ sandbox?: string;
+ scope?: string;
+ scoped?: boolean;
+ scrolling?: string;
+ seamless?: boolean;
+ selected?: boolean;
+ shape?: string;
+ size?: number;
+ sizes?: string;
+ slot?: string;
+ span?: number;
+ spellcheck?: boolean;
+ spellCheck?: boolean;
+ src?: string;
+ srcset?: string;
+ srcDoc?: string;
+ srcLang?: string;
+ srcSet?: string;
+ start?: number;
+ step?: number | string;
+ style?: string | CSSProperties;
+ summary?: string;
+ tabIndex?: number;
+ target?: string;
+ title?: string;
+ type?: string;
+ useMap?: string;
+ value?: string | string[] | number;
+ volume?: string | number;
+ width?: number | string;
+ wmode?: string;
+ wrap?: string;
+
+ // Non-standard Attributes
+ autocapitalize?:
+ | 'off'
+ | 'none'
+ | 'on'
+ | 'sentences'
+ | 'words'
+ | 'characters';
+ autoCapitalize?:
+ | 'off'
+ | 'none'
+ | 'on'
+ | 'sentences'
+ | 'words'
+ | 'characters';
+
+ // RDFa Attributes
+ about?: string;
+ datatype?: string;
+ inlist?: any;
+ prefix?: string;
+ property?: string;
+ resource?: string;
+ typeof?: string;
+ vocab?: string;
+
+ // Microdata Attributes
+ itemProp?: string;
+ itemScope?: boolean;
+ itemType?: string;
+ itemID?: string;
+ itemRef?: string;
+ }
+
+ export interface HTMLMarqueeElement extends HTMLElement {
+ behavior?: 'scroll' | 'slide' | 'alternate';
+ bgColor?: string;
+ direction?: 'left' | 'right' | 'up' | 'down';
+ height?: number | string;
+ hspace?: number | string;
+ loop?: number | string;
+ scrollAmount?: number | string;
+ scrollDelay?: number | string;
+ trueSpeed?: boolean;
+ vspace?: number | string;
+ width?: number | string;
+ }
+
+ export interface IntrinsicElements {
+ // HTML
+ a: HTMLAttributes<HTMLAnchorElement>;
+ abbr: HTMLAttributes<HTMLElement>;
+ address: HTMLAttributes<HTMLElement>;
+ area: HTMLAttributes<HTMLAreaElement>;
+ article: HTMLAttributes<HTMLElement>;
+ aside: HTMLAttributes<HTMLElement>;
+ audio: HTMLAttributes<HTMLAudioElement>;
+ b: HTMLAttributes<HTMLElement>;
+ base: HTMLAttributes<HTMLBaseElement>;
+ bdi: HTMLAttributes<HTMLElement>;
+ bdo: HTMLAttributes<HTMLElement>;
+ big: HTMLAttributes<HTMLElement>;
+ blockquote: HTMLAttributes<HTMLQuoteElement>;
+ body: HTMLAttributes<HTMLBodyElement>;
+ br: HTMLAttributes<HTMLBRElement>;
+ button: HTMLAttributes<HTMLButtonElement>;
+ canvas: HTMLAttributes<HTMLCanvasElement>;
+ caption: HTMLAttributes<HTMLTableCaptionElement>;
+ cite: HTMLAttributes<HTMLElement>;
+ code: HTMLAttributes<HTMLElement>;
+ col: HTMLAttributes<HTMLTableColElement>;
+ colgroup: HTMLAttributes<HTMLTableColElement>;
+ data: HTMLAttributes<HTMLDataElement>;
+ datalist: HTMLAttributes<HTMLDataListElement>;
+ dd: HTMLAttributes<HTMLElement>;
+ del: HTMLAttributes<HTMLModElement>;
+ details: HTMLAttributes<HTMLDetailsElement>;
+ dfn: HTMLAttributes<HTMLElement>;
+ dialog: HTMLAttributes<HTMLDialogElement>;
+ div: HTMLAttributes<HTMLDivElement>;
+ dl: HTMLAttributes<HTMLDListElement>;
+ dt: HTMLAttributes<HTMLElement>;
+ em: HTMLAttributes<HTMLElement>;
+ embed: HTMLAttributes<HTMLEmbedElement>;
+ fieldset: HTMLAttributes<HTMLFieldSetElement>;
+ figcaption: HTMLAttributes<HTMLElement>;
+ figure: HTMLAttributes<HTMLElement>;
+ footer: HTMLAttributes<HTMLElement>;
+ form: HTMLAttributes<HTMLFormElement>;
+ h1: HTMLAttributes<HTMLHeadingElement>;
+ h2: HTMLAttributes<HTMLHeadingElement>;
+ h3: HTMLAttributes<HTMLHeadingElement>;
+ h4: HTMLAttributes<HTMLHeadingElement>;
+ h5: HTMLAttributes<HTMLHeadingElement>;
+ h6: HTMLAttributes<HTMLHeadingElement>;
+ head: HTMLAttributes<HTMLHeadElement>;
+ header: HTMLAttributes<HTMLElement>;
+ hgroup: HTMLAttributes<HTMLElement>;
+ hr: HTMLAttributes<HTMLHRElement>;
+ html: HTMLAttributes<HTMLHtmlElement>;
+ i: HTMLAttributes<HTMLElement>;
+ iframe: HTMLAttributes<HTMLIFrameElement>;
+ img: HTMLAttributes<HTMLImageElement>;
+ input: HTMLAttributes<HTMLInputElement>;
+ ins: HTMLAttributes<HTMLModElement>;
+ kbd: HTMLAttributes<HTMLElement>;
+ keygen: HTMLAttributes<HTMLUnknownElement>;
+ label: HTMLAttributes<HTMLLabelElement>;
+ legend: HTMLAttributes<HTMLLegendElement>;
+ li: HTMLAttributes<HTMLLIElement>;
+ link: HTMLAttributes<HTMLLinkElement>;
+ main: HTMLAttributes<HTMLElement>;
+ map: HTMLAttributes<HTMLMapElement>;
+ mark: HTMLAttributes<HTMLElement>;
+ marquee: HTMLAttributes<HTMLMarqueeElement>;
+ menu: HTMLAttributes<HTMLMenuElement>;
+ menuitem: HTMLAttributes<HTMLUnknownElement>;
+ meta: HTMLAttributes<HTMLMetaElement>;
+ meter: HTMLAttributes<HTMLMeterElement>;
+ nav: HTMLAttributes<HTMLElement>;
+ noscript: HTMLAttributes<HTMLElement>;
+ object: HTMLAttributes<HTMLObjectElement>;
+ ol: HTMLAttributes<HTMLOListElement>;
+ optgroup: HTMLAttributes<HTMLOptGroupElement>;
+ option: HTMLAttributes<HTMLOptionElement>;
+ output: HTMLAttributes<HTMLOutputElement>;
+ p: HTMLAttributes<HTMLParagraphElement>;
+ param: HTMLAttributes<HTMLParamElement>;
+ picture: HTMLAttributes<HTMLPictureElement>;
+ pre: HTMLAttributes<HTMLPreElement>;
+ progress: HTMLAttributes<HTMLProgressElement>;
+ q: HTMLAttributes<HTMLQuoteElement>;
+ rp: HTMLAttributes<HTMLElement>;
+ rt: HTMLAttributes<HTMLElement>;
+ ruby: HTMLAttributes<HTMLElement>;
+ s: HTMLAttributes<HTMLElement>;
+ samp: HTMLAttributes<HTMLElement>;
+ script: HTMLAttributes<HTMLScriptElement>;
+ section: HTMLAttributes<HTMLElement>;
+ select: HTMLAttributes<HTMLSelectElement>;
+ slot: HTMLAttributes<HTMLSlotElement>;
+ small: HTMLAttributes<HTMLElement>;
+ source: HTMLAttributes<HTMLSourceElement>;
+ span: HTMLAttributes<HTMLSpanElement>;
+ strong: HTMLAttributes<HTMLElement>;
+ style: HTMLAttributes<HTMLStyleElement>;
+ sub: HTMLAttributes<HTMLElement>;
+ summary: HTMLAttributes<HTMLElement>;
+ sup: HTMLAttributes<HTMLElement>;
+ table: HTMLAttributes<HTMLTableElement>;
+ tbody: HTMLAttributes<HTMLTableSectionElement>;
+ td: HTMLAttributes<HTMLTableCellElement>;
+ textarea: HTMLAttributes<HTMLTextAreaElement>;
+ tfoot: HTMLAttributes<HTMLTableSectionElement>;
+ th: HTMLAttributes<HTMLTableCellElement>;
+ thead: HTMLAttributes<HTMLTableSectionElement>;
+ time: HTMLAttributes<HTMLTimeElement>;
+ title: HTMLAttributes<HTMLTitleElement>;
+ tr: HTMLAttributes<HTMLTableRowElement>;
+ track: HTMLAttributes<HTMLTrackElement>;
+ u: HTMLAttributes<HTMLElement>;
+ ul: HTMLAttributes<HTMLUListElement>;
+ var: HTMLAttributes<HTMLElement>;
+ video: HTMLAttributes<HTMLVideoElement>;
+ wbr: HTMLAttributes<HTMLElement>;
+
+ //SVG
+ svg: SVGAttributes<SVGSVGElement>;
+ animate: SVGAttributes<SVGAnimateElement>;
+ circle: SVGAttributes<SVGCircleElement>;
+ animateTransform: SVGAttributes<SVGAnimateElement>;
+ clipPath: SVGAttributes<SVGClipPathElement>;
+ defs: SVGAttributes<SVGDefsElement>;
+ desc: SVGAttributes<SVGDescElement>;
+ ellipse: SVGAttributes<SVGEllipseElement>;
+ feBlend: SVGAttributes<SVGFEBlendElement>;
+ feColorMatrix: SVGAttributes<SVGFEColorMatrixElement>;
+ feComponentTransfer: SVGAttributes<SVGFEComponentTransferElement>;
+ feComposite: SVGAttributes<SVGFECompositeElement>;
+ feConvolveMatrix: SVGAttributes<SVGFEConvolveMatrixElement>;
+ feDiffuseLighting: SVGAttributes<SVGFEDiffuseLightingElement>;
+ feDisplacementMap: SVGAttributes<SVGFEDisplacementMapElement>;
+ feDropShadow: SVGAttributes<SVGFEDropShadowElement>;
+ feFlood: SVGAttributes<SVGFEFloodElement>;
+ feFuncA: SVGAttributes<SVGFEFuncAElement>;
+ feFuncB: SVGAttributes<SVGFEFuncBElement>;
+ feFuncG: SVGAttributes<SVGFEFuncGElement>;
+ feFuncR: SVGAttributes<SVGFEFuncRElement>;
+ feGaussianBlur: SVGAttributes<SVGFEGaussianBlurElement>;
+ feImage: SVGAttributes<SVGFEImageElement>;
+ feMerge: SVGAttributes<SVGFEMergeElement>;
+ feMergeNode: SVGAttributes<SVGFEMergeNodeElement>;
+ feMorphology: SVGAttributes<SVGFEMorphologyElement>;
+ feOffset: SVGAttributes<SVGFEOffsetElement>;
+ feSpecularLighting: SVGAttributes<SVGFESpecularLightingElement>;
+ feTile: SVGAttributes<SVGFETileElement>;
+ feTurbulence: SVGAttributes<SVGFETurbulenceElement>;
+ filter: SVGAttributes<SVGFilterElement>;
+ foreignObject: SVGAttributes<SVGForeignObjectElement>;
+ g: SVGAttributes<SVGGElement>;
+ image: SVGAttributes<SVGImageElement>;
+ line: SVGAttributes<SVGLineElement>;
+ linearGradient: SVGAttributes<SVGLinearGradientElement>;
+ marker: SVGAttributes<SVGMarkerElement>;
+ mask: SVGAttributes<SVGMaskElement>;
+ path: SVGAttributes<SVGPathElement>;
+ pattern: SVGAttributes<SVGPatternElement>;
+ polygon: SVGAttributes<SVGPolygonElement>;
+ polyline: SVGAttributes<SVGPolylineElement>;
+ radialGradient: SVGAttributes<SVGRadialGradientElement>;
+ rect: SVGAttributes<SVGRectElement>;
+ stop: SVGAttributes<SVGStopElement>;
+ symbol: SVGAttributes<SVGSymbolElement>;
+ text: SVGAttributes<SVGTextElement>;
+ tspan: SVGAttributes<SVGTSpanElement>;
+ use: SVGAttributes<SVGUseElement>;
+ }
+}
diff --git a/preact/src/options.js b/preact/src/options.js
new file mode 100644
index 0000000..174f322
--- /dev/null
+++ b/preact/src/options.js
@@ -0,0 +1,16 @@
+import { _catchError } from './diff/catch-error';
+
+/**
+ * The `option` object can potentially contain callback functions
+ * that are called during various stages of our renderer. This is the
+ * foundation on which all our addons like `preact/debug`, `preact/compat`,
+ * and `preact/hooks` are based on. See the `Options` type in `internal.d.ts`
+ * for a full list of available option hooks (most editors/IDEs allow you to
+ * ctrl+click or cmd+click on mac the type definition below).
+ * @type {import('./internal').Options}
+ */
+const options = {
+ _catchError
+};
+
+export default options;
diff --git a/preact/src/render.js b/preact/src/render.js
new file mode 100644
index 0000000..c8ef828
--- /dev/null
+++ b/preact/src/render.js
@@ -0,0 +1,75 @@
+import { EMPTY_OBJ } from './constants';
+import { commitRoot, diff } from './diff/index';
+import { createElement, Fragment } from './create-element';
+import options from './options';
+import { slice } from './util';
+
+/**
+ * Render a Preact virtual node into a DOM element
+ * @param {import('./internal').ComponentChild} vnode The virtual node to render
+ * @param {import('./internal').PreactElement} parentDom The DOM element to
+ * render into
+ * @param {import('./internal').PreactElement | object} [replaceNode] Optional: Attempt to re-use an
+ * existing DOM tree rooted at `replaceNode`
+ */
+export function render(vnode, parentDom, replaceNode) {
+ if (options._root) options._root(vnode, parentDom);
+
+ // We abuse the `replaceNode` parameter in `hydrate()` to signal if we are in
+ // hydration mode or not by passing the `hydrate` function instead of a DOM
+ // element..
+ let isHydrating = typeof replaceNode === 'function';
+
+ // To be able to support calling `render()` multiple times on the same
+ // DOM node, we need to obtain a reference to the previous tree. We do
+ // this by assigning a new `_children` property to DOM nodes which points
+ // to the last rendered tree. By default this property is not present, which
+ // means that we are mounting a new tree for the first time.
+ let oldVNode = isHydrating
+ ? null
+ : (replaceNode && replaceNode._children) || parentDom._children;
+
+ vnode = (
+ (!isHydrating && replaceNode) ||
+ parentDom
+ )._children = createElement(Fragment, null, [vnode]);
+
+ // List of effects that need to be called after diffing.
+ let commitQueue = [];
+ diff(
+ parentDom,
+ // Determine the new vnode tree and store it on the DOM element on
+ // our custom `_children` property.
+ vnode,
+ oldVNode || EMPTY_OBJ,
+ EMPTY_OBJ,
+ parentDom.ownerSVGElement !== undefined,
+ !isHydrating && replaceNode
+ ? [replaceNode]
+ : oldVNode
+ ? null
+ : parentDom.firstChild
+ ? slice.call(parentDom.childNodes)
+ : null,
+ commitQueue,
+ !isHydrating && replaceNode
+ ? replaceNode
+ : oldVNode
+ ? oldVNode._dom
+ : parentDom.firstChild,
+ isHydrating
+ );
+
+ // Flush all queued effects
+ commitRoot(commitQueue, vnode);
+}
+
+/**
+ * Update an existing DOM element with data from a Preact virtual node
+ * @param {import('./internal').ComponentChild} vnode The virtual node to render
+ * @param {import('./internal').PreactElement} parentDom The DOM element to
+ * update
+ */
+export function hydrate(vnode, parentDom) {
+ render(vnode, parentDom, hydrate);
+}
diff --git a/preact/src/util.js b/preact/src/util.js
new file mode 100644
index 0000000..0e9b3b1
--- /dev/null
+++ b/preact/src/util.js
@@ -0,0 +1,27 @@
+import { EMPTY_ARR } from './constants';
+
+/**
+ * Assign properties from `props` to `obj`
+ * @template O, P The obj and props types
+ * @param {O} obj The object to copy properties to
+ * @param {P} props The object to copy properties from
+ * @returns {O & P}
+ */
+export function assign(obj, props) {
+ // @ts-ignore We change the type of `obj` to be `O & P`
+ for (let i in props) obj[i] = props[i];
+ return /** @type {O & P} */ (obj);
+}
+
+/**
+ * Remove a child node from its parent if attached. This is a workaround for
+ * IE11 which doesn't support `Element.prototype.remove()`. Using this function
+ * is smaller than including a dedicated polyfill.
+ * @param {Node} node The node to remove
+ */
+export function removeNode(node) {
+ let parentNode = node.parentNode;
+ if (parentNode) parentNode.removeChild(node);
+}
+
+export const slice = EMPTY_ARR.slice;
diff --git a/preact/test-utils/package.json b/preact/test-utils/package.json
new file mode 100644
index 0000000..b7da0b7
--- /dev/null
+++ b/preact/test-utils/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "test-utils",
+ "amdName": "preactTestUtils",
+ "version": "0.1.0",
+ "private": true,
+ "description": "Test-utils for Preact",
+ "main": "dist/testUtils.js",
+ "module": "dist/testUtils.module.js",
+ "umd:main": "dist/testUtils.umd.js",
+ "source": "src/index.js",
+ "license": "MIT",
+ "types": "src/index.d.ts",
+ "peerDependencies": {
+ "preact": "^10.0.0"
+ },
+ "mangle": {
+ "regex": "^_"
+ }
+}
diff --git a/preact/test-utils/src/index.d.ts b/preact/test-utils/src/index.d.ts
new file mode 100644
index 0000000..d786e73
--- /dev/null
+++ b/preact/test-utils/src/index.d.ts
@@ -0,0 +1,3 @@
+export function setupRerender(): () => void;
+export function act(callback: () => void | Promise<void>): Promise<void>;
+export function teardown(): void;
diff --git a/preact/test-utils/src/index.js b/preact/test-utils/src/index.js
new file mode 100644
index 0000000..0883d7e
--- /dev/null
+++ b/preact/test-utils/src/index.js
@@ -0,0 +1,117 @@
+import { options } from 'preact';
+
+/**
+ * Setup a rerender function that will drain the queue of pending renders
+ * @returns {() => void}
+ */
+export function setupRerender() {
+ options.__test__previousDebounce = options.debounceRendering;
+ options.debounceRendering = cb => (options.__test__drainQueue = cb);
+ return () => options.__test__drainQueue && options.__test__drainQueue();
+}
+
+const isThenable = value => value != null && typeof value.then == 'function';
+
+/** Depth of nested calls to `act`. */
+let actDepth = 0;
+
+/**
+ * Run a test function, and flush all effects and rerenders after invoking it.
+ *
+ * Returns a Promise which resolves "immediately" if the callback is
+ * synchronous or when the callback's result resolves if it is asynchronous.
+ *
+ * @param {() => void|Promise<void>} cb The function under test. This may be sync or async.
+ * @return {Promise<void>}
+ */
+export function act(cb) {
+ if (++actDepth > 1) {
+ // If calls to `act` are nested, a flush happens only when the
+ // outermost call returns. In the inner call, we just execute the
+ // callback and return since the infrastructure for flushing has already
+ // been set up.
+ //
+ // If an exception occurs, the outermost `act` will handle cleanup.
+ const result = cb();
+ if (isThenable(result)) {
+ return result.then(() => {
+ --actDepth;
+ });
+ }
+ --actDepth;
+ return Promise.resolve();
+ }
+
+ const previousRequestAnimationFrame = options.requestAnimationFrame;
+ const rerender = setupRerender();
+
+ /** @type {() => void} */
+ let flush, toFlush;
+
+ // Override requestAnimationFrame so we can flush pending hooks.
+ options.requestAnimationFrame = fc => (flush = fc);
+
+ const finish = () => {
+ try {
+ rerender();
+ while (flush) {
+ toFlush = flush;
+ flush = null;
+
+ toFlush();
+ rerender();
+ }
+ teardown();
+ } catch (e) {
+ if (!err) {
+ err = e;
+ }
+ }
+
+ options.requestAnimationFrame = previousRequestAnimationFrame;
+ --actDepth;
+ };
+
+ let err;
+ let result;
+
+ try {
+ result = cb();
+ } catch (e) {
+ err = e;
+ }
+
+ if (isThenable(result)) {
+ return result.then(finish, err => {
+ finish();
+ throw err;
+ });
+ }
+
+ // nb. If the callback is synchronous, effects must be flushed before
+ // `act` returns, so that the caller does not have to await the result,
+ // even though React recommends this.
+ finish();
+ if (err) {
+ throw err;
+ }
+ return Promise.resolve();
+}
+
+/**
+ * Teardown test environment and reset preact's internal state
+ */
+export function teardown() {
+ if (options.__test__drainQueue) {
+ // Flush any pending updates leftover by test
+ options.__test__drainQueue();
+ delete options.__test__drainQueue;
+ }
+
+ if (typeof options.__test__previousDebounce != 'undefined') {
+ options.debounceRendering = options.__test__previousDebounce;
+ delete options.__test__previousDebounce;
+ } else {
+ options.debounceRendering = undefined;
+ }
+}
diff --git a/preact/test-utils/test/shared/act.test.js b/preact/test-utils/test/shared/act.test.js
new file mode 100644
index 0000000..7769b5b
--- /dev/null
+++ b/preact/test-utils/test/shared/act.test.js
@@ -0,0 +1,479 @@
+import { options, createElement, render } from 'preact';
+import { useEffect, useReducer, useState } from 'preact/hooks';
+import { act } from 'preact/test-utils';
+import { setupScratch, teardown } from '../../../test/_util/helpers';
+
+/** @jsx createElement */
+
+// IE11 doesn't support `new Event()`
+function createEvent(name) {
+ if (typeof Event == 'function') return new Event(name);
+
+ const event = document.createEvent('Event');
+ event.initEvent(name, true, true);
+ return event;
+}
+
+describe('act', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ options.debounceRendering = undefined;
+ });
+
+ it('should reset options after act finishes', () => {
+ expect(options.requestAnimationFrame).to.equal(undefined);
+ act(() => null);
+ expect(options.requestAnimationFrame).to.equal(undefined);
+ });
+
+ it('should flush pending effects', () => {
+ let spy = sinon.spy();
+ function StateContainer() {
+ useEffect(spy);
+ return <div />;
+ }
+ act(() => render(<StateContainer />, scratch));
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should flush pending and initial effects', () => {
+ const spy = sinon.spy();
+ function StateContainer() {
+ const [count, setCount] = useState(0);
+ useEffect(() => spy(), [count]);
+ return (
+ <div>
+ <p>Count: {count}</p>
+ <button onClick={() => setCount(c => c + 11)} />
+ </div>
+ );
+ }
+
+ act(() => render(<StateContainer />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.textContent).to.include('Count: 0');
+ act(() => {
+ const button = scratch.querySelector('button');
+ button.click();
+ expect(spy).to.be.calledOnce;
+ expect(scratch.textContent).to.include('Count: 0');
+ });
+ expect(spy).to.be.calledTwice;
+ expect(scratch.textContent).to.include('Count: 1');
+ });
+
+ it('should flush series of hooks', () => {
+ const spy = sinon.spy();
+ const spy2 = sinon.spy();
+ function StateContainer() {
+ const [count, setCount] = useState(0);
+ useEffect(() => {
+ spy();
+ if (count === 1) {
+ setCount(() => 2);
+ }
+ }, [count]);
+ useEffect(() => {
+ if (count === 2) {
+ spy2();
+ setCount(() => 4);
+ return () => setCount(() => 3);
+ }
+ }, [count]);
+ return (
+ <div>
+ <p>Count: {count}</p>
+ <button onClick={() => setCount(c => c + 1)} />
+ </div>
+ );
+ }
+ act(() => render(<StateContainer />, scratch));
+ expect(spy).to.be.calledOnce;
+ expect(scratch.textContent).to.include('Count: 0');
+ act(() => {
+ const button = scratch.querySelector('button');
+ button.click();
+ });
+ expect(spy.callCount).to.equal(5);
+ expect(spy2).to.be.calledOnce;
+ expect(scratch.textContent).to.include('Count: 3');
+ });
+
+ it('should drain the queue of hooks', () => {
+ const spy = sinon.spy();
+ function StateContainer() {
+ const [count, setCount] = useState(0);
+ useEffect(() => spy());
+ return (
+ <div>
+ <p>Count: {count}</p>
+ <button onClick={() => setCount(c => c + 11)} />
+ </div>
+ );
+ }
+
+ render(<StateContainer />, scratch);
+ expect(scratch.textContent).to.include('Count: 0');
+ act(() => {
+ const button = scratch.querySelector('button');
+ button.click();
+ expect(scratch.textContent).to.include('Count: 0');
+ });
+ expect(scratch.textContent).to.include('Count: 1');
+ });
+
+ it('should restore options.requestAnimationFrame', () => {
+ const spy = sinon.spy();
+
+ options.requestAnimationFrame = spy;
+ act(() => null);
+
+ expect(options.requestAnimationFrame).to.equal(spy);
+ expect(spy).to.not.be.called;
+ });
+
+ it('should restore options.debounceRendering', () => {
+ const spy = sinon.spy();
+
+ options.debounceRendering = spy;
+ act(() => null);
+
+ expect(options.debounceRendering).to.equal(spy);
+ expect(spy).to.not.be.called;
+ });
+
+ it('should restore options.debounceRendering when it was undefined before', () => {
+ act(() => null);
+ expect(options.debounceRendering).to.equal(undefined);
+ });
+
+ it('should flush state updates if there are pending state updates before `act` call', () => {
+ function CounterButton() {
+ const [count, setCount] = useState(0);
+ const increment = () => setCount(count => count + 1);
+ return <button onClick={increment}>{count}</button>;
+ }
+
+ render(<CounterButton />, scratch);
+ const button = scratch.querySelector('button');
+
+ // Click button. This will schedule an update which is deferred, as is
+ // normal for Preact, since it happens outside an `act` call.
+ button.dispatchEvent(createEvent('click'));
+
+ expect(button.textContent).to.equal('0');
+
+ act(() => {
+ // Click button a second time. This will schedule a second update.
+ button.dispatchEvent(createEvent('click'));
+ });
+ // All state updates should be applied synchronously after the `act`
+ // callback has run but before `act` returns.
+ expect(button.textContent).to.equal('2');
+ });
+
+ it('should flush effects if there are pending effects before `act` call', () => {
+ function Counter() {
+ const [count, setCount] = useState(0);
+ useEffect(() => {
+ setCount(count => count + 1);
+ }, []);
+ return <div>{count}</div>;
+ }
+
+ // Render a component which schedules an effect outside of an `act`
+ // call. This will be scheduled to execute after the next paint as usual.
+ render(<Counter />, scratch);
+ expect(scratch.firstChild.textContent).to.equal('0');
+
+ // Render a component inside an `act` call, this effect should be
+ // executed synchronously before `act` returns.
+ act(() => {
+ render(<div />, scratch);
+ render(<Counter />, scratch);
+ });
+ expect(scratch.firstChild.textContent).to.equal('1');
+ });
+
+ it('returns a Promise if invoked with a sync callback', () => {
+ const result = act(() => {});
+ expect(result.then).to.be.a('function');
+ return result;
+ });
+
+ it('returns a Promise if invoked with an async callback', () => {
+ const result = act(async () => {});
+ expect(result.then).to.be.a('function');
+ return result;
+ });
+
+ it('should await "thenable" result of callback before flushing', async () => {
+ const events = [];
+
+ function TestComponent() {
+ useEffect(() => {
+ events.push('flushed effect');
+ }, []);
+ events.push('scheduled effect');
+ return <div>Test</div>;
+ }
+
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+ events.push('began test');
+ const acted = act(async () => {
+ events.push('began act callback');
+ await delay(1);
+ render(<TestComponent />, scratch);
+ events.push('end act callback');
+ });
+ events.push('act returned');
+ await acted;
+ events.push('act result resolved');
+
+ expect(events).to.deep.equal([
+ 'began test',
+ 'began act callback',
+ 'act returned',
+ 'scheduled effect',
+ 'end act callback',
+ 'flushed effect',
+ 'act result resolved'
+ ]);
+ });
+
+ context('when `act` calls are nested', () => {
+ it('should invoke nested sync callback and return a Promise', () => {
+ let innerResult;
+ const spy = sinon.stub();
+
+ act(() => {
+ innerResult = act(spy);
+ });
+
+ expect(spy).to.be.calledOnce;
+ expect(innerResult.then).to.be.a('function');
+ });
+
+ it('should invoke nested async callback and return a Promise', async () => {
+ const events = [];
+
+ await act(async () => {
+ events.push('began outer act callback');
+ await act(async () => {
+ events.push('began inner act callback');
+ await Promise.resolve();
+ events.push('end inner act callback');
+ });
+ events.push('end outer act callback');
+ });
+ events.push('act finished');
+
+ expect(events).to.deep.equal([
+ 'began outer act callback',
+ 'began inner act callback',
+ 'end inner act callback',
+ 'end outer act callback',
+ 'act finished'
+ ]);
+ });
+
+ it('should only flush effects when outer `act` call returns', () => {
+ let counter = 0;
+
+ function Widget() {
+ useEffect(() => {
+ ++counter;
+ });
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
+ return <button onClick={forceUpdate}>test</button>;
+ }
+
+ act(() => {
+ render(<Widget />, scratch);
+ const button = scratch.querySelector('button');
+ expect(counter).to.equal(0);
+
+ act(() => {
+ button.dispatchEvent(createEvent('click'));
+ });
+
+ // Effect triggered by inner `act` call should not have been
+ // flushed yet.
+ expect(counter).to.equal(0);
+ });
+
+ // Effects triggered by inner `act` call should now have been
+ // flushed.
+ expect(counter).to.equal(2);
+ });
+
+ it('should only flush updates when outer `act` call returns', () => {
+ function Button() {
+ const [count, setCount] = useState(0);
+ const increment = () => setCount(count => count + 1);
+ return <button onClick={increment}>{count}</button>;
+ }
+
+ render(<Button />, scratch);
+ const button = scratch.querySelector('button');
+ expect(button.textContent).to.equal('0');
+
+ act(() => {
+ act(() => {
+ button.dispatchEvent(createEvent('click'));
+ });
+
+ // Update triggered by inner `act` call should not have been
+ // flushed yet.
+ expect(button.textContent).to.equal('0');
+ });
+
+ // Updates from outer and inner `act` calls should now have been
+ // flushed.
+ expect(button.textContent).to.equal('1');
+ });
+ });
+
+ describe('when `act` callback throws an exception', () => {
+ function BrokenWidget() {
+ throw new Error('BrokenWidget is broken');
+ }
+
+ let effectCount;
+
+ function WorkingWidget() {
+ const [count, setCount] = useState(0);
+
+ useEffect(() => {
+ ++effectCount;
+ }, []);
+
+ if (count === 0) {
+ setCount(1);
+ }
+
+ return <div>{count}</div>;
+ }
+
+ beforeEach(() => {
+ effectCount = 0;
+ });
+
+ const renderBroken = () => {
+ act(() => {
+ render(<BrokenWidget />, scratch);
+ });
+ };
+
+ const renderWorking = () => {
+ act(() => {
+ render(<WorkingWidget />, scratch);
+ });
+ };
+
+ const tryRenderBroken = () => {
+ try {
+ renderBroken();
+ } catch (e) {}
+ };
+
+ describe('synchronously', () => {
+ it('should rethrow the exception', () => {
+ expect(renderBroken).to.throw('BrokenWidget is broken');
+ });
+
+ it('should not affect state updates in future renders', () => {
+ tryRenderBroken();
+ renderWorking();
+ expect(scratch.textContent).to.equal('1');
+ });
+
+ it('should not affect effects in future renders', () => {
+ tryRenderBroken();
+ renderWorking();
+ expect(effectCount).to.equal(1);
+ });
+ });
+
+ describe('asynchronously', () => {
+ const renderBrokenAsync = async () => {
+ await act(async () => {
+ render(<BrokenWidget />, scratch);
+ });
+ };
+
+ it('should rethrow the exception', async () => {
+ let err;
+ try {
+ await renderBrokenAsync();
+ } catch (e) {
+ err = e;
+ }
+ expect(err.message).to.equal('BrokenWidget is broken');
+ });
+
+ it('should not affect state updates in future renders', async () => {
+ try {
+ await renderBrokenAsync();
+ } catch (e) {}
+
+ renderWorking();
+ expect(scratch.textContent).to.equal('1');
+ });
+
+ it('should not affect effects in future renders', async () => {
+ try {
+ await renderBrokenAsync();
+ } catch (e) {}
+
+ renderWorking();
+ expect(effectCount).to.equal(1);
+ });
+ });
+
+ describe('in an effect', () => {
+ function BrokenEffect() {
+ useEffect(() => {
+ throw new Error('BrokenEffect effect');
+ }, []);
+ return null;
+ }
+
+ const renderBrokenEffect = () => {
+ act(() => {
+ render(<BrokenEffect />, scratch);
+ });
+ };
+
+ it('should rethrow the exception', () => {
+ expect(renderBrokenEffect).to.throw('BrokenEffect effect');
+ });
+
+ it('should not affect state updates in future renders', () => {
+ try {
+ renderBrokenEffect();
+ } catch (e) {}
+
+ renderWorking();
+ expect(scratch.textContent).to.equal('1');
+ });
+
+ it('should not affect effects in future renders', () => {
+ try {
+ renderBrokenEffect();
+ } catch (e) {}
+
+ renderWorking();
+ expect(effectCount).to.equal(1);
+ });
+ });
+ });
+});
diff --git a/preact/test-utils/test/shared/rerender.test.js b/preact/test-utils/test/shared/rerender.test.js
new file mode 100644
index 0000000..a2e4335
--- /dev/null
+++ b/preact/test-utils/test/shared/rerender.test.js
@@ -0,0 +1,59 @@
+import { options, createElement, render, Component } from 'preact';
+import { teardown, setupRerender } from 'preact/test-utils';
+
+/** @jsx createElement */
+
+describe('setupRerender & teardown', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = document.createElement('div');
+ });
+
+ it('should restore previous debounce', () => {
+ let spy = (options.debounceRendering = sinon.spy());
+
+ setupRerender();
+ teardown();
+
+ expect(options.debounceRendering).to.equal(spy);
+ });
+
+ it('teardown should flush the queue', () => {
+ /** @type {() => void} */
+ let increment;
+ class Counter extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { count: 0 };
+ increment = () => this.setState({ count: this.state.count + 1 });
+ }
+
+ render() {
+ return <div>{this.state.count}</div>;
+ }
+ }
+
+ sinon.spy(Counter.prototype, 'render');
+
+ // Setup rerender
+ setupRerender();
+
+ // Initial render
+ render(<Counter />, scratch);
+ expect(Counter.prototype.render).to.have.been.calledOnce;
+ expect(scratch.innerHTML).to.equal('<div>0</div>');
+
+ // queue rerender
+ increment();
+ expect(Counter.prototype.render).to.have.been.calledOnce;
+ expect(scratch.innerHTML).to.equal('<div>0</div>');
+
+ // Pretend test forgot to call rerender. Teardown should do that
+ teardown();
+ expect(Counter.prototype.render).to.have.been.calledTwice;
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+ });
+});
diff --git a/preact/test/TODO.md b/preact/test/TODO.md
new file mode 100644
index 0000000..b7b1aab
--- /dev/null
+++ b/preact/test/TODO.md
@@ -0,0 +1,13 @@
+# Tests skipped to get CI to pass
+
+- Fragment
+ - ✖ should not preserve state between array nested in fragment and double nested array
+ - ✖ should preserve state between double nested fragment and double nested array
+- hydrate
+ - ✖ should override incorrect pre-existing DOM with VNodes passed into render
+
+Also:
+
+- Extend Fragment preserving state tests to track unmounting lifecycle callbacks to verify
+ components are properly unmounted. I think all 'should not preserve' tests are the ones
+ that will have unmount operations.
diff --git a/preact/test/_util/bench.js b/preact/test/_util/bench.js
new file mode 100644
index 0000000..5085daa
--- /dev/null
+++ b/preact/test/_util/bench.js
@@ -0,0 +1,46 @@
+global._ = require('lodash');
+const Benchmark = (global.Benchmark = require('benchmark'));
+
+export default function bench(benches, callback) {
+ return new Promise(resolve => {
+ const suite = new Benchmark.Suite();
+
+ let i = 0;
+ Object.keys(benches).forEach(name => {
+ let run = benches[name];
+ suite.add(name, () => {
+ run(++i);
+ });
+ });
+
+ suite.on('complete', () => {
+ const result = {
+ fastest: suite.filter('fastest')[0],
+ results: [],
+ text: ''
+ };
+ const useKilo = suite.filter(b => b.hz < 10000).length === 0;
+ suite.forEach((bench, index) => {
+ let r = {
+ name: bench.name,
+ slowdown:
+ bench.name === result.fastest.name
+ ? 0
+ : (((result.fastest.hz - bench.hz) / result.fastest.hz) * 100) |
+ 0,
+ hz: bench.hz.toFixed(bench.hz < 100 ? 2 : 0),
+ rme: bench.stats.rme.toFixed(2),
+ size: bench.stats.sample.length,
+ error: bench.error ? String(bench.error) : undefined
+ };
+ result.text += `\n ${r.name}: ${
+ useKilo ? `${(r.hz / 1000) | 0} kHz` : `${r.hz} Hz`
+ }${r.slowdown ? ` (-${r.slowdown}%)` : ''}`;
+ result.results[index] = result.results[r.name] = r;
+ });
+ resolve(result);
+ if (callback) callback(result);
+ });
+ suite.run({ async: true });
+ });
+}
diff --git a/preact/test/_util/dom.js b/preact/test/_util/dom.js
new file mode 100644
index 0000000..b24bd3e
--- /dev/null
+++ b/preact/test/_util/dom.js
@@ -0,0 +1,66 @@
+/**
+ * Serialize contents
+ * @typedef {string | number | Array<string | number>} Contents
+ * @param {Contents} contents
+ */
+const serialize = contents =>
+ Array.isArray(contents) ? contents.join('') : contents.toString();
+
+/**
+ * A helper to generate innerHTML validation strings containing spans
+ * @param {Contents} contents The contents of the span, as a string
+ */
+export const span = contents => `<span>${serialize(contents)}</span>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing divs
+ * @param {Contents} contents The contents of the div, as a string
+ */
+export const div = contents => `<div>${serialize(contents)}</div>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing p
+ * @param {Contents} contents The contents of the p, as a string
+ */
+export const p = contents => `<p>${serialize(contents)}</p>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing sections
+ * @param {Contents} contents The contents of the section, as a string
+ */
+export const section = contents => `<section>${serialize(contents)}</section>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing uls
+ * @param {Contents} contents The contents of the ul, as a string
+ */
+export const ul = contents => `<ul>${serialize(contents)}</ul>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing ols
+ * @param {Contents} contents The contents of the ol, as a string
+ */
+export const ol = contents => `<ol>${serialize(contents)}</ol>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing lis
+ * @param {Contents} contents The contents of the li, as a string
+ */
+export const li = contents => `<li>${serialize(contents)}</li>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing inputs
+ */
+export const input = () => `<input type="text">`;
+
+/**
+ * A helper to generate innerHTML validation strings containing h1
+ * @param {Contents} contents The contents of the h1
+ */
+export const h1 = contents => `<h1>${serialize(contents)}</h1>`;
+
+/**
+ * A helper to generate innerHTML validation strings containing h2
+ * @param {Contents} contents The contents of the h2
+ */
+export const h2 = contents => `<h2>${serialize(contents)}</h2>`;
diff --git a/preact/test/_util/helpers.js b/preact/test/_util/helpers.js
new file mode 100644
index 0000000..8f0cf02
--- /dev/null
+++ b/preact/test/_util/helpers.js
@@ -0,0 +1,292 @@
+import { createElement, options } from 'preact';
+import { clearLog, getLog } from './logCall';
+import { teardown as testUtilTeardown } from 'preact/test-utils';
+
+/** @jsx createElement */
+
+/**
+ * Assign properties from `props` to `obj`
+ * @template O, P The obj and props types
+ * @param {O} obj The object to copy properties to
+ * @param {P} props The object to copy properties from
+ * @returns {O & P}
+ */
+function assign(obj, props) {
+ for (let i in props) obj[i] = props[i];
+ return /** @type {O & P} */ (obj);
+}
+
+export function supportsPassiveEvents() {
+ let supported = false;
+ try {
+ let options = {
+ get passive() {
+ supported = true;
+ return undefined;
+ }
+ };
+
+ window.addEventListener('test', options, options);
+ window.removeEventListener('test', options, options);
+ } catch (err) {
+ supported = false;
+ }
+ return supported;
+}
+
+export function supportsDataList() {
+ return (
+ 'list' in document.createElement('input') &&
+ Boolean(
+ document.createElement('datalist') && 'HTMLDataListElement' in window
+ )
+ );
+}
+
+const VOID_ELEMENTS = /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;
+
+function encodeEntities(str) {
+ return str.replace(/&/g, '&amp;');
+}
+
+/**
+ * Normalize svg paths spacing. Some browsers insert spaces around letters,
+ * others do not.
+ * @param {string} str
+ * @returns {string}
+ */
+function normalizePath(str) {
+ let len = str.length;
+ let out = '';
+ for (let i = 0; i < len; i++) {
+ const char = str[i];
+ if (/[A-Za-z]/.test(char)) {
+ if (i == 0) out += char + ' ';
+ else
+ out += (str[i - 1] == ' ' ? '' : ' ') + char + (i < len - 1 ? ' ' : '');
+ } else if (char == '-' && str[i - 1] !== ' ') out += ' ' + char;
+ else out += char;
+ }
+
+ return out.replace(/\s\s+/g, ' ').replace(/z/g, 'Z');
+}
+
+export function serializeHtml(node) {
+ let str = '';
+ let child = node.firstChild;
+ while (child) {
+ str += serializeDomTree(child);
+ child = child.nextSibling;
+ }
+ return str;
+}
+
+/**
+ * Serialize a DOM tree.
+ * Uses deterministic sorting where necessary to ensure consistent tests.
+ * @param {Element|Node} node The root node to serialize
+ * @returns {string} html
+ */
+function serializeDomTree(node) {
+ if (node.nodeType === 3) {
+ return encodeEntities(node.data);
+ } else if (node.nodeType === 8) {
+ return '<!--' + encodeEntities(node.data) + '-->';
+ } else if (node.nodeType === 1 || node.nodeType === 9) {
+ let str = '<' + node.localName;
+ const attrs = [];
+ for (let i = 0; i < node.attributes.length; i++) {
+ attrs.push(node.attributes[i].name);
+ }
+ attrs.sort();
+ for (let i = 0; i < attrs.length; i++) {
+ const name = attrs[i];
+ let value = node.getAttribute(name);
+
+ // don't render attributes with null or undefined values
+ if (value == null) continue;
+
+ // normalize empty class attribute
+ if (!value && name === 'class') continue;
+
+ str += ' ' + name;
+ value = encodeEntities(value);
+
+ // normalize svg <path d="value">
+ if (node.localName === 'path' && name === 'd') {
+ value = normalizePath(value);
+ }
+ str += '="' + value + '"';
+ }
+ str += '>';
+
+ // For elements that don't have children (e.g. <wbr />) don't descend.
+ if (!VOID_ELEMENTS.test(node.localName)) {
+ // IE puts the value of a textarea as its children while other browsers don't.
+ // Normalize those differences by forcing textarea to not have children.
+ if (node.localName != 'textarea') {
+ let child = node.firstChild;
+ while (child) {
+ str += serializeDomTree(child);
+ child = child.nextSibling;
+ }
+ }
+
+ str += '</' + node.localName + '>';
+ }
+ return str;
+ }
+}
+
+/**
+ * Normalize event creation in browsers
+ * @param {string} name
+ * @returns {Event}
+ */
+export function createEvent(name) {
+ // Modern browsers
+ if (typeof Event == 'function') {
+ return new Event(name);
+ }
+
+ // IE 11...
+ let event = document.createEvent('Event');
+ event.initEvent(name, true, true);
+ return event;
+}
+
+/**
+ * Sort a cssText alphabetically.
+ * @param {string} cssText
+ */
+export function sortCss(cssText) {
+ return (
+ cssText
+ .split(';')
+ .filter(Boolean)
+ .map(s => s.replace(/^\s+|\s+$/g, '').replace(/(\s*:\s*)/g, ': '))
+ .sort((a, b) => {
+ // CSS Variables are typically positioned at the start
+ if (a[0] === '-') {
+ // If both are a variable we just compare them
+ if (b[0] === '-') return a.localeCompare(b);
+ return -1;
+ }
+ // b is a css var
+ if (b[0] === '-') return 1;
+
+ return a.localeCompare(b);
+ })
+ .join('; ') + ';'
+ );
+}
+
+/**
+ * Setup the test environment
+ * @returns {HTMLDivElement}
+ */
+export function setupScratch() {
+ const scratch = document.createElement('div');
+ scratch.id = 'scratch';
+ (document.body || document.documentElement).appendChild(scratch);
+ return scratch;
+}
+
+let oldOptions = null;
+export function clearOptions() {
+ oldOptions = assign({}, options);
+ delete options.vnode;
+ delete options.diffed;
+ delete options.unmount;
+ delete options._diff;
+}
+
+/**
+ * Teardown test environment and reset preact's internal state
+ * @param {HTMLDivElement} scratch
+ */
+export function teardown(scratch) {
+ if (scratch) {
+ scratch.parentNode.removeChild(scratch);
+ }
+
+ if (oldOptions != null) {
+ assign(options, oldOptions);
+ oldOptions = null;
+ }
+
+ testUtilTeardown();
+
+ if (getLog().length > 0) {
+ clearLog();
+ }
+
+ restoreElementAttributes();
+}
+
+const Foo = () => 'd';
+export const getMixedArray = () =>
+ // Make it a function so each test gets a new copy of the array
+ [0, 'a', 'b', <span>c</span>, <Foo />, null, undefined, false, ['e', 'f'], 1];
+export const mixedArrayHTML = '0ab<span>c</span>def1';
+
+/**
+ * Reset obj to empty to keep reference
+ * @param {object} obj
+ */
+export function clear(obj) {
+ Object.keys(obj).forEach(key => delete obj[key]);
+}
+
+/**
+ * Hacky normalization of attribute order across browsers.
+ * @param {string} html
+ */
+export function sortAttributes(html) {
+ return html.replace(
+ /<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi,
+ (s, pre, attrs, after) => {
+ let list = attrs
+ .match(/\s[a-z0-9:_.-]+=".*?"/gi)
+ .sort((a, b) => (a > b ? 1 : -1));
+ if (~after.indexOf('/')) after = '></' + pre + '>';
+ return '<' + pre + list.join('') + after;
+ }
+ );
+}
+
+let attributesSpy, originalAttributesPropDescriptor;
+
+export function spyOnElementAttributes() {
+ const test = Object.getOwnPropertyDescriptor(Element.prototype, 'attributes');
+
+ // IE11 doesn't correctly restore the prototype methods so we have to check
+ // whether this prototype method is already a sinon spy.
+ if (!attributesSpy && !(test && test.get && test.get.isSinonProxy)) {
+ if (!originalAttributesPropDescriptor) {
+ originalAttributesPropDescriptor = Object.getOwnPropertyDescriptor(
+ Element.prototype,
+ 'attributes'
+ );
+ }
+
+ attributesSpy = sinon.spy(Element.prototype, 'attributes', ['get']);
+ } else if (test && test.get && test.get.isSinonProxy) {
+ // Due to IE11 not resetting we will do this manually when it is a proxy.
+ test.get.resetHistory();
+ }
+
+ return attributesSpy || test;
+}
+
+function restoreElementAttributes() {
+ if (originalAttributesPropDescriptor) {
+ // Workaround bug in Sinon where getter/setter spies don't get auto-restored
+ Object.defineProperty(
+ Element.prototype,
+ 'attributes',
+ originalAttributesPropDescriptor
+ );
+ attributesSpy = null;
+ }
+}
diff --git a/preact/test/_util/logCall.js b/preact/test/_util/logCall.js
new file mode 100644
index 0000000..0eff282
--- /dev/null
+++ b/preact/test/_util/logCall.js
@@ -0,0 +1,66 @@
+/**
+ * Serialize an object
+ * @param {Object} obj
+ * @return {string}
+ */
+function serialize(obj) {
+ if (obj instanceof Text) return '#text';
+ if (obj instanceof Element) return `<${obj.localName}>${obj.textContent}`;
+ if (obj === document) return 'document';
+ if (typeof obj == 'string') return obj;
+ return Object.prototype.toString.call(obj).replace(/(^\[object |\]$)/g, '');
+}
+
+/** @type {string[]} */
+let log = [];
+
+/**
+ * Modify obj's original method to log calls and arguments on logger object
+ * @template T
+ * @param {T} obj
+ * @param {keyof T} method
+ */
+export function logCall(obj, method) {
+ let old = obj[method];
+ obj[method] = function(...args) {
+ let c = '';
+ for (let i = 0; i < args.length; i++) {
+ if (c) c += ', ';
+ c += serialize(args[i]);
+ }
+
+ // Normalize removeChild -> remove to keep output clean and readable
+ const operation =
+ method != 'removeChild'
+ ? `${serialize(this)}.${method}(${c})`
+ : `${serialize(c)}.remove()`;
+ log.push(operation);
+ return old.apply(this, args);
+ };
+
+ return () => (obj[method] = old);
+}
+
+/**
+ * Return log object
+ * @return {string[]} log
+ */
+export function getLog() {
+ return log;
+}
+
+/** Clear log object */
+export function clearLog() {
+ log = [];
+}
+
+export function getLogSummary() {
+ /** @type {{ [key: string]: number }} */
+ const summary = {};
+
+ for (let entry of log) {
+ summary[entry] = (summary[entry] || 0) + 1;
+ }
+
+ return summary;
+}
diff --git a/preact/test/_util/optionSpies.js b/preact/test/_util/optionSpies.js
new file mode 100644
index 0000000..de32c52
--- /dev/null
+++ b/preact/test/_util/optionSpies.js
@@ -0,0 +1,39 @@
+import { options as rawOptions } from 'preact';
+
+/** @type {import('preact/src/internal').Options} */
+let options = rawOptions;
+
+let oldVNode = options.vnode;
+let oldEvent = options.event || (e => e);
+let oldAfterDiff = options.diffed;
+let oldUnmount = options.unmount;
+
+let oldRoot = options._root;
+let oldBeforeDiff = options._diff;
+let oldBeforeRender = options._render;
+let oldBeforeCommit = options._commit;
+let oldHook = options._hook;
+let oldCatchError = options._catchError;
+
+export const vnodeSpy = sinon.spy(oldVNode);
+export const eventSpy = sinon.spy(oldEvent);
+export const afterDiffSpy = sinon.spy(oldAfterDiff);
+export const unmountSpy = sinon.spy(oldUnmount);
+
+export const rootSpy = sinon.spy(oldRoot);
+export const beforeDiffSpy = sinon.spy(oldBeforeDiff);
+export const beforeRenderSpy = sinon.spy(oldBeforeRender);
+export const beforeCommitSpy = sinon.spy(oldBeforeCommit);
+export const hookSpy = sinon.spy(oldHook);
+export const catchErrorSpy = sinon.spy(oldCatchError);
+
+options.vnode = vnodeSpy;
+options.event = eventSpy;
+options.diffed = afterDiffSpy;
+options.unmount = unmountSpy;
+options._root = rootSpy;
+options._diff = beforeDiffSpy;
+options._render = beforeRenderSpy;
+options._commit = beforeCommitSpy;
+options._hook = hookSpy;
+options._catchError = catchErrorSpy;
diff --git a/preact/test/benchmarks/performance.test.js b/preact/test/benchmarks/performance.test.js
new file mode 100644
index 0000000..8729878
--- /dev/null
+++ b/preact/test/benchmarks/performance.test.js
@@ -0,0 +1,470 @@
+/*global COVERAGE, ENABLE_PERFORMANCE*/
+/*eslint no-console:0*/
+/** @jsx createElement */
+import { setupScratch, teardown } from '../_util/helpers';
+import {
+ createElement,
+ Component,
+ render,
+ hydrate
+} from 'preact/dist/preact.module';
+
+const MULTIPLIER = ENABLE_PERFORMANCE ? (COVERAGE ? 5 : 1) : 999999;
+
+// let now = typeof performance!=='undefined' && performance.now ? () => performance.now() : () => +new Date();
+if (typeof performance == 'undefined') {
+ window.performance = { now: () => +new Date() };
+}
+
+function loop(iter, time) {
+ let start = performance.now(),
+ count = 0;
+ while (performance.now() - start < time) {
+ count++;
+ iter();
+ }
+ return count;
+}
+
+function benchmark(iter, callback) {
+ let a = 0; // eslint-disable-line no-unused-vars
+ function noop() {
+ try {
+ a++;
+ } finally {
+ a += Math.random();
+ }
+ }
+
+ // warm
+ for (let i = 100; i--; ) noop(), iter();
+
+ let count = 4,
+ time = 500,
+ passes = 0,
+ noops = loop(noop, time),
+ iterations = 0;
+
+ function next() {
+ iterations += loop(iter, time);
+ setTimeout(++passes === count ? done : next, 10);
+ }
+
+ function done() {
+ let ticks = Math.round((noops / iterations) * count),
+ hz = (iterations / count / time) * 1000,
+ message = `${hz | 0}/s (${ticks} ticks)`;
+ callback({ iterations, noops, count, time, ticks, hz, message });
+ }
+
+ next();
+}
+
+describe('performance', function() {
+ let scratch;
+
+ this.timeout(10000);
+
+ before(function() {
+ if (!ENABLE_PERFORMANCE) this.skip();
+ if (COVERAGE) {
+ console.warn(
+ 'WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.'
+ );
+ }
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should rerender without changes fast', done => {
+ let jsx = (
+ <div class="foo bar" data-foo="bar" p={2}>
+ <header>
+ <h1 class="asdf">
+ a {'b'} c {0} d
+ </h1>
+ <nav>
+ <a href="/foo">Foo</a>
+ <a href="/bar">Bar</a>
+ </nav>
+ </header>
+ <main>
+ <form onSubmit={() => {}}>
+ <input type="checkbox" checked />
+ <input type="checkbox" checked={false} />
+ <fieldset>
+ <label>
+ <input type="radio" checked />
+ </label>
+ <label>
+ <input type="radio" />
+ </label>
+ </fieldset>
+ <button-bar>
+ <button style="width:10px; height:10px; border:1px solid #FFF;">
+ Normal CSS
+ </button>
+ <button style="top:0 ; right: 20">Poor CSS</button>
+ <button
+ style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;"
+ icon
+ >
+ Poorer CSS
+ </button>
+ <button
+ style={{ margin: 0, padding: '10px', overflow: 'visible' }}
+ >
+ Object CSS
+ </button>
+ </button-bar>
+ </form>
+ </main>
+ </div>
+ );
+
+ benchmark(
+ () => {
+ render(jsx, scratch);
+ },
+ ({ ticks, message }) => {
+ console.log(`PERF: empty diff: ${message}`);
+ expect(ticks).to.be.below(150 * MULTIPLIER);
+ done();
+ }
+ );
+ });
+
+ it('should rerender repeated trees fast', done => {
+ class Header extends Component {
+ render() {
+ return (
+ <header>
+ <h1 class="asdf">
+ a {'b'} c {0} d
+ </h1>
+ <nav>
+ <a href="/foo">Foo</a>
+ <a href="/bar">Bar</a>
+ </nav>
+ </header>
+ );
+ }
+ }
+ class Form extends Component {
+ render() {
+ return (
+ <form onSubmit={() => {}}>
+ <input type="checkbox" checked />
+ <input type="checkbox" checked={false} />
+ <fieldset>
+ <label>
+ <input type="radio" checked />
+ </label>
+ <label>
+ <input type="radio" />
+ </label>
+ </fieldset>
+ <ButtonBar />
+ </form>
+ );
+ }
+ }
+ class ButtonBar extends Component {
+ render() {
+ return (
+ <button-bar>
+ <Button style="width:10px; height:10px; border:1px solid #FFF;">
+ Normal CSS
+ </Button>
+ <Button style="top:0 ; right: 20">Poor CSS</Button>
+ <Button
+ style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;"
+ icon
+ >
+ Poorer CSS
+ </Button>
+ <Button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>
+ Object CSS
+ </Button>
+ </button-bar>
+ );
+ }
+ }
+ class Button extends Component {
+ render(props) {
+ return <button {...props} />;
+ }
+ }
+ class Main extends Component {
+ render() {
+ return <Form />;
+ }
+ }
+ class Root extends Component {
+ render() {
+ return (
+ <div class="foo bar" data-foo="bar" p={2}>
+ <Header />
+ <Main />
+ </div>
+ );
+ }
+ }
+ class Empty extends Component {
+ render() {
+ return <div />;
+ }
+ }
+ class Parent extends Component {
+ render({ child: C }) {
+ return <C />;
+ }
+ }
+
+ benchmark(
+ () => {
+ render(<Parent child={Root} />, scratch);
+ render(<Parent child={Empty} />, scratch);
+ },
+ ({ ticks, message }) => {
+ console.log(`PERF: repeat diff: ${message}`);
+ expect(ticks).to.be.below(3000 * MULTIPLIER);
+ done();
+ }
+ );
+ });
+
+ it('should construct large VDOM trees fast', done => {
+ const FIELDS = [];
+ for (let i = 100; i--; ) FIELDS.push((i * 999).toString(36));
+
+ let out = [];
+ function digest(vnode) {
+ out.push(vnode);
+ out.length = 0;
+ }
+ benchmark(
+ () => {
+ digest(
+ <div class="foo bar" data-foo="bar" p={2}>
+ <header>
+ <h1 class="asdf">
+ a {'b'} c {0} d
+ </h1>
+ <nav>
+ <a href="/foo">Foo</a>
+ <a href="/bar">Bar</a>
+ </nav>
+ </header>
+ <main>
+ <form onSubmit={() => {}}>
+ <input type="checkbox" checked />
+ <input type="checkbox" />
+ <fieldset>
+ {FIELDS.map(field => (
+ <label>
+ {field}:
+ <input placeholder={field} />
+ </label>
+ ))}
+ </fieldset>
+ <button-bar>
+ <button style="width:10px; height:10px; border:1px solid #FFF;">
+ Normal CSS
+ </button>
+ <button style="top:0 ; right: 20">Poor CSS</button>
+ <button
+ style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;"
+ icon
+ >
+ Poorer CSS
+ </button>
+ <button
+ style={{ margin: 0, padding: '10px', overflow: 'visible' }}
+ >
+ Object CSS
+ </button>
+ </button-bar>
+ </form>
+ </main>
+ </div>
+ );
+ },
+ ({ ticks, message }) => {
+ console.log(`PERF: large VTree: ${message}`);
+ expect(ticks).to.be.below(200 * MULTIPLIER);
+ done();
+ }
+ );
+ });
+
+ it('should mutate styles/properties quickly', done => {
+ let counter = 0;
+ const keyLooper = n => c => (c % n ? `${c}px` : c);
+ const get = (obj, i) => obj[i % obj.length];
+ const CLASSES = ['foo', 'foo bar', '', 'baz-bat', null];
+ const STYLES = [];
+ const MULTIVALUE = [
+ '0 1px',
+ '0 0 1px 0',
+ '0',
+ '1px',
+ '20px 10px',
+ '7em 5px',
+ '1px 0 5em 2px'
+ ];
+ const STYLEKEYS = [
+ ['left', keyLooper(3)],
+ ['top', keyLooper(2)],
+ ['margin', c => get(MULTIVALUE, c).replace('1px', c + 'px')],
+ ['padding', c => get(MULTIVALUE, c)],
+ ['position', c => (c % 5 ? (c % 2 ? 'absolute' : 'relative') : null)],
+ ['display', c => (c % 10 ? (c % 2 ? 'block' : 'inline') : 'none')],
+ [
+ 'color',
+ c =>
+ `rgba(${c % 255}, ${255 - (c % 255)}, ${50 + (c % 150)}, ${(c % 50) /
+ 50})`
+ ],
+ [
+ 'border',
+ c =>
+ c % 5
+ ? `${c % 10}px ${c % 2 ? 'solid' : 'dotted'} ${STYLEKEYS[6][1](c)}`
+ : ''
+ ]
+ ];
+ for (let i = 0; i < 1000; i++) {
+ let style = {};
+ for (let j = 0; j < i % 10; j++) {
+ let conf = get(STYLEKEYS, ++counter);
+ style[conf[0]] = conf[1](counter);
+ }
+ STYLES[i] = style;
+ }
+
+ const app = index => (
+ <div
+ class={get(CLASSES, index)}
+ data-index={index}
+ title={index.toString(36)}
+ >
+ <input type="checkbox" checked={index % 3 == 0} />
+ <input
+ value={`test ${(index / 4) | 0}`}
+ disabled={index % 10 ? null : true}
+ />
+ <div class={get(CLASSES, index * 10)}>
+ <p style={get(STYLES, index)}>p1</p>
+ <p style={get(STYLES, index + 1)}>p2</p>
+ <p style={get(STYLES, index * 2)}>p3</p>
+ <p style={get(STYLES, index * 3 + 1)}>p4</p>
+ </div>
+ </div>
+ );
+
+ let count = 0;
+ benchmark(
+ () => {
+ render(app(++count), scratch);
+ },
+ ({ ticks, message }) => {
+ console.log(`PERF: style/prop mutation: ${message}`);
+ expect(ticks).to.be.below(350 * MULTIPLIER);
+ done();
+ }
+ );
+ });
+
+ it('should hydrate from SSR quickly', done => {
+ class Header extends Component {
+ render() {
+ return (
+ <header>
+ <h1 class="asdf">
+ a {'b'} c {0} d
+ </h1>
+ <nav>
+ <a href="/foo">Foo</a>
+ <a href="/bar">Bar</a>
+ </nav>
+ </header>
+ );
+ }
+ }
+ class Form extends Component {
+ render() {
+ return (
+ <form onSubmit={() => {}}>
+ <input type="checkbox" checked />
+ <input type="checkbox" checked={false} />
+ <fieldset>
+ <label>
+ <input type="radio" checked />
+ </label>
+ <label>
+ <input type="radio" />
+ </label>
+ </fieldset>
+ <ButtonBar />
+ </form>
+ );
+ }
+ }
+ const ButtonBar = () => (
+ <button-bar>
+ <Button style="width:10px; height:10px; border:1px solid #FFF;">
+ Normal CSS
+ </Button>
+ <Button style="top:0 ; right: 20">Poor CSS</Button>
+ <Button
+ style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;"
+ icon
+ >
+ Poorer CSS
+ </Button>
+ <Button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>
+ Object CSS
+ </Button>
+ </button-bar>
+ );
+ class Button extends Component {
+ handleClick() {}
+ render(props) {
+ return <button onClick={this.handleClick} {...props} />;
+ }
+ }
+ const Main = () => <Form />;
+ class App extends Component {
+ render() {
+ return (
+ <div class="foo bar" data-foo="bar" p={2}>
+ <Header />
+ <Main />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ let html = scratch.innerHTML;
+
+ benchmark(
+ () => {
+ scratch.innerHTML = html;
+ hydrate(<App />, scratch);
+ },
+ ({ ticks, message }) => {
+ console.log(`PERF: SSR Hydrate: ${message}`);
+ expect(ticks).to.be.below(3000 * MULTIPLIER);
+ done();
+ }
+ );
+ });
+});
diff --git a/preact/test/benchmarks/text.test.js b/preact/test/benchmarks/text.test.js
new file mode 100644
index 0000000..9106e52
--- /dev/null
+++ b/preact/test/benchmarks/text.test.js
@@ -0,0 +1,101 @@
+/*global COVERAGE, ENABLE_PERFORMANCE */
+/*eslint no-console:0*/
+/** @jsx createElement */
+
+import { setupScratch, teardown } from '../_util/helpers';
+import bench from '../_util/bench';
+import preact8 from '../fixtures/preact';
+import * as preactX from '../../dist/preact.module';
+const MULTIPLIER = ENABLE_PERFORMANCE ? (COVERAGE ? 5 : 1) : 999999;
+
+describe('benchmarks', function() {
+ let scratch;
+
+ this.timeout(100000);
+
+ before(function() {
+ if (!ENABLE_PERFORMANCE) this.skip();
+ if (COVERAGE) {
+ console.warn(
+ 'WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.'
+ );
+ }
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('in-place text update', done => {
+ function createTest({ createElement, render }) {
+ const parent = document.createElement('div');
+ scratch.appendChild(parent);
+
+ function component(randomValue) {
+ return (
+ <div>
+ <h2>Test {randomValue}</h2>
+ <h1>==={randomValue}===</h1>
+ </div>
+ );
+ }
+
+ return value => {
+ const t = value % 100;
+ render(component(t), parent);
+ };
+ }
+
+ function createVanillaTest() {
+ const parent = document.createElement('div');
+ let div, h1, h2, text1, text2;
+ parent.appendChild((div = document.createElement('div')));
+ div.appendChild((h2 = document.createElement('h2')));
+ h2.appendChild(document.createTextNode('Vanilla '));
+ h2.appendChild((text1 = document.createTextNode('0')));
+ div.appendChild((h1 = document.createElement('h1')));
+ h1.appendChild(document.createTextNode('==='));
+ h1.appendChild((text2 = document.createTextNode('0')));
+ h1.appendChild(document.createTextNode('==='));
+ scratch.appendChild(parent);
+
+ return value => {
+ const t = value % 100;
+ text1.data = '' + t;
+ text2.data = '' + t;
+ };
+ }
+
+ const preact8Test = createTest(preact8);
+ const preactXTest = createTest(preactX);
+ const vanillaTest = createVanillaTest();
+
+ for (let i = 100; i--; ) {
+ preact8Test(i);
+ preactXTest(i);
+ vanillaTest(i);
+ }
+
+ bench(
+ {
+ vanilla: vanillaTest,
+ preact8: preact8Test,
+ preactX: preactXTest
+ },
+ ({ text, results }) => {
+ const THRESHOLD = 10 * MULTIPLIER;
+ // const slowdown = Math.sqrt(results.preactX.hz * results.vanilla.hz);
+ const slowdown = results.vanilla.hz / results.preactX.hz;
+ console.log(
+ `in-place text update is ${slowdown.toFixed(2)}x slower:` + text
+ );
+ expect(slowdown).to.be.below(THRESHOLD);
+ done();
+ }
+ );
+ });
+});
diff --git a/preact/test/browser/cloneElement.test.js b/preact/test/browser/cloneElement.test.js
new file mode 100644
index 0000000..80c44c8
--- /dev/null
+++ b/preact/test/browser/cloneElement.test.js
@@ -0,0 +1,87 @@
+import { createElement, cloneElement, createRef } from 'preact';
+
+/** @jsx createElement */
+
+describe('cloneElement', () => {
+ it('should clone components', () => {
+ function Comp() {}
+ const instance = <Comp prop1={1}>hello</Comp>;
+ const clone = cloneElement(instance);
+
+ expect(clone.prototype).to.equal(instance.prototype);
+ expect(clone.type).to.equal(instance.type);
+ expect(clone.props).not.to.equal(instance.props); // Should be a different object...
+ expect(clone.props).to.deep.equal(instance.props); // with the same properties
+ });
+
+ it('should merge new props', () => {
+ function Foo() {}
+ const instance = <Foo prop1={1} prop2={2} />;
+ const clone = cloneElement(instance, { prop1: -1, newProp: -2 });
+
+ expect(clone.prototype).to.equal(instance.prototype);
+ expect(clone.type).to.equal(instance.type);
+ expect(clone.props).not.to.equal(instance.props);
+ expect(clone.props.prop1).to.equal(-1);
+ expect(clone.props.prop2).to.equal(2);
+ expect(clone.props.newProp).to.equal(-2);
+ });
+
+ it('should override children if specified', () => {
+ function Foo() {}
+ const instance = <Foo>hello</Foo>;
+ const clone = cloneElement(instance, null, 'world', '!');
+
+ expect(clone.prototype).to.equal(instance.prototype);
+ expect(clone.type).to.equal(instance.type);
+ expect(clone.props).not.to.equal(instance.props);
+ expect(clone.props.children).to.deep.equal(['world', '!']);
+ });
+
+ it('should override children if null is provided as an argument', () => {
+ function Foo() {}
+ const instance = <Foo>foo</Foo>;
+ const clone = cloneElement(instance, { children: 'bar' }, null);
+
+ expect(clone.prototype).to.equal(instance.prototype);
+ expect(clone.type).to.equal(instance.type);
+ expect(clone.props).not.to.equal(instance.props);
+ expect(clone.props.children).to.be.null;
+ });
+
+ it('should override key if specified', () => {
+ function Foo() {}
+ const instance = <Foo key="1">hello</Foo>;
+
+ let clone = cloneElement(instance);
+ expect(clone.key).to.equal('1');
+
+ clone = cloneElement(instance, { key: '2' });
+ expect(clone.key).to.equal('2');
+ });
+
+ it('should override ref if specified', () => {
+ function a() {}
+ function b() {}
+ function Foo() {}
+ const instance = <Foo ref={a}>hello</Foo>;
+
+ let clone = cloneElement(instance);
+ expect(clone.ref).to.equal(a);
+
+ clone = cloneElement(instance, { ref: b });
+ expect(clone.ref).to.equal(b);
+ });
+
+ it('should normalize props (ref)', () => {
+ const div = <div>hello</div>;
+ const clone = cloneElement(div, { ref: createRef() });
+ expect(clone.props.ref).to.equal(undefined);
+ });
+
+ it('should normalize props (key)', () => {
+ const div = <div>hello</div>;
+ const clone = cloneElement(div, { key: 'myKey' });
+ expect(clone.props.key).to.equal(undefined);
+ });
+});
diff --git a/preact/test/browser/components.test.js b/preact/test/browser/components.test.js
new file mode 100644
index 0000000..405d608
--- /dev/null
+++ b/preact/test/browser/components.test.js
@@ -0,0 +1,2664 @@
+import { createElement, render, Component, Fragment } from 'preact';
+import { setupRerender } from 'preact/test-utils';
+import {
+ setupScratch,
+ teardown,
+ getMixedArray,
+ mixedArrayHTML,
+ serializeHtml,
+ sortAttributes
+} from '../_util/helpers';
+import { div, span, p } from '../_util/dom';
+
+/** @jsx createElement */
+const h = createElement;
+
+function getAttributes(node) {
+ let attrs = {};
+ if (node.attributes) {
+ for (let i = node.attributes.length; i--; ) {
+ attrs[node.attributes[i].name] = node.attributes[i].value;
+ }
+ }
+ return attrs;
+}
+
+describe('Components', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('Component construction', () => {
+ /** @type {object} */
+ let instance;
+ let PROPS;
+ let STATE;
+
+ beforeEach(() => {
+ instance = null;
+ PROPS = { foo: 'bar', onBaz: () => {} };
+ STATE = { text: 'Hello' };
+ });
+
+ it('should render components', () => {
+ class C1 extends Component {
+ render() {
+ return <div>C1</div>;
+ }
+ }
+ sinon.spy(C1.prototype, 'render');
+ render(<C1 />, scratch);
+
+ expect(C1.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch({}, {})
+ .and.to.have.returned(sinon.match({ type: 'div' }));
+
+ expect(scratch.innerHTML).to.equal('<div>C1</div>');
+ });
+
+ it('should render functional components', () => {
+ const C3 = sinon.spy(props => <div {...props} />);
+
+ render(<C3 {...PROPS} />, scratch);
+
+ expect(C3)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS)
+ .and.to.have.returned(
+ sinon.match({
+ type: 'div',
+ props: PROPS
+ })
+ );
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar"></div>');
+ });
+
+ it('should render components with props', () => {
+ let constructorProps;
+
+ class C2 extends Component {
+ constructor(props) {
+ super(props);
+ constructorProps = props;
+ }
+ render(props) {
+ return <div {...props} />;
+ }
+ }
+ sinon.spy(C2.prototype, 'render');
+
+ render(<C2 {...PROPS} />, scratch);
+
+ expect(constructorProps).to.deep.equal(PROPS);
+
+ expect(C2.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS, {})
+ .and.to.have.returned(
+ sinon.match({
+ type: 'div',
+ props: PROPS
+ })
+ );
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar"></div>');
+ });
+
+ it('should not crash when setting state in constructor', () => {
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ // the following line made `this._nextState !== this.state` be truthy prior to the fix for preactjs/preact#2638
+ this.state = {};
+ this.setState({ preact: 'awesome' });
+ }
+ }
+
+ expect(() => render(<Foo foo="bar" />, scratch)).not.to.throw();
+ rerender();
+ });
+
+ it('should not crash when setting state with cb in constructor', () => {
+ let spy = sinon.spy();
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.setState({ preact: 'awesome' }, spy);
+ }
+ }
+
+ expect(() => render(<Foo foo="bar" />, scratch)).not.to.throw();
+ rerender();
+ expect(spy).to.not.be.called;
+ });
+
+ it('should not crash when calling forceUpdate with cb in constructor', () => {
+ let spy = sinon.spy();
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.forceUpdate(spy);
+ }
+ }
+
+ expect(() => render(<Foo foo="bar" />, scratch)).not.to.throw();
+ rerender();
+ expect(spy).to.not.be.called;
+ });
+
+ it('should accurately call nested setState callbacks', () => {
+ let states = [];
+ let finalState;
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { a: 'b' };
+ }
+
+ componentDidMount() {
+ states.push(this.state);
+ expect(scratch.innerHTML).to.equal('<p>b</p>');
+
+ // eslint-disable-next-line
+ this.setState({ a: 'a' }, () => {
+ states.push(this.state);
+ expect(scratch.innerHTML).to.equal('<p>a</p>');
+
+ this.setState({ a: 'c' }, () => {
+ expect(scratch.innerHTML).to.equal('<p>c</p>');
+ states.push(this.state);
+ });
+ });
+ }
+
+ render() {
+ finalState = this.state;
+ return <p>{this.state.a}</p>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ rerender(); // First setState
+ rerender(); // Second setState
+
+ let [firstState, secondState, thirdState] = states;
+ expect(finalState).to.deep.equal({ a: 'c' });
+ expect(firstState).to.deep.equal({ a: 'b' });
+ expect(secondState).to.deep.equal({ a: 'a' });
+ expect(thirdState).to.deep.equal({ a: 'c' });
+ });
+
+ it('should initialize props & context but not state in Component constructor', () => {
+ // Not initializing state matches React behavior: https://codesandbox.io/s/rml19v8o2q
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ expect(this.props).to.equal(props);
+ expect(this.state).to.deep.equal(undefined);
+ expect(this.context).to.equal(context);
+
+ instance = this;
+ }
+ render(props) {
+ return <div {...props}>Hello</div>;
+ }
+ }
+
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS, {}, {})
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal({});
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render Component classes that don't pass args into the Component constructor", () => {
+ function Foo() {
+ Component.call(this);
+ instance = this;
+ this.state = STATE;
+ }
+ Foo.prototype.render = sinon.spy((props, state) => (
+ <div {...props}>{state.text}</div>
+ ));
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(
+ PROPS,
+ STATE,
+ {}
+ )
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal(STATE);
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it('should also update the current dom', () => {
+ let trigger;
+
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: false };
+ trigger = this.set = this.set.bind(this);
+ }
+
+ set() {
+ this.setState({ show: true });
+ }
+
+ render() {
+ return this.state.show ? <div>A</div> : null;
+ }
+ }
+
+ const B = () => <p>B</p>;
+
+ render(
+ <div>
+ <A />
+ <B />
+ </div>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<div><p>B</p></div>');
+
+ trigger();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><div>A</div><p>B</p></div>');
+ });
+
+ it('should not orphan children', () => {
+ let triggerC, triggerA;
+ const B = () => <p>B</p>;
+
+ // Component with state which swaps its returned element type
+ class C extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: false };
+ triggerC = this.set = this.set.bind(this);
+ }
+
+ set() {
+ this.setState({ show: true });
+ }
+
+ render() {
+ return this.state.show ? <div>data</div> : <p>Loading</p>;
+ }
+ }
+
+ const WrapC = () => <C />;
+
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: false };
+ triggerA = this.set = this.set.bind(this);
+ }
+
+ set() {
+ this.setState({ show: true });
+ }
+
+ render() {
+ return this.state.show ? <B /> : <WrapC />;
+ }
+ }
+
+ render(<A />, scratch);
+ expect(scratch.innerHTML).to.equal('<p>Loading</p>');
+
+ triggerC();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>data</div>');
+
+ triggerA();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>B</p>');
+ });
+
+ it("should render components that don't pass args into the Component constructor (unistore pattern)", () => {
+ // Pattern unistore uses for connect: https://git.io/fxRqu
+ function Wrapper() {
+ instance = this;
+ this.state = STATE;
+ this.render = sinon.spy((props, state) => (
+ <div {...props}>{state.text}</div>
+ ));
+ }
+ (Wrapper.prototype = new Component()).constructor = Wrapper;
+
+ render(<Wrapper {...PROPS} />, scratch);
+
+ expect(instance.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(
+ PROPS,
+ STATE,
+ {}
+ )
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal(STATE);
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render components that don't call Component constructor", () => {
+ function Foo() {
+ instance = this;
+ this.state = STATE;
+ }
+ Foo.prototype = Object.create(Component);
+ Foo.prototype.render = sinon.spy((props, state) => (
+ <div {...props}>{state.text}</div>
+ ));
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(
+ PROPS,
+ STATE,
+ {}
+ )
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal(STATE);
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render components that don't call Component constructor and don't initialize state", () => {
+ function Foo() {
+ instance = this;
+ }
+ Foo.prototype.render = sinon.spy(props => <div {...props}>Hello</div>);
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS, {}, {})
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal({});
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render components that don't inherit from Component", () => {
+ class Foo {
+ constructor() {
+ instance = this;
+ this.state = STATE;
+ }
+ render(props, state) {
+ return <div {...props}>{state.text}</div>;
+ }
+ }
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(
+ PROPS,
+ STATE,
+ {}
+ )
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal(STATE);
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render components that don't inherit from Component (unistore pattern)", () => {
+ // Pattern unistore uses for Provider: https://git.io/fxRqR
+ function Provider() {
+ instance = this;
+ this.state = STATE;
+ }
+ Provider.prototype.render = sinon.spy((props, state) => (
+ <div {...PROPS}>{state.text}</div>
+ ));
+
+ render(<Provider {...PROPS} />, scratch);
+
+ expect(Provider.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(
+ PROPS,
+ STATE,
+ {}
+ )
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal(STATE);
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it("should render components that don't inherit from Component and don't initialize state", () => {
+ class Foo {
+ constructor() {
+ instance = this;
+ }
+ render(props, state) {
+ return <div {...props}>Hello</div>;
+ }
+ }
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS, {}, {})
+ .and.to.have.returned(sinon.match({ type: 'div', props: PROPS }));
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal({});
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">Hello</div>');
+ });
+
+ it('should render class components that inherit from Component without a render method', () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ instance = this;
+ }
+ }
+
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo {...PROPS} />, scratch);
+
+ expect(Foo.prototype.render)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS, {}, {})
+ .and.to.have.returned(undefined);
+ expect(instance.props).to.deep.equal(PROPS);
+ expect(instance.state).to.deep.equal({});
+ expect(instance.context).to.deep.equal({});
+
+ expect(scratch.innerHTML).to.equal('');
+ });
+ });
+
+ it('should render string', () => {
+ class StringComponent extends Component {
+ render() {
+ return 'Hi there';
+ }
+ }
+
+ render(<StringComponent />, scratch);
+ expect(scratch.innerHTML).to.equal('Hi there');
+ });
+
+ it('should render number as string', () => {
+ class NumberComponent extends Component {
+ render() {
+ return 42;
+ }
+ }
+
+ render(<NumberComponent />, scratch);
+ expect(scratch.innerHTML).to.equal('42');
+ });
+
+ it('should render null as empty string', () => {
+ class NullComponent extends Component {
+ render() {
+ return null;
+ }
+ }
+
+ render(<NullComponent />, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ // Test for Issue #73
+ it('should remove orphaned elements replaced by Components', () => {
+ class Comp extends Component {
+ render() {
+ return <span>span in a component</span>;
+ }
+ }
+
+ let root;
+ function test(content) {
+ root = render(content, scratch, root);
+ }
+
+ test(<Comp />);
+ test(<div>just a div</div>);
+ test(<Comp />);
+
+ expect(scratch.innerHTML).to.equal('<span>span in a component</span>');
+ });
+
+ // Test for Issue preactjs/preact#176
+ it('should remove children when root changes to text node', () => {
+ /** @type {import('preact').Component} */
+ let comp;
+
+ class Comp extends Component {
+ constructor() {
+ super();
+ comp = this;
+ }
+ render(_, { alt }) {
+ return alt ? 'asdf' : <div>test</div>;
+ }
+ }
+
+ render(<Comp />, scratch);
+
+ comp.setState({ alt: true });
+ comp.forceUpdate();
+ rerender();
+ expect(scratch.innerHTML, 'switching to textnode').to.equal('asdf');
+
+ comp.setState({ alt: false });
+ comp.forceUpdate();
+ rerender();
+ expect(scratch.innerHTML, 'switching to element').to.equal(
+ '<div>test</div>'
+ );
+
+ comp.setState({ alt: true });
+ comp.forceUpdate();
+ rerender();
+ expect(scratch.innerHTML, 'switching to textnode 2').to.equal('asdf');
+ });
+
+ // Test for Issue preactjs/preact#1616
+ it('should maintain order when setting state (that inserts dom-elements)', () => {
+ let add, addTwice, reset;
+ const Entry = props => <div>{props.children}</div>;
+
+ class App extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { values: ['abc'] };
+
+ add = this.add = this.add.bind(this);
+ addTwice = this.addTwice = this.addTwice.bind(this);
+ reset = this.reset = this.reset.bind(this);
+ }
+
+ add() {
+ this.setState({ values: [...this.state.values, 'def'] });
+ }
+
+ addTwice() {
+ this.setState({ values: [...this.state.values, 'def', 'ghi'] });
+ }
+
+ reset() {
+ this.setState({ values: ['abc'] });
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.values.map(v => (
+ <Entry>{v}</Entry>
+ ))}
+ <button>First Button</button>
+ <button>Second Button</button>
+ <button>Third Button</button>
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.firstChild.innerHTML).to.equal(
+ '<div>abc</div>' +
+ '<button>First Button</button><button>Second Button</button><button>Third Button</button>'
+ );
+
+ add();
+ rerender();
+ expect(scratch.firstChild.innerHTML).to.equal(
+ '<div>abc</div><div>def' +
+ '</div><button>First Button</button><button>Second Button</button><button>Third Button</button>'
+ );
+
+ add();
+ rerender();
+ expect(scratch.firstChild.innerHTML).to.equal(
+ '<div>abc</div><div>def</div><div>def' +
+ '</div><button>First Button</button><button>Second Button</button><button>Third Button</button>'
+ );
+
+ reset();
+ rerender();
+ expect(scratch.firstChild.innerHTML).to.equal(
+ '<div>abc</div>' +
+ '<button>First Button</button><button>Second Button</button><button>Third Button</button>'
+ );
+
+ addTwice();
+ rerender();
+ expect(scratch.firstChild.innerHTML).to.equal(
+ '<div>abc</div><div>def</div><div>ghi' +
+ '</div><button>First Button</button><button>Second Button</button><button>Third Button</button>'
+ );
+ });
+
+ // Test for Issue preactjs/preact#254
+ it('should not recycle common class children with different keys', () => {
+ let idx = 0;
+ let msgs = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
+ let sideEffect = sinon.spy();
+
+ class Comp extends Component {
+ componentWillMount() {
+ this.innerMsg = msgs[idx++ % 8];
+ sideEffect();
+ }
+ render() {
+ return <div>{this.innerMsg}</div>;
+ }
+ }
+ sinon.spy(Comp.prototype, 'componentWillMount');
+
+ let good, bad;
+ class GoodContainer extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { alt: false };
+ good = this;
+ }
+
+ render(_, { alt }) {
+ return (
+ <div>
+ {alt ? null : <Comp key={1} alt={alt} />}
+ {alt ? null : <Comp key={2} alt={alt} />}
+ {alt ? <Comp key={3} alt={alt} /> : null}
+ </div>
+ );
+ }
+ }
+
+ class BadContainer extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { alt: false };
+ bad = this;
+ }
+
+ render(_, { alt }) {
+ return (
+ <div>
+ {alt ? null : <Comp alt={alt} />}
+ {alt ? null : <Comp alt={alt} />}
+ {alt ? <Comp alt={alt} /> : null}
+ </div>
+ );
+ }
+ }
+
+ render(<GoodContainer />, scratch);
+ expect(scratch.textContent, 'new component with key present').to.equal(
+ 'AB'
+ );
+ expect(Comp.prototype.componentWillMount).to.have.been.calledTwice;
+ expect(sideEffect).to.have.been.calledTwice;
+
+ sideEffect.resetHistory();
+ Comp.prototype.componentWillMount.resetHistory();
+ good.setState({ alt: true });
+ rerender();
+ expect(
+ scratch.textContent,
+ 'new component with key present re-rendered'
+ ).to.equal('C');
+ //we are recycling the first 2 components already rendered, just need a new one
+ expect(Comp.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(sideEffect).to.have.been.calledOnce;
+
+ sideEffect.resetHistory();
+ Comp.prototype.componentWillMount.resetHistory();
+ render(<BadContainer />, scratch);
+ expect(scratch.textContent, 'new component without key').to.equal('DE');
+ expect(Comp.prototype.componentWillMount).to.have.been.calledTwice;
+ expect(sideEffect).to.have.been.calledTwice;
+
+ sideEffect.resetHistory();
+ Comp.prototype.componentWillMount.resetHistory();
+ bad.setState({ alt: true });
+ rerender();
+
+ expect(
+ scratch.textContent,
+ 'use null placeholders to detect new component is appended'
+ ).to.equal('F');
+ expect(Comp.prototype.componentWillMount).to.be.calledOnce;
+ expect(sideEffect).to.be.calledOnce;
+ });
+
+ describe('array children', () => {
+ it("should render DOM element's array children", () => {
+ render(<div>{getMixedArray()}</div>, scratch);
+ expect(scratch.firstChild.innerHTML).to.equal(mixedArrayHTML);
+ });
+
+ it("should render Component's array children", () => {
+ const Foo = () => getMixedArray();
+
+ render(<Foo />, scratch);
+
+ expect(scratch.innerHTML).to.equal(mixedArrayHTML);
+ });
+
+ it("should render Fragment's array children", () => {
+ const Foo = () => <Fragment>{getMixedArray()}</Fragment>;
+
+ render(<Foo />, scratch);
+
+ expect(scratch.innerHTML).to.equal(mixedArrayHTML);
+ });
+
+ it('should render sibling array children', () => {
+ const Todo = () => (
+ <ul>
+ <li>A header</li>
+ {['a', 'b'].map(value => (
+ <li>{value}</li>
+ ))}
+ <li>A divider</li>
+ {['c', 'd'].map(value => (
+ <li>{value}</li>
+ ))}
+ <li>A footer</li>
+ </ul>
+ );
+
+ render(<Todo />, scratch);
+
+ let ul = scratch.firstChild;
+ expect(ul.childNodes.length).to.equal(7);
+ expect(ul.childNodes[0].textContent).to.equal('A header');
+ expect(ul.childNodes[1].textContent).to.equal('a');
+ expect(ul.childNodes[2].textContent).to.equal('b');
+ expect(ul.childNodes[3].textContent).to.equal('A divider');
+ expect(ul.childNodes[4].textContent).to.equal('c');
+ expect(ul.childNodes[5].textContent).to.equal('d');
+ expect(ul.childNodes[6].textContent).to.equal('A footer');
+ });
+ });
+
+ describe('props.children', () => {
+ let children;
+
+ let Foo = props => {
+ children = props.children;
+ return <div>{props.children}</div>;
+ };
+
+ let FunctionFoo = props => {
+ children = props.children;
+ return <div>{props.children(2)}</div>;
+ };
+
+ let Bar = () => <span>Bar</span>;
+
+ beforeEach(() => {
+ children = undefined;
+ });
+
+ it('should support passing children as a prop', () => {
+ const Foo = props => <div {...props} />;
+
+ render(
+ <Foo a="b" children={[<span class="bar">bar</span>, '123', 456]} />,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(
+ '<div a="b"><span class="bar">bar</span>123456</div>'
+ );
+ });
+
+ it('should be ignored when explicit children exist', () => {
+ const Foo = props => <div {...props}>a</div>;
+
+ render(<Foo children={'b'} />, scratch);
+
+ expect(scratch.innerHTML).to.equal('<div>a</div>');
+ });
+
+ it('should be undefined with no child', () => {
+ render(<Foo />, scratch);
+
+ expect(children).to.be.undefined;
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should be null with null as a child', () => {
+ render(<Foo>{null}</Foo>, scratch);
+
+ expect(children).to.be.null;
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should be false with false as a child', () => {
+ render(<Foo>{false}</Foo>, scratch);
+
+ expect(children).to.be.false;
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should be true with true as a child', () => {
+ render(<Foo>{true}</Foo>, scratch);
+
+ expect(children).to.be.true;
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should be a string with a text child', () => {
+ render(<Foo>text</Foo>, scratch);
+
+ expect(children).to.be.a('string');
+ expect(children).to.equal('text');
+ expect(scratch.innerHTML).to.equal('<div>text</div>');
+ });
+
+ it('should be a string with a number child', () => {
+ render(<Foo>1</Foo>, scratch);
+
+ expect(children).to.be.a('string');
+ expect(children).to.equal('1');
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+ });
+
+ it('should be a VNode with a DOM node child', () => {
+ render(
+ <Foo>
+ <span />
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('object');
+ expect(children.type).to.equal('span');
+ expect(scratch.innerHTML).to.equal('<div><span></span></div>');
+ });
+
+ it('should be a VNode with a Component child', () => {
+ render(
+ <Foo>
+ <Bar />
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('object');
+ expect(children.type).to.equal(Bar);
+ expect(scratch.innerHTML).to.equal('<div><span>Bar</span></div>');
+ });
+
+ it('should be a function with a function child', () => {
+ const child = num => num.toFixed(2);
+ render(<FunctionFoo>{child}</FunctionFoo>, scratch);
+
+ expect(children).to.be.an('function');
+ expect(children).to.equal(child);
+ expect(scratch.innerHTML).to.equal('<div>2.00</div>');
+ });
+
+ it('should be an array with multiple children', () => {
+ render(
+ <Foo>
+ 0<span />
+ <input />
+ <div />1
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(children[0]).to.equal('0');
+ expect(children[1].type).to.equal('span');
+ expect(children[2].type).to.equal('input');
+ expect(children[3].type).to.equal('div');
+ expect(children[4]).to.equal('1');
+ expect(scratch.innerHTML).to.equal(
+ `<div>0<span></span><input><div></div>1</div>`
+ );
+ });
+
+ it('should be an array with an array as children', () => {
+ const mixedArray = getMixedArray();
+ render(<Foo>{mixedArray}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.deep.equal(mixedArray);
+ expect(scratch.innerHTML).to.equal(`<div>${mixedArrayHTML}</div>`);
+ });
+
+ it('should not flatten sibling and nested arrays', () => {
+ const list1 = [0, 1];
+ const list2 = [2, 3];
+ const list3 = [4, 5];
+ const list4 = [6, 7];
+ const list5 = [8, 9];
+
+ render(
+ <Foo>
+ {[list1, list2]}
+ {[list3, list4]}
+ {list5}
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(children).to.deep.equal([[list1, list2], [list3, list4], list5]);
+ expect(scratch.innerHTML).to.equal('<div>0123456789</div>');
+ });
+ });
+
+ describe('High-Order Components', () => {
+ it('should render wrapper HOCs', () => {
+ const text = "We'll throw some happy little limbs on this tree.";
+
+ function withBobRoss(ChildComponent) {
+ return class BobRossIpsum extends Component {
+ getChildContext() {
+ return { text };
+ }
+
+ render(props) {
+ return <ChildComponent {...props} />;
+ }
+ };
+ }
+
+ const PaintSomething = (props, context) => <div>{context.text}</div>;
+ const Paint = withBobRoss(PaintSomething);
+
+ render(<Paint />, scratch);
+ expect(scratch.innerHTML).to.equal(`<div>${text}</div>`);
+ });
+
+ it('should render HOCs with generic children', () => {
+ const text =
+ "Let your imagination just wonder around when you're doing these things.";
+
+ class BobRossProvider extends Component {
+ getChildContext() {
+ return { text };
+ }
+
+ render(props) {
+ return props.children;
+ }
+ }
+
+ function BobRossConsumer(props, context) {
+ return props.children(context.text);
+ }
+
+ const Say = props => <div>{props.text}</div>;
+
+ const Speak = () => (
+ <BobRossProvider>
+ <span>A span</span>
+ <BobRossConsumer>{text => <Say text={text} />}</BobRossConsumer>
+ <span>A final span</span>
+ </BobRossProvider>
+ );
+
+ render(<Speak />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ `<span>A span</span><div>${text}</div><span>A final span</span>`
+ );
+ });
+
+ it('should render nested functional components', () => {
+ const PROPS = { foo: 'bar', onBaz: () => {} };
+
+ const Outer = sinon.spy(props => <Inner {...props} />);
+
+ const Inner = sinon.spy(props => <div {...props}>inner</div>);
+
+ render(<Outer {...PROPS} />, scratch);
+
+ expect(Outer)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS)
+ .and.to.have.returned(
+ sinon.match({
+ type: Inner,
+ props: PROPS
+ })
+ );
+
+ expect(Inner)
+ .to.have.been.calledOnce.and.to.have.been.calledWithMatch(PROPS)
+ .and.to.have.returned(
+ sinon.match({
+ type: 'div',
+ props: { ...PROPS, children: 'inner' }
+ })
+ );
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">inner</div>');
+ });
+
+ it('should re-render nested functional components', () => {
+ let doRender = null;
+ class Outer extends Component {
+ componentDidMount() {
+ let i = 1;
+ doRender = () => this.setState({ i: ++i });
+ }
+ componentWillUnmount() {}
+ render(props, { i }) {
+ return <Inner i={i} {...props} />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'render');
+ sinon.spy(Outer.prototype, 'componentWillUnmount');
+
+ let j = 0;
+ const Inner = sinon.spy(props => (
+ <div j={++j} {...props}>
+ inner
+ </div>
+ ));
+
+ render(<Outer foo="bar" />, scratch);
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Outer.prototype.componentWillUnmount).not.to.have.been.called;
+
+ expect(Inner).to.have.been.calledTwice;
+
+ expect(Inner.secondCall)
+ .to.have.been.calledWithMatch({ foo: 'bar', i: 2 })
+ .and.to.have.returned(
+ sinon.match({
+ props: {
+ j: 2,
+ i: 2,
+ foo: 'bar'
+ }
+ })
+ );
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '2',
+ i: '2',
+ foo: 'bar'
+ });
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Inner).to.have.been.calledThrice;
+
+ expect(Inner.thirdCall)
+ .to.have.been.calledWithMatch({ foo: 'bar', i: 3 })
+ .and.to.have.returned(
+ sinon.match({
+ props: {
+ j: 3,
+ i: 3,
+ foo: 'bar'
+ }
+ })
+ );
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '3',
+ i: '3',
+ foo: 'bar'
+ });
+ });
+
+ it('should re-render nested components', () => {
+ let doRender = null,
+ alt = false;
+
+ class Outer extends Component {
+ componentDidMount() {
+ let i = 1;
+ doRender = () => this.setState({ i: ++i });
+ }
+ componentWillUnmount() {}
+ render(props, { i }) {
+ if (alt) return <div is-alt />;
+ return <Inner i={i} {...props} />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'render');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+ sinon.spy(Outer.prototype, 'componentWillUnmount');
+
+ let j = 0;
+ class Inner extends Component {
+ constructor(...args) {
+ super();
+ }
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render(props) {
+ return (
+ <div j={++j} {...props}>
+ inner
+ </div>
+ );
+ }
+ }
+ sinon.spy(Inner.prototype, 'render');
+ sinon.spy(Inner.prototype, 'componentWillMount');
+ sinon.spy(Inner.prototype, 'componentDidMount');
+ sinon.spy(Inner.prototype, 'componentWillUnmount');
+
+ render(<Outer foo="bar" />, scratch);
+
+ expect(Outer.prototype.componentDidMount).to.have.been.calledOnce;
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Outer.prototype.componentWillUnmount).not.to.have.been.called;
+
+ expect(Inner.prototype.componentWillUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.render).to.have.been.calledTwice;
+
+ expect(Inner.prototype.render.secondCall)
+ .to.have.been.calledWithMatch({ foo: 'bar', i: 2 })
+ .and.to.have.returned(
+ sinon.match({
+ props: {
+ j: 2,
+ i: 2,
+ foo: 'bar'
+ }
+ })
+ );
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '2',
+ i: '2',
+ foo: 'bar'
+ });
+
+ expect(serializeHtml(scratch)).to.equal(
+ sortAttributes('<div foo="bar" j="2" i="2">inner</div>')
+ );
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Inner.prototype.componentWillUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.render).to.have.been.calledThrice;
+
+ expect(Inner.prototype.render.thirdCall)
+ .to.have.been.calledWithMatch({ foo: 'bar', i: 3 })
+ .and.to.have.returned(
+ sinon.match({
+ props: {
+ j: 3,
+ i: 3,
+ foo: 'bar'
+ }
+ })
+ );
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '3',
+ i: '3',
+ foo: 'bar'
+ });
+
+ // update & flush
+ alt = true;
+ doRender();
+ rerender();
+
+ expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce;
+
+ expect(scratch.innerHTML).to.equal('<div is-alt="true"></div>');
+
+ // update & flush
+ alt = false;
+ doRender();
+ rerender();
+
+ expect(serializeHtml(scratch)).to.equal(
+ sortAttributes('<div foo="bar" j="4" i="5">inner</div>')
+ );
+ });
+
+ it('should resolve intermediary functional component', () => {
+ let ctx = {};
+ class Root extends Component {
+ getChildContext() {
+ return { ctx };
+ }
+ render() {
+ return <Func />;
+ }
+ }
+ const Func = () => <Inner />;
+ class Inner extends Component {
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render() {
+ return <div>inner</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'componentWillUnmount');
+ sinon.spy(Inner.prototype, 'componentWillMount');
+ sinon.spy(Inner.prototype, 'componentDidMount');
+ sinon.spy(Inner.prototype, 'render');
+
+ render(<Root />, scratch);
+
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledBefore(
+ Inner.prototype.componentDidMount
+ );
+
+ render(<asdf />, scratch);
+
+ expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce;
+ });
+
+ it('should unmount children of high-order components without unmounting parent', () => {
+ let outer,
+ inner2,
+ counter = 0;
+
+ class Outer extends Component {
+ constructor(props, context) {
+ super(props, context);
+ outer = this;
+ this.state = {
+ child: this.props.child
+ };
+ }
+ componentWillUnmount() {}
+ componentWillMount() {}
+ componentDidMount() {}
+ render(_, { child: C }) {
+ return <C />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'componentWillUnmount');
+ sinon.spy(Outer.prototype, 'componentWillMount');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+ sinon.spy(Outer.prototype, 'render');
+
+ class Inner extends Component {
+ componentWillUnmount() {}
+ componentWillMount() {}
+ componentDidMount() {}
+ render() {
+ return h('element' + ++counter);
+ }
+ }
+ sinon.spy(Inner.prototype, 'componentWillUnmount');
+ sinon.spy(Inner.prototype, 'componentWillMount');
+ sinon.spy(Inner.prototype, 'componentDidMount');
+ sinon.spy(Inner.prototype, 'render');
+
+ class Inner2 extends Component {
+ constructor(props, context) {
+ super(props, context);
+ inner2 = this;
+ }
+ componentWillUnmount() {}
+ componentWillMount() {}
+ componentDidMount() {}
+ render() {
+ return h('element' + ++counter);
+ }
+ }
+ sinon.spy(Inner2.prototype, 'componentWillUnmount');
+ sinon.spy(Inner2.prototype, 'componentWillMount');
+ sinon.spy(Inner2.prototype, 'componentDidMount');
+ sinon.spy(Inner2.prototype, 'render');
+
+ render(<Outer child={Inner} />, scratch);
+
+ // outer should only have been mounted once
+ expect(Outer.prototype.componentWillMount, 'outer initial').to.have.been
+ .calledOnce;
+ expect(Outer.prototype.componentDidMount, 'outer initial').to.have.been
+ .calledOnce;
+ expect(Outer.prototype.componentWillUnmount, 'outer initial').not.to.have
+ .been.called;
+
+ // inner should only have been mounted once
+ expect(Inner.prototype.componentWillMount, 'inner initial').to.have.been
+ .calledOnce;
+ expect(Inner.prototype.componentDidMount, 'inner initial').to.have.been
+ .calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'inner initial').not.to.have
+ .been.called;
+
+ outer.setState({ child: Inner2 });
+ outer.forceUpdate();
+ rerender();
+
+ expect(Inner2.prototype.render).to.have.been.calledOnce;
+
+ // outer should still only have been mounted once
+ expect(Outer.prototype.componentWillMount, 'outer swap').to.have.been
+ .calledOnce;
+ expect(Outer.prototype.componentDidMount, 'outer swap').to.have.been
+ .calledOnce;
+ expect(Outer.prototype.componentWillUnmount, 'outer swap').not.to.have
+ .been.called;
+
+ // inner should only have been mounted once
+ expect(Inner2.prototype.componentWillMount, 'inner2 swap').to.have.been
+ .calledOnce;
+ expect(Inner2.prototype.componentDidMount, 'inner2 swap').to.have.been
+ .calledOnce;
+ expect(Inner2.prototype.componentWillUnmount, 'inner2 swap').not.to.have
+ .been.called;
+
+ inner2.forceUpdate();
+ rerender();
+
+ expect(Inner2.prototype.render, 'inner2 update').to.have.been.calledTwice;
+ expect(Inner2.prototype.componentWillMount, 'inner2 update').to.have.been
+ .calledOnce;
+ expect(Inner2.prototype.componentDidMount, 'inner2 update').to.have.been
+ .calledOnce;
+ expect(Inner2.prototype.componentWillUnmount, 'inner2 update').not.to.have
+ .been.called;
+ });
+
+ it('should remount when swapping between HOC child types', () => {
+ class Outer extends Component {
+ render({ child: Child }) {
+ return <Child />;
+ }
+ }
+
+ class Inner extends Component {
+ componentWillMount() {}
+ componentWillUnmount() {}
+ render() {
+ return <div class="inner">foo</div>;
+ }
+ }
+ sinon.spy(Inner.prototype, 'componentWillMount');
+ sinon.spy(Inner.prototype, 'componentWillUnmount');
+ sinon.spy(Inner.prototype, 'render');
+
+ const InnerFunc = () => <div class="inner-func">bar</div>;
+
+ render(<Outer child={Inner} />, scratch);
+
+ expect(Inner.prototype.componentWillMount, 'initial mount').to.have.been
+ .calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'initial mount').not.to.have
+ .been.called;
+
+ Inner.prototype.componentWillMount.resetHistory();
+ render(<Outer child={InnerFunc} />, scratch);
+
+ expect(Inner.prototype.componentWillMount, 'unmount').not.to.have.been
+ .called;
+ expect(Inner.prototype.componentWillUnmount, 'unmount').to.have.been
+ .calledOnce;
+
+ Inner.prototype.componentWillUnmount.resetHistory();
+ render(<Outer child={Inner} />, scratch);
+
+ expect(Inner.prototype.componentWillMount, 'remount').to.have.been
+ .calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'remount').not.to.have.been
+ .called;
+ });
+ });
+
+ describe('Component Nesting', () => {
+ let useIntermediary = false;
+
+ let createComponent = Intermediary => {
+ class C extends Component {
+ componentWillMount() {}
+ render({ children }) {
+ if (!useIntermediary) return children;
+ let I = useIntermediary === true ? Intermediary : useIntermediary;
+ return <I>{children}</I>;
+ }
+ }
+ sinon.spy(C.prototype, 'componentWillMount');
+ sinon.spy(C.prototype, 'render');
+ return C;
+ };
+
+ let createFunction = () => sinon.spy(({ children }) => children);
+
+ let F1 = createFunction();
+ let F2 = createFunction();
+ let F3 = createFunction();
+
+ let C1 = createComponent(F1);
+ let C2 = createComponent(F2);
+ let C3 = createComponent(F3);
+
+ let reset = () =>
+ [C1, C2, C3]
+ .reduce(
+ (acc, c) =>
+ acc.concat(c.prototype.render, c.prototype.componentWillMount),
+ [F1, F2, F3]
+ )
+ .forEach(c => c.resetHistory());
+
+ it('should handle lifecycle for no intermediary in component tree', () => {
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(C1.prototype.componentWillMount, 'initial mount').to.have.been
+ .calledOnce;
+ expect(C2.prototype.componentWillMount, 'initial mount').to.have.been
+ .calledOnce;
+ expect(C3.prototype.componentWillMount, 'initial mount').to.have.been
+ .calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>Some Text</C2>
+ </C1>,
+ scratch
+ );
+
+ expect(C1.prototype.componentWillMount, 'unmount innermost, C1').not.to
+ .have.been.called;
+ expect(C2.prototype.componentWillMount, 'unmount innermost, C2').not.to
+ .have.been.called;
+
+ reset();
+ render(
+ <C1>
+ <C3>Some Text</C3>
+ </C1>,
+ scratch
+ );
+
+ expect(C1.prototype.componentWillMount, 'swap innermost').not.to.have.been
+ .called;
+ expect(C3.prototype.componentWillMount, 'swap innermost').to.have.been
+ .calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(C1.prototype.componentWillMount, 'inject between, C1').not.to.have
+ .been.called;
+ expect(C2.prototype.componentWillMount, 'inject between, C2').to.have.been
+ .calledOnce;
+ expect(C3.prototype.componentWillMount, 'inject between, C3').to.have.been
+ .calledOnce;
+ });
+
+ it('should handle lifecycle for nested intermediary functional components', () => {
+ useIntermediary = true;
+
+ render(<div />, scratch);
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'initial mount w/ intermediary fn, C1'
+ ).to.have.been.calledOnce;
+ expect(
+ C2.prototype.componentWillMount,
+ 'initial mount w/ intermediary fn, C2'
+ ).to.have.been.calledOnce;
+ expect(
+ C3.prototype.componentWillMount,
+ 'initial mount w/ intermediary fn, C3'
+ ).to.have.been.calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>Some Text</C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'unmount innermost w/ intermediary fn, C1'
+ ).not.to.have.been.called;
+ expect(
+ C2.prototype.componentWillMount,
+ 'unmount innermost w/ intermediary fn, C2'
+ ).not.to.have.been.called;
+
+ reset();
+ render(
+ <C1>
+ <C3>Some Text</C3>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'swap innermost w/ intermediary fn'
+ ).not.to.have.been.called;
+ expect(
+ C3.prototype.componentWillMount,
+ 'swap innermost w/ intermediary fn'
+ ).to.have.been.calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'inject between, C1 w/ intermediary fn'
+ ).not.to.have.been.called;
+ expect(
+ C2.prototype.componentWillMount,
+ 'inject between, C2 w/ intermediary fn'
+ ).to.have.been.calledOnce;
+ expect(
+ C3.prototype.componentWillMount,
+ 'inject between, C3 w/ intermediary fn'
+ ).to.have.been.calledOnce;
+ });
+
+ it('should render components by depth', () => {
+ let spy = sinon.spy();
+ let update;
+ class Child extends Component {
+ constructor(props) {
+ super(props);
+ update = () => {
+ this.props.update();
+ this.setState({});
+ };
+ }
+
+ render() {
+ spy();
+ let items = [];
+ for (let i = 0; i < this.props.items; i++) items.push(i);
+ return <div>{items.join(',')}</div>;
+ }
+ }
+
+ let i = 0;
+ class Parent extends Component {
+ render() {
+ return <Child items={++i} update={() => this.setState({})} />;
+ }
+ }
+
+ render(<Parent />, scratch);
+ expect(spy).to.be.calledOnce;
+
+ update();
+ rerender();
+ expect(spy).to.be.calledTwice;
+ });
+
+ it('should handle lifecycle for nested intermediary elements', () => {
+ useIntermediary = 'div';
+
+ render(<div />, scratch);
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'initial mount w/ intermediary div, C1'
+ ).to.have.been.calledOnce;
+ expect(
+ C2.prototype.componentWillMount,
+ 'initial mount w/ intermediary div, C2'
+ ).to.have.been.calledOnce;
+ expect(
+ C3.prototype.componentWillMount,
+ 'initial mount w/ intermediary div, C3'
+ ).to.have.been.calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>Some Text</C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'unmount innermost w/ intermediary div, C1'
+ ).not.to.have.been.called;
+ expect(
+ C2.prototype.componentWillMount,
+ 'unmount innermost w/ intermediary div, C2'
+ ).not.to.have.been.called;
+
+ reset();
+ render(
+ <C1>
+ <C3>Some Text</C3>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'swap innermost w/ intermediary div'
+ ).not.to.have.been.called;
+ expect(
+ C3.prototype.componentWillMount,
+ 'swap innermost w/ intermediary div'
+ ).to.have.been.calledOnce;
+
+ reset();
+ render(
+ <C1>
+ <C2>
+ <C3>Some Text</C3>
+ </C2>
+ </C1>,
+ scratch
+ );
+
+ expect(
+ C1.prototype.componentWillMount,
+ 'inject between, C1 w/ intermediary div'
+ ).not.to.have.been.called;
+ expect(
+ C2.prototype.componentWillMount,
+ 'inject between, C2 w/ intermediary div'
+ ).to.have.been.calledOnce;
+ expect(
+ C3.prototype.componentWillMount,
+ 'inject between, C3 w/ intermediary div'
+ ).to.have.been.calledOnce;
+ });
+ });
+
+ it('should set component._vnode._dom when sCU returns false', () => {
+ let parent;
+ class Parent extends Component {
+ render() {
+ parent = this;
+ return <Child />;
+ }
+ }
+
+ let renderChildDiv = false;
+
+ let child;
+ class Child extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ child = this;
+ if (!renderChildDiv) return null;
+ return <div class="child" />;
+ }
+ }
+
+ let app;
+ class App extends Component {
+ render() {
+ app = this;
+ return <Parent />;
+ }
+ }
+
+ // TODO: Consider rewriting test to not rely on internal properties
+ // and instead capture user-facing bug that would occur if this
+ // behavior were broken
+ const getDom = c => ('__v' in c ? c.__v.__e : c._vnode._dom);
+
+ render(<App />, scratch);
+ expect(getDom(child)).to.equalNode(child.base);
+
+ app.forceUpdate();
+ expect(getDom(child)).to.equalNode(child.base);
+
+ parent.setState({});
+ renderChildDiv = true;
+ child.forceUpdate();
+ expect(getDom(child)).to.equalNode(child.base);
+ rerender();
+
+ expect(getDom(child)).to.equalNode(child.base);
+
+ renderChildDiv = false;
+ app.setState({});
+ child.forceUpdate();
+ rerender();
+ expect(getDom(child)).to.equalNode(child.base);
+ });
+
+ // preact/#1323
+ it('should handle hoisted component vnodes without DOM', () => {
+ let x = 0;
+ let mounted = '';
+ let unmounted = '';
+ let updateAppState;
+
+ class X extends Component {
+ constructor(props) {
+ super(props);
+ this.name = `${x++}`;
+ }
+
+ componentDidMount() {
+ mounted += `,${this.name}`;
+ }
+
+ componentWillUnmount() {
+ unmounted += `,${this.name}`;
+ }
+
+ render() {
+ return null;
+ }
+ }
+
+ // Statically create X element
+ const A = <X />;
+
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { i: 0 };
+ updateAppState = () => this.setState({ i: this.state.i + 1 });
+ }
+
+ render() {
+ return (
+ <div key={this.state.i}>
+ {A}
+ {A}
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+
+ updateAppState();
+ rerender();
+ updateAppState();
+ rerender();
+
+ expect(mounted).to.equal(',0,1,2,3,4,5');
+ expect(unmounted).to.equal(',0,1,2,3');
+ });
+
+ describe('c.base', () => {
+ /* eslint-disable lines-around-comment */
+ /** @type {import('../../src').Component} */
+ let parentDom1;
+ /** @type {import('../../src').Component} */
+ let parent1;
+ /** @type {import('../../src').Component} */
+ let parent2;
+ /** @type {import('../../src').Component} */
+ let maybe;
+ /** @type {import('../../src').Component} */
+ let child;
+ /** @type {import('../../src').Component} */
+ let sibling;
+ /** @type {import('../../src').Component} */
+ let nullInst;
+
+ /** @type {() => void} */
+ let toggleMaybeNull;
+ /** @type {() => void} */
+ let swapChildTag;
+
+ function ParentWithDom(props) {
+ parentDom1 = this;
+ return <div>{props.children}</div>;
+ }
+
+ class Parent1 extends Component {
+ render() {
+ parent1 = this;
+ return this.props.children;
+ }
+ }
+
+ function Parent2(props) {
+ parent2 = this;
+ return props.children;
+ }
+
+ class MaybeNull extends Component {
+ constructor(props) {
+ super(props);
+ maybe = this;
+ this.state = { active: props.active || false };
+ toggleMaybeNull = () =>
+ this.setState(prev => ({
+ active: !prev.active
+ }));
+ }
+ render() {
+ return this.state.active ? <div>maybe</div> : null;
+ }
+ }
+
+ class Child extends Component {
+ constructor(props) {
+ super(props);
+ child = this;
+ this.state = { tagName: 'p' };
+ swapChildTag = () =>
+ this.setState(prev => ({
+ tagName: prev.tagName == 'p' ? 'span' : 'p'
+ }));
+ }
+ render() {
+ return h(this.state.tagName, null, 'child');
+ }
+ }
+
+ function Sibling(props) {
+ sibling = this;
+ return <p />;
+ }
+
+ function Null() {
+ nullInst = this;
+ return null;
+ }
+
+ afterEach(() => {
+ parentDom1 = null;
+ parent1 = null;
+ parent2 = null;
+ child = null;
+ sibling = null;
+ });
+
+ it('should keep c.base up to date if a nested child component changes DOM nodes', () => {
+ render(
+ <ParentWithDom>
+ <Parent1>
+ <Parent2>
+ <Child />
+ </Parent2>
+ </Parent1>
+ </ParentWithDom>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<div><p>child</p></div>');
+ expect(child.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(parent1.base).to.equalNode(child.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div><span>child</span></div>');
+ expect(child.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(parent1.base).to.equalNode(child.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+ });
+
+ it('should not update sibling c.base if child component changes DOM nodes', () => {
+ let s1 = {},
+ s2 = {},
+ s3 = {},
+ s4 = {};
+
+ render(
+ <Fragment>
+ <ParentWithDom>
+ <Parent1>
+ <Parent2>
+ <Child />
+ <Sibling ref={s1} />
+ </Parent2>
+ <Sibling ref={s2} />
+ </Parent1>
+ <Sibling ref={s3} />
+ </ParentWithDom>
+ <Sibling ref={s4} />
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><p>child</p><p></p><p></p><p></p></div><p></p>'
+ );
+ expect(child.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(parent1.base).to.equalNode(child.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+ expect(s1.current.base).to.equalNode(scratch.firstChild.childNodes[1]);
+ expect(s2.current.base).to.equalNode(scratch.firstChild.childNodes[2]);
+ expect(s3.current.base).to.equalNode(scratch.firstChild.childNodes[3]);
+ expect(s4.current.base).to.equalNode(scratch.lastChild);
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><span>child</span><p></p><p></p><p></p></div><p></p>'
+ );
+ expect(child.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(parent1.base).to.equalNode(child.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+ expect(s1.current.base).to.equalNode(scratch.firstChild.childNodes[1]);
+ expect(s2.current.base).to.equalNode(scratch.firstChild.childNodes[2]);
+ expect(s3.current.base).to.equalNode(scratch.firstChild.childNodes[3]);
+ expect(s4.current.base).to.equalNode(scratch.lastChild);
+ });
+
+ it('should not update parent c.base if child component changes DOM nodes and it is not first child component', () => {
+ render(
+ <Parent1>
+ <Sibling />
+ <Child />
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<p></p><p>child</p>');
+ expect(child.base).to.equalNode(scratch.lastChild);
+ expect(sibling.base).to.equalNode(scratch.firstChild);
+ expect(parent1.base).to.equalNode(sibling.base);
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<p></p><span>child</span>');
+ expect(child.base).to.equalNode(scratch.lastChild);
+ expect(sibling.base).to.equalNode(scratch.firstChild);
+ expect(parent1.base).to.equalNode(sibling.base);
+ });
+
+ it('should update parent c.base if child component changes DOM nodes and it is first non-null child component', () => {
+ render(
+ <Parent1>
+ <Null />
+ <Child />
+ <Sibling />
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<p>child</p><p></p>');
+ expect(nullInst.base).to.equalNode(null);
+ expect(child.base).to.equalNode(scratch.firstChild);
+ expect(sibling.base).to.equalNode(scratch.lastChild);
+ expect(parent1.base).to.equalNode(child.base);
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<span>child</span><p></p>');
+ expect(nullInst.base).to.equalNode(null);
+ expect(child.base).to.equalNode(scratch.firstChild);
+ expect(sibling.base).to.equalNode(scratch.lastChild);
+ expect(parent1.base).to.equalNode(child.base);
+ });
+
+ it('should not update parent c.base if child component changes DOM nodes and a parent is not first child component', () => {
+ render(
+ <ParentWithDom>
+ <Parent1>
+ <Sibling />
+ <Parent2>
+ <Child />
+ </Parent2>
+ </Parent1>
+ </ParentWithDom>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<div><p></p><p>child</p></div>');
+ expect(child.base).to.equalNode(scratch.firstChild.lastChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(sibling.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent1.base).to.equalNode(sibling.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><p></p><span>child</span></div>'
+ );
+ expect(child.base).to.equalNode(scratch.firstChild.lastChild);
+ expect(parent2.base).to.equalNode(child.base);
+ expect(sibling.base).to.equalNode(scratch.firstChild.firstChild);
+ expect(parent1.base).to.equalNode(sibling.base);
+ expect(parentDom1.base).to.equalNode(scratch.firstChild);
+ });
+
+ it('should update parent c.base if first child becomes null', () => {
+ render(
+ <Parent1>
+ <MaybeNull active />
+ <Parent2>
+ <Child />
+ </Parent2>
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal([div('maybe'), p('child')].join(''));
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(child.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(maybe.base, 'initial - parent1.base');
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'toggleMaybe - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - parent1.base'
+ );
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(span('child'));
+ expect(maybe.base).to.equalNode(null, 'swapChildTag - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'swapChildTag - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent1.base'
+ );
+ });
+
+ it('should update parent c.base if first child becomes non-null', () => {
+ render(
+ <Parent1>
+ <MaybeNull />
+ <Parent2>
+ <Child />
+ </Parent2>
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'initial - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(child.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(child.base, 'initial - parent1.base');
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(span('child'));
+ expect(maybe.base).to.equalNode(null, 'swapChildTag - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'swapChildTag - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent1.base'
+ );
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ [div('maybe'), span('child')].join('')
+ );
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent1.base'
+ );
+ });
+
+ it('should update parent c.base if first non-null child becomes null with multiple null siblings', () => {
+ render(
+ <Parent1>
+ <Null />
+ <Null />
+ <Parent2>
+ <MaybeNull active />
+ <Child />
+ </Parent2>
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal([div('maybe'), p('child')].join(''));
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(maybe.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(maybe.base, 'initial - parent1.base');
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'toggleMaybe - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - parent1.base'
+ );
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(span('child'));
+ expect(maybe.base).to.equalNode(null, 'swapChildTag - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'swapChildTag - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent1.base'
+ );
+ });
+
+ it('should update parent c.base if a null child returns DOM with multiple null siblings', () => {
+ render(
+ <Parent1>
+ <Null />
+ <Null />
+ <Parent2>
+ <MaybeNull />
+ <Child />
+ </Parent2>
+ </Parent1>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'initial - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(child.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(child.base, 'initial - parent1.base');
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(span('child'));
+ expect(maybe.base).to.equalNode(null, 'swapChildTag - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'swapChildTag - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ child.base,
+ 'swapChildTag - parent1.base'
+ );
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ [div('maybe'), span('child')].join('')
+ );
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent1.base'
+ );
+ });
+
+ it('should update parent c.base to null if last child becomes null', () => {
+ let fragRef = {};
+ render(
+ <Fragment ref={fragRef}>
+ <Parent1>
+ <Null />
+ <Null />
+ <Parent2>
+ <MaybeNull active />
+ </Parent2>
+ <Null />
+ </Parent1>
+ <Child />
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal([div('maybe'), p('child')].join(''));
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(maybe.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(maybe.base, 'initial - parent1.base');
+ expect(fragRef.current.base).to.equalNode(
+ maybe.base,
+ 'initial - fragRef.current.base'
+ );
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'toggleMaybe - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent2.base'
+ );
+ expect(parent1.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent1.base'
+ );
+ expect(fragRef.current.base).to.equalNode(
+ child.base,
+ 'toggleMaybe - fragRef.current.base'
+ );
+ });
+
+ it('should update parent c.base if last child returns dom', () => {
+ let fragRef = {};
+ render(
+ <Fragment ref={fragRef}>
+ <Parent1>
+ <Null />
+ <Null />
+ <Parent2>
+ <MaybeNull />
+ </Parent2>
+ <Null />
+ </Parent1>
+ <Child />
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(p('child'));
+ expect(maybe.base).to.equalNode(null, 'initial - maybe.base');
+ expect(child.base).to.equalNode(
+ scratch.firstChild,
+ 'initial - child.base'
+ );
+ expect(parent2.base).to.equalNode(maybe.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(maybe.base, 'initial - parent1.base');
+ expect(fragRef.current.base).to.equalNode(
+ child.base,
+ 'initial - fragRef.current.base'
+ );
+
+ toggleMaybeNull();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal([div('maybe'), p('child')].join(''));
+ expect(maybe.base).to.equalNode(
+ scratch.firstChild,
+ 'toggleMaybe - maybe.base'
+ );
+ expect(child.base).to.equalNode(
+ scratch.lastChild,
+ 'toggleMaybe - child.base'
+ );
+ expect(parent2.base).to.equalNode(maybe.base, 'initial - parent2.base');
+ expect(parent1.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - parent1.base'
+ );
+ expect(fragRef.current.base).to.equalNode(
+ maybe.base,
+ 'toggleMaybe - fragRef.current.base'
+ );
+ });
+
+ it('should not update parent if it is a DOM node', () => {
+ let divVNode = (
+ <div>
+ <Child />
+ </div>
+ );
+ render(divVNode, scratch);
+
+ // TODO: Consider rewriting test to not rely on internal properties
+ // and instead capture user-facing bug that would occur if this
+ // behavior were broken
+ const domProp = '__e' in divVNode ? '__e' : '_dom';
+
+ expect(scratch.innerHTML).to.equal('<div><p>child</p></div>');
+ expect(divVNode[domProp]).to.equalNode(
+ scratch.firstChild,
+ 'initial - divVNode._dom'
+ );
+ expect(child.base).to.equalNode(
+ scratch.firstChild.firstChild,
+ 'initial - child.base'
+ );
+
+ swapChildTag();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div><span>child</span></div>');
+ expect(divVNode[domProp]).to.equalNode(
+ scratch.firstChild,
+ 'swapChildTag - divVNode._dom'
+ );
+ expect(child.base).to.equalNode(
+ scratch.firstChild.firstChild,
+ 'swapChildTag - child.base'
+ );
+ });
+ });
+
+ describe('setState', () => {
+ it('should not error if called on an unmounted component', () => {
+ /** @type {() => void} */
+ let increment;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { count: 0 };
+ increment = () => this.setState({ count: this.state.count + 1 });
+ }
+ render(props, state) {
+ return <div>{state.count}</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>0</div>');
+
+ increment();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+
+ render(null, scratch);
+ expect(scratch.innerHTML).to.equal('');
+
+ expect(() => increment()).to.not.throw();
+ expect(() => rerender()).to.not.throw();
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('setState callbacks should have latest state, even when called in render', () => {
+ let callbackState;
+ let i = 0;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { foo: 'bar' };
+ }
+ render() {
+ // So we don't get infinite loop
+ if (i++ === 0) {
+ this.setState({ foo: 'baz' }, () => {
+ callbackState = this.state;
+ });
+ }
+ return String(this.state.foo);
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal('bar');
+
+ rerender();
+ expect(scratch.innerHTML).to.equal('baz');
+ expect(callbackState).to.deep.equal({ foo: 'baz' });
+ });
+
+ // #2716
+ it('should work with readonly state', () => {
+ let update;
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { foo: 'bar' };
+ update = () =>
+ this.setState(prev => {
+ Object.defineProperty(prev, 'foo', {
+ writable: false
+ });
+
+ return prev;
+ });
+ }
+
+ render() {
+ return <div />;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(() => {
+ update();
+ rerender();
+ }).to.not.throw();
+ });
+ });
+
+ describe('forceUpdate', () => {
+ it('should not error if called on an unmounted component', () => {
+ /** @type {() => void} */
+ let forceUpdate;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ forceUpdate = () => this.forceUpdate();
+ }
+ render(props, state) {
+ return <div>Hello</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(null, scratch);
+ expect(scratch.innerHTML).to.equal('');
+
+ expect(() => forceUpdate()).to.not.throw();
+ expect(() => rerender()).to.not.throw();
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should update old dom on forceUpdate in a lifecycle', () => {
+ let i = 0;
+ class App extends Component {
+ componentWillReceiveProps() {
+ this.forceUpdate();
+ }
+ render() {
+ if (i++ == 0) return <div>foo</div>;
+ return <div>bar</div>;
+ }
+ }
+
+ render(<App />, scratch);
+ render(<App />, scratch);
+
+ expect(scratch.innerHTML).to.equal('<div>bar</div>');
+ });
+ });
+});
diff --git a/preact/test/browser/context.test.js b/preact/test/browser/context.test.js
new file mode 100644
index 0000000..ce3a57a
--- /dev/null
+++ b/preact/test/browser/context.test.js
@@ -0,0 +1,237 @@
+import { createElement, render, Component, Fragment } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('context', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should pass context to grandchildren', () => {
+ const CONTEXT = { a: 'a' };
+ const PROPS = { b: 'b' };
+ // let inner;
+
+ class Outer extends Component {
+ getChildContext() {
+ return CONTEXT;
+ }
+ render(props) {
+ return (
+ <div>
+ <Inner {...props} />
+ </div>
+ );
+ }
+ }
+ sinon.spy(Outer.prototype, 'getChildContext');
+
+ class Inner extends Component {
+ // constructor() {
+ // super();
+ // inner = this;
+ // }
+ shouldComponentUpdate() {
+ return true;
+ }
+ componentWillReceiveProps() {}
+ componentWillUpdate() {}
+ componentDidUpdate() {}
+ render(props, state, context) {
+ return <div>{context && context.a}</div>;
+ }
+ }
+ sinon.spy(Inner.prototype, 'shouldComponentUpdate');
+ sinon.spy(Inner.prototype, 'componentWillReceiveProps');
+ sinon.spy(Inner.prototype, 'componentWillUpdate');
+ sinon.spy(Inner.prototype, 'componentDidUpdate');
+ sinon.spy(Inner.prototype, 'render');
+
+ render(<Outer />, scratch);
+
+ expect(Outer.prototype.getChildContext).to.have.been.calledOnce;
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWith({}, {}, CONTEXT);
+
+ CONTEXT.foo = 'bar';
+ render(<Outer {...PROPS} />, scratch);
+
+ expect(Outer.prototype.getChildContext).to.have.been.calledTwice;
+
+ expect(
+ Inner.prototype.shouldComponentUpdate
+ ).to.have.been.calledOnce.and.calledWith(PROPS, {}, CONTEXT);
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(
+ PROPS,
+ CONTEXT
+ );
+ expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(
+ PROPS,
+ {},
+ CONTEXT
+ );
+ expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith(
+ {},
+ {},
+ undefined
+ );
+ expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, CONTEXT);
+
+ /* Future:
+ * Newly created context objects are *not* currently cloned.
+ * This test checks that they *are* cloned.
+ */
+ // Inner.prototype.render.resetHistory();
+ // CONTEXT.foo = 'baz';
+ // inner.forceUpdate();
+ // expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, { a:'a', foo:'bar' });
+ });
+
+ it('should pass context to direct children', () => {
+ const CONTEXT = { a: 'a' };
+ const PROPS = { b: 'b' };
+
+ class Outer extends Component {
+ getChildContext() {
+ return CONTEXT;
+ }
+ render(props) {
+ return <Inner {...props} />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'getChildContext');
+
+ class Inner extends Component {
+ shouldComponentUpdate() {
+ return true;
+ }
+ componentWillReceiveProps() {}
+ componentWillUpdate() {}
+ componentDidUpdate() {}
+ render(props, state, context) {
+ return <div>{context && context.a}</div>;
+ }
+ }
+ sinon.spy(Inner.prototype, 'shouldComponentUpdate');
+ sinon.spy(Inner.prototype, 'componentWillReceiveProps');
+ sinon.spy(Inner.prototype, 'componentWillUpdate');
+ sinon.spy(Inner.prototype, 'componentDidUpdate');
+ sinon.spy(Inner.prototype, 'render');
+
+ render(<Outer />, scratch);
+
+ expect(Outer.prototype.getChildContext).to.have.been.calledOnce;
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWith({}, {}, CONTEXT);
+
+ CONTEXT.foo = 'bar';
+ render(<Outer {...PROPS} />, scratch);
+
+ expect(Outer.prototype.getChildContext).to.have.been.calledTwice;
+
+ expect(
+ Inner.prototype.shouldComponentUpdate
+ ).to.have.been.calledOnce.and.calledWith(PROPS, {}, CONTEXT);
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.calledWith(
+ PROPS,
+ CONTEXT
+ );
+ expect(Inner.prototype.componentWillUpdate).to.have.been.calledWith(
+ PROPS,
+ {},
+ CONTEXT
+ );
+ expect(Inner.prototype.componentDidUpdate).to.have.been.calledWith(
+ {},
+ {},
+ undefined
+ );
+ expect(Inner.prototype.render).to.have.been.calledWith(PROPS, {}, CONTEXT);
+
+ // make sure render() could make use of context.a
+ expect(Inner.prototype.render).to.have.returned(
+ sinon.match({ props: { children: 'a' } })
+ );
+ });
+
+ it('should preserve existing context properties when creating child contexts', () => {
+ let outerContext = { outer: true },
+ innerContext = { inner: true };
+ class Outer extends Component {
+ getChildContext() {
+ return { outerContext };
+ }
+ render() {
+ return (
+ <div>
+ <Inner />
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ getChildContext() {
+ return { innerContext };
+ }
+ render() {
+ return <InnerMost />;
+ }
+ }
+
+ class InnerMost extends Component {
+ render() {
+ return <strong>test</strong>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+ sinon.spy(InnerMost.prototype, 'render');
+
+ render(<Outer />, scratch);
+
+ expect(Inner.prototype.render).to.have.been.calledWith(
+ {},
+ {},
+ { outerContext }
+ );
+ expect(InnerMost.prototype.render).to.have.been.calledWith(
+ {},
+ {},
+ { outerContext, innerContext }
+ );
+ });
+
+ it('should pass context through Fragments', () => {
+ const context = { foo: 'bar' };
+
+ const Foo = sinon.spy(() => <div />);
+
+ class Wrapper extends Component {
+ getChildContext() {
+ return context;
+ }
+
+ render() {
+ return (
+ <Fragment>
+ <Foo />
+ <Foo />
+ </Fragment>
+ );
+ }
+ }
+
+ render(<Wrapper />, scratch);
+ expect(Foo.args[0][1]).to.deep.equal(context);
+ });
+});
diff --git a/preact/test/browser/createContext.test.js b/preact/test/browser/createContext.test.js
new file mode 100644
index 0000000..092a2ba
--- /dev/null
+++ b/preact/test/browser/createContext.test.js
@@ -0,0 +1,931 @@
+import { setupRerender, act } from 'preact/test-utils';
+import {
+ createElement,
+ render,
+ Component,
+ createContext,
+ Fragment
+} from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('createContext', () => {
+ let scratch;
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should pass context to a consumer', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+
+ let receivedContext;
+
+ class Inner extends Component {
+ render(props) {
+ return <div>{props.a}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <Provider value={CONTEXT}>
+ <div>
+ <Consumer>
+ {data => {
+ receivedContext = data;
+ return <Inner {...data} />;
+ }}
+ </Consumer>
+ </div>
+ </Provider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWithMatch(CONTEXT);
+ expect(receivedContext).to.equal(CONTEXT);
+ expect(scratch.innerHTML).to.equal('<div><div>a</div></div>');
+ });
+
+ // This optimization helps
+ // to prevent a Provider from rerendering the children, this means
+ // we only propagate to children.
+ // Strict equal vnode optimization
+ it('skips referentially equal children to Provider', () => {
+ const { Provider, Consumer } = createContext();
+ let set,
+ renders = 0;
+ const Layout = ({ children }) => {
+ renders++;
+ return children;
+ };
+ class State extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { i: 0 };
+ set = this.setState.bind(this);
+ }
+ render() {
+ const { children } = this.props;
+ return <Provider value={this.state}>{children}</Provider>;
+ }
+ }
+ const App = () => (
+ <State>
+ <Layout>
+ <Consumer>{({ i }) => <p>{i}</p>}</Consumer>
+ </Layout>
+ </State>
+ );
+ render(<App />, scratch);
+ expect(renders).to.equal(1);
+ set({ i: 2 });
+ rerender();
+ expect(renders).to.equal(1);
+ });
+
+ it('should preserve provider context through nesting providers', done => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+ const CHILD_CONTEXT = { b: 'b' };
+
+ let parentContext, childContext;
+
+ class Inner extends Component {
+ render(props) {
+ return (
+ <div>
+ {props.a} - {props.b}
+ </div>
+ );
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <Provider value={CONTEXT}>
+ <Consumer>
+ {data => {
+ parentContext = data;
+ return (
+ <Provider value={CHILD_CONTEXT}>
+ <Consumer>
+ {childData => {
+ childContext = childData;
+ return <Inner {...data} {...childData} />;
+ }}
+ </Consumer>
+ </Provider>
+ );
+ }}
+ </Consumer>
+ </Provider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWithMatch({
+ ...CONTEXT,
+ ...CHILD_CONTEXT
+ });
+ expect(Inner.prototype.render).to.be.calledOnce;
+ expect(parentContext).to.equal(CONTEXT);
+ expect(childContext).to.equal(CHILD_CONTEXT);
+ expect(scratch.innerHTML).to.equal('<div>a - b</div>');
+ setTimeout(() => {
+ expect(Inner.prototype.render).to.be.calledOnce;
+ done();
+ }, 0);
+ });
+
+ it('should preserve provider context between different providers', () => {
+ const {
+ Provider: ThemeProvider,
+ Consumer: ThemeConsumer
+ } = createContext();
+ const { Provider: DataProvider, Consumer: DataConsumer } = createContext();
+ const THEME_CONTEXT = { theme: 'black' };
+ const DATA_CONTEXT = { global: 'a' };
+
+ let receivedTheme;
+ let receivedData;
+
+ class Inner extends Component {
+ render(props) {
+ return (
+ <div>
+ {props.theme} - {props.global}
+ </div>
+ );
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <ThemeProvider value={THEME_CONTEXT.theme}>
+ <DataProvider value={DATA_CONTEXT}>
+ <ThemeConsumer>
+ {theme => {
+ receivedTheme = theme;
+ return (
+ <DataConsumer>
+ {data => {
+ receivedData = data;
+ return <Inner theme={theme} {...data} />;
+ }}
+ </DataConsumer>
+ );
+ }}
+ </ThemeConsumer>
+ </DataProvider>
+ </ThemeProvider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWithMatch({
+ ...THEME_CONTEXT,
+ ...DATA_CONTEXT
+ });
+ expect(receivedTheme).to.equal(THEME_CONTEXT.theme);
+ expect(receivedData).to.equal(DATA_CONTEXT);
+ expect(scratch.innerHTML).to.equal('<div>black - a</div>');
+ });
+
+ it('should preserve provider context through nesting consumers', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+
+ let receivedData;
+ let receivedChildData;
+
+ class Inner extends Component {
+ render(props) {
+ return <div>{props.a}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <Provider value={CONTEXT}>
+ <Consumer>
+ {data => {
+ receivedData = data;
+ return (
+ <Consumer>
+ {childData => {
+ receivedChildData = childData;
+ return <Inner {...data} {...childData} />;
+ }}
+ </Consumer>
+ );
+ }}
+ </Consumer>
+ </Provider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT });
+ expect(receivedData).to.equal(CONTEXT);
+ expect(receivedChildData).to.equal(CONTEXT);
+ expect(scratch.innerHTML).to.equal('<div>a</div>');
+ });
+
+ it('should not emit when value does not update', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+
+ class NoUpdate extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return this.props.children;
+ }
+ }
+
+ class Inner extends Component {
+ render(props) {
+ return <div>{props.a}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <div>
+ <Provider value={CONTEXT}>
+ <NoUpdate>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </NoUpdate>
+ </Provider>
+ </div>,
+ scratch
+ );
+
+ expect(Inner.prototype.render).to.have.been.calledOnce;
+
+ render(
+ <div>
+ <Provider value={CONTEXT}>
+ <NoUpdate>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </NoUpdate>
+ </Provider>
+ </div>,
+ scratch
+ );
+
+ expect(Inner.prototype.render).to.have.been.calledOnce;
+ });
+
+ it('should preserve provider context through nested components', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+
+ let receivedContext;
+
+ class Consumed extends Component {
+ render(props) {
+ return <strong>{props.a}</strong>;
+ }
+ }
+
+ sinon.spy(Consumed.prototype, 'render');
+
+ class Outer extends Component {
+ render() {
+ return (
+ <div>
+ <Inner />
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ render() {
+ return (
+ <Fragment>
+ <InnerMost />
+ </Fragment>
+ );
+ }
+ }
+
+ class InnerMost extends Component {
+ render() {
+ return (
+ <div>
+ <Consumer>
+ {data => {
+ receivedContext = data;
+ return <Consumed {...data} />;
+ }}
+ </Consumer>
+ </div>
+ );
+ }
+ }
+
+ render(
+ <Provider value={CONTEXT}>
+ <Outer />
+ </Provider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Consumed.prototype.render).to.have.been.calledWithMatch({
+ ...CONTEXT
+ });
+ expect(receivedContext).to.equal(CONTEXT);
+ expect(scratch.innerHTML).to.equal(
+ '<div><div><strong>a</strong></div></div>'
+ );
+ });
+
+ it('should propagates through shouldComponentUpdate false', done => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { a: 'a' };
+ const UPDATED_CONTEXT = { a: 'b' };
+
+ class Consumed extends Component {
+ render(props) {
+ return <strong>{props.a}</strong>;
+ }
+ }
+
+ sinon.spy(Consumed.prototype, 'render');
+
+ class Outer extends Component {
+ render() {
+ return (
+ <div>
+ <Inner />
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return (
+ <Fragment>
+ <InnerMost />
+ </Fragment>
+ );
+ }
+ }
+
+ class InnerMost extends Component {
+ render() {
+ return (
+ <div>
+ <Consumer>{data => <Consumed {...data} />}</Consumer>
+ </div>
+ );
+ }
+ }
+
+ class App extends Component {
+ render() {
+ return (
+ <Provider value={this.props.value}>
+ <Outer />
+ </Provider>
+ );
+ }
+ }
+
+ render(<App value={CONTEXT} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div><div><strong>a</strong></div></div>'
+ );
+ expect(Consumed.prototype.render).to.have.been.calledOnce;
+
+ render(<App value={UPDATED_CONTEXT} />, scratch);
+
+ rerender();
+
+ // initial render does not invoke anything but render():
+ expect(Consumed.prototype.render).to.have.been.calledTwice;
+ // expect(Consumed.prototype.render).to.have.been.calledWithMatch({ ...UPDATED_CONTEXT }, {}, { ['__cC' + (ctxId - 1)]: {} });
+ expect(scratch.innerHTML).to.equal(
+ '<div><div><strong>b</strong></div></div>'
+ );
+ setTimeout(() => {
+ expect(Consumed.prototype.render).to.have.been.calledTwice;
+ done();
+ });
+ });
+
+ it('should keep the right context at the right "depth"', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { theme: 'a', global: 1 };
+ const NESTED_CONTEXT = { theme: 'b', global: 1 };
+
+ let receivedData;
+ let receivedNestedData;
+
+ class Inner extends Component {
+ render(props) {
+ return (
+ <div>
+ {props.theme} - {props.global}
+ </div>
+ );
+ }
+ }
+ class Nested extends Component {
+ render(props) {
+ return (
+ <div>
+ {props.theme} - {props.global}
+ </div>
+ );
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+ sinon.spy(Nested.prototype, 'render');
+
+ render(
+ <Provider value={CONTEXT}>
+ <Provider value={NESTED_CONTEXT}>
+ <Consumer>
+ {data => {
+ receivedNestedData = data;
+ return <Nested {...data} />;
+ }}
+ </Consumer>
+ </Provider>
+ <Consumer>
+ {data => {
+ receivedData = data;
+ return <Inner {...data} />;
+ }}
+ </Consumer>
+ </Provider>,
+ scratch
+ );
+
+ // initial render does not invoke anything but render():
+ expect(Nested.prototype.render).to.have.been.calledWithMatch({
+ ...NESTED_CONTEXT
+ });
+ expect(Inner.prototype.render).to.have.been.calledWithMatch({ ...CONTEXT });
+ expect(receivedData).to.equal(CONTEXT);
+ expect(receivedNestedData).to.equal(NESTED_CONTEXT);
+
+ expect(scratch.innerHTML).to.equal('<div>b - 1</div><div>a - 1</div>');
+ });
+
+ it("should not re-render the consumer if the context doesn't change", () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { i: 1 };
+
+ class NoUpdate extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return this.props.children;
+ }
+ }
+
+ class Inner extends Component {
+ render(props) {
+ return <div>{props.i}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ render(
+ <Provider value={CONTEXT}>
+ <NoUpdate>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </NoUpdate>
+ </Provider>,
+ scratch
+ );
+
+ render(
+ <Provider value={CONTEXT}>
+ <NoUpdate>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </NoUpdate>
+ </Provider>,
+ scratch
+ );
+
+ // Rendered twice, should called just one 'Consumer' render
+ expect(Inner.prototype.render).to.have.been.calledOnce.and.calledWithMatch(
+ CONTEXT
+ );
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+
+ act(() => {
+ render(
+ <Provider value={{ i: 2 }}>
+ <NoUpdate>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </NoUpdate>
+ </Provider>,
+ scratch
+ );
+ });
+
+ // Rendered three times, should call 'Consumer' render two times
+ expect(
+ Inner.prototype.render
+ ).to.have.been.calledTwice.and.calledWithMatch({ i: 2 });
+ expect(scratch.innerHTML).to.equal('<div>2</div>');
+ });
+
+ it('should allow for updates of props', () => {
+ let app;
+ const { Provider, Consumer } = createContext();
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ status: 'initial'
+ };
+
+ this.renderInner = this.renderInner.bind(this);
+
+ app = this;
+ }
+
+ renderInner(value) {
+ return (
+ <p>
+ {value}: {this.state.status}
+ </p>
+ );
+ }
+
+ render() {
+ return (
+ <Provider value="value">
+ <Consumer>{this.renderInner}</Consumer>
+ </Provider>
+ );
+ }
+ }
+
+ act(() => {
+ render(<App />, scratch);
+ });
+
+ expect(scratch.innerHTML).to.equal('<p>value: initial</p>');
+
+ act(() => {
+ app.setState({ status: 'updated' });
+ rerender();
+ });
+
+ expect(scratch.innerHTML).to.equal('<p>value: updated</p>');
+ });
+
+ it('should re-render the consumer if the children change', () => {
+ const { Provider, Consumer } = createContext();
+ const CONTEXT = { i: 1 };
+
+ class Inner extends Component {
+ render(props) {
+ return <div>{props.i}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'render');
+
+ act(() => {
+ render(
+ <Provider value={CONTEXT}>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </Provider>,
+ scratch
+ );
+
+ // Not calling re-render since it's gonna get called with the same Consumer function
+ render(
+ <Provider value={CONTEXT}>
+ <Consumer>{data => <Inner {...data} />}</Consumer>
+ </Provider>,
+ scratch
+ );
+ });
+
+ // Rendered twice, with two different children for consumer, should render twice
+ expect(Inner.prototype.render).to.have.been.calledTwice;
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+ });
+
+ it('should not rerender consumers that have been unmounted', () => {
+ const { Provider, Consumer } = createContext(0);
+
+ const Inner = sinon.spy(props => <div>{props.value}</div>);
+
+ let toggleConsumer;
+ let changeValue;
+ class App extends Component {
+ constructor() {
+ super();
+
+ this.state = { value: 0, show: true };
+ changeValue = value => this.setState({ value });
+ toggleConsumer = () => this.setState(({ show }) => ({ show: !show }));
+ }
+ render(props, state) {
+ return (
+ <Provider value={state.value}>
+ <div>
+ {state.show ? (
+ <Consumer>{data => <Inner value={data} />}</Consumer>
+ ) : null}
+ </div>
+ </Provider>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><div>0</div></div>');
+ expect(Inner).to.have.been.calledOnce;
+
+ changeValue(1);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div><div>1</div></div>');
+ expect(Inner).to.have.been.calledTwice;
+
+ toggleConsumer();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ expect(Inner).to.have.been.calledTwice;
+
+ changeValue(2);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ expect(Inner).to.have.been.calledTwice;
+ });
+
+ describe('class.contextType', () => {
+ it('should use default value', () => {
+ const ctx = createContext('foo');
+
+ let actual;
+ class App extends Component {
+ render() {
+ actual = this.context;
+ return <div>bar</div>;
+ }
+ }
+
+ App.contextType = ctx;
+
+ render(<App />, scratch);
+ expect(actual).to.deep.equal('foo');
+ });
+
+ it('should use the value of the nearest Provider', () => {
+ const ctx = createContext('foo');
+
+ let actual;
+ class App extends Component {
+ render() {
+ actual = this.context;
+ return <div>bar</div>;
+ }
+ }
+
+ App.contextType = ctx;
+ const Provider = ctx.Provider;
+
+ render(
+ <Provider value="bar">
+ <Provider value="bob">
+ <App />
+ </Provider>
+ </Provider>,
+ scratch
+ );
+ expect(actual).to.deep.equal('bob');
+ });
+
+ it('should restore legacy context for children', () => {
+ const Foo = createContext('foo');
+ const spy = sinon.spy();
+
+ class NewContext extends Component {
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ class OldContext extends Component {
+ getChildContext() {
+ return { foo: 'foo' };
+ }
+
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ class Inner extends Component {
+ render() {
+ spy(this.context);
+ return <div>Inner</div>;
+ }
+ }
+
+ NewContext.contextType = Foo;
+
+ render(
+ <Foo.Provider value="bar">
+ <OldContext>
+ <NewContext>
+ <Inner />
+ </NewContext>
+ </OldContext>
+ </Foo.Provider>,
+ scratch
+ );
+
+ expect(spy).to.be.calledWithMatch({ foo: 'foo' });
+ });
+
+ it('should call componentWillUnmount', () => {
+ let Foo = createContext('foo');
+ let spy = sinon.spy();
+
+ let instance;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ instance = this;
+ }
+
+ componentWillUnmount() {
+ spy(this);
+ }
+
+ render() {
+ return <div />;
+ }
+ }
+
+ App.contextType = Foo;
+
+ render(
+ <Foo.Provider value="foo">
+ <App />
+ </Foo.Provider>,
+ scratch
+ );
+
+ render(null, scratch);
+
+ expect(spy).to.be.calledOnce;
+ expect(spy.getCall(0).args[0]).to.equal(instance);
+ });
+
+ it('should order updates correctly', () => {
+ const events = [];
+ let update;
+ const Store = createContext();
+
+ class Root extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { id: 0 };
+ update = this.updateStore = this.updateStore.bind(this);
+ }
+
+ updateStore() {
+ this.setState(state => ({ id: state.id + 1 }));
+ }
+
+ render() {
+ return (
+ <Store.Provider value={this.state.id}>
+ <App />
+ </Store.Provider>
+ );
+ }
+ }
+
+ class App extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return <Store.Consumer>{id => <Parent key={id} />}</Store.Consumer>;
+ }
+ }
+
+ function Parent(props) {
+ return <Store.Consumer>{id => <Child id={id} />}</Store.Consumer>;
+ }
+
+ class Child extends Component {
+ componentDidMount() {
+ events.push('mount ' + this.props.id);
+ }
+
+ componentDidUpdate(prevProps) {
+ events.push('update ' + prevProps.id + ' to ' + this.props.id);
+ }
+
+ componentWillUnmount() {
+ events.push('unmount ' + this.props.id);
+ }
+
+ render() {
+ events.push('render ' + this.props.id);
+ return this.props.id;
+ }
+ }
+
+ render(<Root />, scratch);
+ expect(events).to.deep.equal(['render 0', 'mount 0']);
+
+ update();
+ rerender();
+ expect(events).to.deep.equal([
+ 'render 0',
+ 'mount 0',
+ 'render 1',
+ 'unmount 0',
+ 'mount 1'
+ ]);
+ });
+ });
+
+ it('should rerender when reset to defaultValue', () => {
+ const defaultValue = { state: 'hi' };
+ const context = createContext(defaultValue);
+ let set;
+
+ class NoUpdate extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return <context.Consumer>{v => <p>{v.state}</p>}</context.Consumer>;
+ }
+ }
+
+ class Provider extends Component {
+ constructor(props) {
+ super(props);
+ this.state = defaultValue;
+ set = this.setState.bind(this);
+ }
+
+ render() {
+ return (
+ <context.Provider value={this.state}>
+ <NoUpdate />
+ </context.Provider>
+ );
+ }
+ }
+
+ render(<Provider />, scratch);
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+
+ set({ state: 'bye' });
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>bye</p>');
+
+ set(defaultValue);
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>hi</p>');
+ });
+});
diff --git a/preact/test/browser/customBuiltInElements.test.js b/preact/test/browser/customBuiltInElements.test.js
new file mode 100644
index 0000000..eb8ce17
--- /dev/null
+++ b/preact/test/browser/customBuiltInElements.test.js
@@ -0,0 +1,40 @@
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+const runSuite = typeof customElements == 'undefined' ? xdescribe : describe;
+
+runSuite('customised built-in elements', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should create built in elements correctly', () => {
+ class Foo extends Component {
+ render() {
+ return <div is="built-in" />;
+ }
+ }
+
+ const spy = sinon.spy();
+
+ class BuiltIn extends HTMLDivElement {
+ connectedCallback() {
+ spy();
+ }
+ }
+
+ customElements.define('built-in', BuiltIn, { extends: 'div' });
+
+ render(<Foo />, scratch);
+
+ expect(spy).to.have.been.calledOnce;
+ });
+});
diff --git a/preact/test/browser/events.test.js b/preact/test/browser/events.test.js
new file mode 100644
index 0000000..2e43cba
--- /dev/null
+++ b/preact/test/browser/events.test.js
@@ -0,0 +1,202 @@
+import { createElement, render } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ supportsPassiveEvents
+} from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('event handling', () => {
+ let scratch, proto;
+
+ function fireEvent(on, type) {
+ let e = document.createEvent('Event');
+ e.initEvent(type, true, true);
+ on.dispatchEvent(e);
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+
+ proto = document.createElement('div').constructor.prototype;
+
+ sinon.spy(proto, 'addEventListener');
+ sinon.spy(proto, 'removeEventListener');
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+
+ proto.addEventListener.restore();
+ proto.removeEventListener.restore();
+ });
+
+ it('should only register on* functions as handlers', () => {
+ let click = () => {},
+ onclick = () => {};
+
+ render(<div click={click} onClick={onclick} />, scratch);
+
+ expect(scratch.childNodes[0].attributes.length).to.equal(0);
+
+ expect(
+ proto.addEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'click',
+ sinon.match.func,
+ false
+ );
+ });
+
+ it('should only register truthy values as handlers', () => {
+ function fooHandler() {}
+ const falsyHandler = false;
+
+ render(<div onClick={falsyHandler} onOtherClick={fooHandler} />, scratch);
+
+ expect(
+ proto.addEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'OtherClick',
+ sinon.match.func,
+ false
+ );
+
+ expect(proto.addEventListener).not.to.have.been.calledWith('Click');
+ expect(proto.addEventListener).not.to.have.been.calledWith('click');
+ });
+
+ it('should support native event names', () => {
+ let click = sinon.spy(),
+ mousedown = sinon.spy();
+
+ render(<div onclick={() => click(1)} onmousedown={mousedown} />, scratch);
+
+ expect(proto.addEventListener)
+ .to.have.been.calledTwice.and.to.have.been.calledWith('click')
+ .and.calledWith('mousedown');
+
+ fireEvent(scratch.childNodes[0], 'click');
+ expect(click).to.have.been.calledOnce.and.calledWith(1);
+ });
+
+ it('should support camel-case event names', () => {
+ let click = sinon.spy(),
+ mousedown = sinon.spy();
+
+ render(<div onClick={() => click(1)} onMouseDown={mousedown} />, scratch);
+
+ expect(proto.addEventListener)
+ .to.have.been.calledTwice.and.to.have.been.calledWith('click')
+ .and.calledWith('mousedown');
+
+ fireEvent(scratch.childNodes[0], 'click');
+ expect(click).to.have.been.calledOnce.and.calledWith(1);
+ });
+
+ it('should update event handlers', () => {
+ let click1 = sinon.spy();
+ let click2 = sinon.spy();
+
+ render(<div onClick={click1} />, scratch);
+
+ fireEvent(scratch.childNodes[0], 'click');
+ expect(click1).to.have.been.calledOnce;
+ expect(click2).to.not.have.been.called;
+
+ click1.resetHistory();
+ click2.resetHistory();
+
+ render(<div onClick={click2} />, scratch);
+
+ fireEvent(scratch.childNodes[0], 'click');
+ expect(click1).to.not.have.been.called;
+ expect(click2).to.have.been.called;
+ });
+
+ it('should remove event handlers', () => {
+ let click = sinon.spy(),
+ mousedown = sinon.spy();
+
+ render(<div onClick={() => click(1)} onMouseDown={mousedown} />, scratch);
+ render(<div onClick={() => click(2)} />, scratch);
+
+ expect(proto.removeEventListener).to.have.been.calledWith('mousedown');
+
+ fireEvent(scratch.childNodes[0], 'mousedown');
+ expect(mousedown).not.to.have.been.called;
+
+ proto.removeEventListener.resetHistory();
+ click.resetHistory();
+ mousedown.resetHistory();
+
+ render(<div />, scratch);
+
+ expect(proto.removeEventListener).to.have.been.calledWith('click');
+
+ fireEvent(scratch.childNodes[0], 'click');
+ expect(click).not.to.have.been.called;
+ });
+
+ it('should register events not appearing on dom nodes', () => {
+ let onAnimationEnd = () => {};
+
+ render(<div onanimationend={onAnimationEnd} />, scratch);
+ expect(
+ proto.addEventListener
+ ).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
+ 'animationend',
+ sinon.match.func,
+ false
+ );
+ });
+
+ // Skip test if browser doesn't support passive events
+ if (supportsPassiveEvents()) {
+ it('should use capturing for event props ending with *Capture', () => {
+ let click = sinon.spy(),
+ focus = sinon.spy();
+
+ render(
+ <div onClickCapture={click} onFocusCapture={focus}>
+ <button />
+ </div>,
+ scratch
+ );
+
+ let root = scratch.firstChild;
+ root.firstElementChild.click();
+ root.firstElementChild.focus();
+
+ expect(click, 'click').to.have.been.calledOnce;
+
+ // Focus delegation requires a 50b hack I'm not sure we want to incur
+ expect(focus, 'focus').to.have.been.calledOnce;
+
+ // IE doesn't set it
+ if (!/Edge/.test(navigator.userAgent)) {
+ expect(click).to.have.been.calledWithMatch({ eventPhase: 0 }); // capturing
+ expect(focus).to.have.been.calledWithMatch({ eventPhase: 0 }); // capturing
+ }
+ });
+
+ it('should support both capturing and non-capturing events on the same element', () => {
+ let click = sinon.spy(),
+ clickCapture = sinon.spy();
+
+ render(
+ <div onClick={click} onClickCapture={clickCapture}>
+ <button />
+ </div>,
+ scratch
+ );
+
+ let root = scratch.firstChild;
+ root.firstElementChild.click();
+
+ expect(clickCapture, 'click').to.have.been.calledOnce;
+ expect(click, 'click').to.have.been.calledOnce;
+ });
+ }
+});
diff --git a/preact/test/browser/focus.test.js b/preact/test/browser/focus.test.js
new file mode 100644
index 0000000..004a87a
--- /dev/null
+++ b/preact/test/browser/focus.test.js
@@ -0,0 +1,548 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, Fragment, hydrate } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+import { div, span, input as inputStr, h1, h2 } from '../_util/dom';
+
+/** @jsx createElement */
+/* eslint-disable react/jsx-boolean-value */
+
+describe('focus', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ /** @type {() => void} */
+ let prepend, append, shift, pop;
+
+ /** @type {() => void} */
+ let getDynamicListHtml;
+
+ class DynamicList extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ before: props.initialBefore || [],
+ after: props.initialAfter || []
+ };
+
+ prepend = () => {
+ const before = this.state.before;
+ const newValue = before[0] ? before[0] - 1 : 1;
+ this.setState({
+ before: [newValue, ...before]
+ });
+ };
+
+ append = () => {
+ const after = this.state.after;
+ const lastValue = after[after.length - 1];
+ const newValue = lastValue ? lastValue + 1 : 2;
+ this.setState({
+ after: [...after, newValue]
+ });
+ };
+
+ shift = () => {
+ this.setState({
+ before: this.state.before.slice(1)
+ });
+ };
+
+ pop = () => {
+ this.setState({
+ after: this.state.after.slice(0, -1)
+ });
+ };
+
+ const liHtml = this.props.as == Input ? inputStr : span;
+ getDynamicListHtml = () =>
+ div([
+ ...this.state.before.map(liHtml),
+ '<input id="input-0" type="text">',
+ ...this.state.after.map(liHtml)
+ ]);
+ }
+
+ render(props, state) {
+ const ListComponent = props.as || ListItem;
+ return (
+ <div>
+ {state.before.map(value => (
+ <ListComponent key={props.unkeyed ? undefined : value}>
+ {value}
+ </ListComponent>
+ ))}
+ <InputWithId id="0" />
+ {state.after.map(value => (
+ <ListComponent key={props.unkeyed ? undefined : value}>
+ {value}
+ </ListComponent>
+ ))}
+ </div>
+ );
+ }
+ }
+
+ const List = ({ children }) => <div>{children}</div>;
+ const ListItem = ({ children }) => <span>{children}</span>;
+ const InputWithId = ({ id }) => <input id={`input-${id}`} type="text" />;
+ const Input = () => <input type="text" />;
+
+ function focusInput() {
+ if (!scratch) return;
+
+ const input = scratch.querySelector('input');
+ input.value = 'a word';
+ input.focus();
+ input.setSelectionRange(2, 5);
+
+ expect(document.activeElement).to.equalNode(input);
+
+ return input;
+ }
+
+ function focusInputById() {
+ if (!scratch) return;
+
+ /** @type {HTMLInputElement} */
+ const input = scratch.querySelector('#input-0');
+ input.value = 'a word';
+ input.focus();
+ input.setSelectionRange(2, 5);
+
+ expect(document.activeElement).to.equalNode(input);
+
+ return input;
+ }
+
+ /**
+ * Validate an input tag has maintained focus
+ * @param {HTMLInputElement} input The input to validate
+ * @param {string} [message] Message to show if the activeElement is not
+ * equal to the `input` parameter
+ */
+ function validateFocus(input, message) {
+ expect(document.activeElement).to.equalNode(input, message);
+ expect(input.selectionStart).to.equal(2);
+ expect(input.selectionEnd).to.equal(5);
+ }
+
+ /**
+ * @param {Array<number | string>} before
+ * @param {Array<number | string>} after
+ */
+ function getListHtml(before, after) {
+ return div([
+ ...before.map(i => span(i)),
+ inputStr(),
+ ...after.map(i => span(i))
+ ]);
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it.skip('should maintain focus when swapping elements', () => {
+ render(
+ <List>
+ <Input />
+ <ListItem>fooo</ListItem>
+ </List>,
+ scratch
+ );
+
+ const input = focusInput();
+ expect(scratch.innerHTML).to.equal(getListHtml([], ['fooo']));
+
+ render(
+ <List>
+ <ListItem>fooo</ListItem>
+ <Input />
+ </List>,
+ scratch
+ );
+ validateFocus(input);
+ expect(scratch.innerHTML).to.equal(getListHtml(['fooo'], []));
+ });
+
+ it('should maintain focus when moving the input around', () => {
+ function App({ showFirst, showLast }) {
+ return (
+ <List>
+ {showFirst ? <ListItem>1</ListItem> : null}
+ <Input />
+ {showLast ? <ListItem>2</ListItem> : null}
+ </List>
+ );
+ }
+
+ render(<App showFirst={true} showLast={true} />, scratch);
+
+ let input = focusInput();
+ render(<App showFirst={false} showLast={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(getListHtml([], [2]));
+ validateFocus(input, 'move from middle to beginning');
+
+ input = focusInput();
+ render(<App showFirst={true} showLast={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(getListHtml([1], [2]));
+ validateFocus(input, 'move from beginning to middle');
+
+ input = focusInput();
+ render(<App showFirst={true} showLast={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(getListHtml([1], []));
+ validateFocus(input, 'move from middle to end');
+
+ input = focusInput();
+ render(<App showFirst={true} showLast={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(getListHtml([1], [2]));
+ validateFocus(input, 'move from end to middle');
+ });
+
+ it('should maintain focus when adding children around input', () => {
+ render(<DynamicList />, scratch);
+
+ let input = focusInput();
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling before');
+
+ append();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling after');
+
+ append();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling after again');
+
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling before again');
+ });
+
+ it('should maintain focus when adding children around input (unkeyed)', () => {
+ // Related preactjs/preact#2446
+
+ render(<DynamicList unkeyed />, scratch);
+
+ let input = focusInput();
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling before');
+
+ append();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling after');
+
+ append();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling after again');
+
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'insert sibling before again');
+ });
+
+ it('should maintain focus when conditional elements around input', () => {
+ render(
+ <List>
+ <ListItem>0</ListItem>
+ <ListItem>1</ListItem>
+ <Input />
+ <ListItem>2</ListItem>
+ <ListItem>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ let input = focusInput();
+ expect(scratch.innerHTML).to.equal(getListHtml([0, 1], [2, 3]));
+
+ render(
+ <List>
+ {false && <ListItem>0</ListItem>}
+ <ListItem>1</ListItem>
+ <Input />
+ <ListItem>2</ListItem>
+ <ListItem>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(getListHtml([1], [2, 3]));
+ validateFocus(input, 'remove sibling before');
+
+ render(
+ <List>
+ {false && <ListItem>0</ListItem>}
+ <ListItem>1</ListItem>
+ <Input />
+ <ListItem>2</ListItem>
+ {false && <ListItem>3</ListItem>}
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(getListHtml([1], [2]));
+ validateFocus(input, 'remove sibling after');
+
+ render(
+ <List>
+ {false && <ListItem>0</ListItem>}
+ <ListItem>1</ListItem>
+ <Input />
+ {false && <ListItem>2</ListItem>}
+ {false && <ListItem>3</ListItem>}
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(getListHtml([1], []));
+ validateFocus(input, 'remove sibling after 2');
+
+ render(
+ <List>
+ {false && <ListItem>0</ListItem>}
+ {false && <ListItem>1</ListItem>}
+ <Input />
+ {false && <ListItem>2</ListItem>}
+ {false && <ListItem>3</ListItem>}
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(getListHtml([], []));
+ validateFocus(input, 'remove sibling before 2');
+ });
+
+ it('should maintain focus when removing elements around input', () => {
+ render(
+ <DynamicList initialBefore={[0, 1]} initialAfter={[2, 3]} />,
+ scratch
+ );
+
+ let input = focusInput();
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+
+ shift();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'remove sibling before');
+
+ pop();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'remove sibling after');
+
+ pop();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'remove sibling after 2');
+
+ shift();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'remove sibling before 2');
+ });
+
+ it('should maintain focus when adding input next to the current input', () => {
+ render(<DynamicList as={Input} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+
+ let input = focusInputById();
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'add input before');
+
+ input = focusInputById();
+ append();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'add input after');
+
+ input = focusInputById();
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'add input first place');
+
+ input = focusInputById();
+ prepend();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(getDynamicListHtml());
+ validateFocus(input, 'add input before');
+ });
+
+ it('should maintain focus when hydrating', () => {
+ const html = div([span('1'), span('2'), span('3'), inputStr()]);
+
+ scratch.innerHTML = html;
+ const input = focusInput();
+
+ hydrate(
+ <List>
+ <ListItem>1</ListItem>
+ <ListItem>2</ListItem>
+ <ListItem>3</ListItem>
+ <Input />
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ validateFocus(input);
+ });
+
+ it('should keep focus in Fragments', () => {
+ /** @type {HTMLInputElement} */
+ let input;
+
+ /** @type {() => void} */
+ let updateState;
+
+ class App extends Component {
+ constructor() {
+ super();
+ this.state = { active: false };
+ updateState = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return (
+ <div>
+ <h1>Heading</h1>
+ {!this.state.active ? (
+ <Fragment>
+ foobar
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ <input type="text" ref={i => (input = i)} />
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ foobar
+ <input type="text" ref={i => (input = i)} />
+ </Fragment>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+
+ input.focus();
+ updateState();
+
+ expect(document.activeElement).to.equalNode(input, 'Before rerender');
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ div([h1('Heading'), 'Hello World', h2('yo'), 'foobar', inputStr()])
+ );
+ expect(document.activeElement).to.equalNode(input, 'After rerender');
+ });
+
+ it('should keep text selection', () => {
+ /** @type {HTMLInputElement} */
+ let input;
+
+ /** @type {() => void} */
+ let updateState;
+
+ class App extends Component {
+ constructor() {
+ super();
+ this.state = { active: false };
+ updateState = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return (
+ <div>
+ <h1>Heading</h1>
+ {!this.state.active ? (
+ <Fragment>
+ foobar
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ <input type="text" ref={i => (input = i)} value="foobar" />
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ foobar
+ <input type="text" ref={i => (input = i)} value="foobar" />
+ </Fragment>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+
+ input.focus();
+ input.setSelectionRange(2, 5);
+ updateState();
+
+ expect(document.activeElement).to.equalNode(input, 'Before rerender');
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ div([h1('Heading'), 'Hello World', h2('yo'), 'foobar', inputStr()])
+ );
+ expect(input.selectionStart).to.equal(2);
+ expect(input.selectionEnd).to.equal(5);
+ expect(document.activeElement).to.equalNode(input, 'After rerender');
+ });
+});
diff --git a/preact/test/browser/fragments.test.js b/preact/test/browser/fragments.test.js
new file mode 100644
index 0000000..882aeed
--- /dev/null
+++ b/preact/test/browser/fragments.test.js
@@ -0,0 +1,2805 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, Fragment } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+import { span, div, ul, ol, li, section } from '../_util/dom';
+import { logCall, clearLog, getLog } from '../_util/logCall';
+
+/** @jsx createElement */
+/* eslint-disable react/jsx-boolean-value */
+
+describe('Fragment', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ let ops = [];
+
+ function expectDomLogToBe(expectedOperations, message) {
+ expect(getLog()).to.deep.equal(expectedOperations, message);
+ }
+
+ class Stateful extends Component {
+ componentDidUpdate() {
+ ops.push('Update Stateful');
+ }
+ render() {
+ return <div>Hello</div>;
+ }
+ }
+
+ let resetInsertBefore;
+ let resetAppendChild;
+ let resetRemoveChild;
+
+ before(() => {
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ // logCall(CharacterData.prototype, 'remove');
+ // TODO: Consider logging setting set data
+ // ```
+ // var orgData = Object.getOwnPropertyDescriptor(CharacterData.prototype, 'data')
+ // Object.defineProperty(CharacterData.prototype, 'data', {
+ // ...orgData,
+ // get() { return orgData.get.call(this) },
+ // set(value) { console.log('setData', value); orgData.set.call(this, value); }
+ // });
+ // ```
+ });
+
+ after(() => {
+ resetInsertBefore();
+ resetAppendChild();
+ resetRemoveChild();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ ops = [];
+
+ clearLog();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should not render empty Fragment', () => {
+ render(<Fragment />, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ });
+
+ it('should render a single child', () => {
+ clearLog();
+ render(
+ <Fragment>
+ <span>foo</span>
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('<span>foo</span>');
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>.appendChild(<span>foo)'
+ ]);
+ });
+
+ it('should render multiple children via noop renderer', () => {
+ render(
+ <Fragment>
+ hello <span>world</span>
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('hello <span>world</span>');
+ });
+
+ it('should not crash with null as last child', () => {
+ let fn = () => {
+ render(
+ <Fragment>
+ <span>world</span>
+ {null}
+ </Fragment>,
+ scratch
+ );
+ };
+ expect(fn).not.to.throw();
+ expect(scratch.innerHTML).to.equal('<span>world</span>');
+
+ render(
+ <Fragment>
+ <span>world</span>
+ <p>Hello</p>
+ </Fragment>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<span>world</span><p>Hello</p>');
+
+ expect(fn).not.to.throw();
+ expect(scratch.innerHTML).to.equal('<span>world</span>');
+
+ render(
+ <Fragment>
+ <span>world</span>
+ {null}
+ <span>world</span>
+ </Fragment>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<span>world</span><span>world</span>');
+
+ render(
+ <Fragment>
+ <span>world</span>
+ Hello
+ <span>world</span>
+ </Fragment>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<span>world</span>Hello<span>world</span>'
+ );
+ });
+
+ it('should handle reordering components that return Fragments #1325', () => {
+ class X extends Component {
+ render() {
+ return <Fragment>{this.props.children}</Fragment>;
+ }
+ }
+
+ class App extends Component {
+ render(props) {
+ if (this.props.i === 0) {
+ return (
+ <div>
+ <X key={1}>1</X>
+ <X key={2}>2</X>
+ </div>
+ );
+ }
+ return (
+ <div>
+ <X key={2}>2</X>
+ <X key={1}>1</X>
+ </div>
+ );
+ }
+ }
+
+ render(<App i={0} />, scratch);
+ expect(scratch.textContent).to.equal('12');
+ render(<App i={1} />, scratch);
+ expect(scratch.textContent).to.equal('21');
+ });
+
+ it('should handle changing node type within a Component that returns a Fragment #1326', () => {
+ class X extends Component {
+ render() {
+ return this.props.children;
+ }
+ }
+
+ /** @type {(newState: any) => void} */
+ let setState;
+ class App extends Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = { i: 0 };
+ setState = this.setState.bind(this);
+ }
+
+ render() {
+ if (this.state.i === 0) {
+ return (
+ <div>
+ <X>
+ <span>1</span>
+ </X>
+ <X>
+ <span>2</span>
+ <span>2</span>
+ </X>
+ </div>
+ );
+ }
+
+ return (
+ <div>
+ <X>
+ <div>1</div>
+ </X>
+ <X>
+ <span>2</span>
+ <span>2</span>
+ </X>
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(div([span(1), span(2), span(2)]));
+
+ setState({ i: 1 });
+
+ clearLog();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(div([div(1), span(2), span(2)]));
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>122.insertBefore(<div>1, <span>1)',
+ '<span>1.remove()'
+ ]);
+ });
+
+ it('should preserve state of children with 1 level nesting', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Stateful key="a" />
+ ) : (
+ <Fragment>
+ <Stateful key="a" />
+ <div key="b">World</div>
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.deep.equal('<div>Hello</div><div>World</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.deep.equal('<div>Hello</div>');
+ });
+
+ it('should preserve state between top-level fragments', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>
+ <Stateful />
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Stateful />
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([]);
+ });
+
+ it('should preserve state of children nested at same level', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Fragment>
+ <Fragment>
+ <div />
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div></div><div>Hello</div>');
+ expectDomLogToBe(['<div>Hello.insertBefore(<div>, <div>Hello)']);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe(['<div>.remove()']);
+ });
+
+ it('should not preserve state in non-top-level fragment nesting', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>Hello.insertBefore(<div>Hello, <div>Hello)',
+ '<div>Hello.remove()'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ // Re-append the Stateful DOM since it has been re-parented
+ '<div>Hello.insertBefore(<div>Hello, <div>Hello)',
+ '<div>Hello.remove()'
+ ]);
+ });
+
+ it('should not preserve state of children if nested 2 levels without siblings', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Stateful key="a" />
+ ) : (
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>Hello.insertBefore(<div>Hello, <div>Hello)',
+ '<div>Hello.remove()'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>Hello.insertBefore(<div>Hello, <div>Hello)',
+ '<div>Hello.remove()'
+ ]);
+ });
+
+ it('should just render children for fragments', () => {
+ class Comp extends Component {
+ render() {
+ return (
+ <Fragment>
+ <div>Child1</div>
+ <div>Child2</div>
+ </Fragment>
+ );
+ }
+ }
+
+ render(<Comp />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Child1</div><div>Child2</div>');
+ });
+
+ it('should not preserve state of children if nested 2 levels with siblings', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Stateful key="a" />
+ ) : (
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ <div />
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div><div></div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should preserve state between array nested in fragment and fragment', () => {
+ // In this test case, the children of the Fragment in Foo end up being the same when flattened.
+ //
+ // When condition == true, the children of the Fragment are a Stateful VNode.
+ // When condition == false, the children of the Fragment are an Array containing a single
+ // Stateful VNode.
+ //
+ // However, when each of these are flattened (in flattenChildren), they both become
+ // an Array containing a single Stateful VNode. So when diff'ed they are compared together
+ // and the state of Stateful is preserved
+
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ ) : (
+ <Fragment>{[<Stateful key="a" />]}</Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should preserve state between top level fragment and array', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ [<Stateful key="a" />]
+ ) : (
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should not preserve state between array nested in fragment and double nested fragment', () => {
+ // In this test case, the children of the Fragment in Foo end up being the different when flattened.
+ //
+ // When condition == true, the children of the Fragment are an Array of Stateful VNode.
+ // When condition == false, the children of the Fragment are another Fragment whose children are
+ // a single Stateful VNode.
+ //
+ // When each of these are flattened (in flattenChildren), the first Fragment stays the same
+ // (Fragment -> [Stateful]). The second Fragment also doesn't change (flattening doesn't erase
+ // Fragments) so it remains Fragment -> Fragment -> Stateful. Therefore when diff'ed these Fragments
+ // separate the two Stateful VNodes into different trees and state is not preserved between them.
+
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>{[<Stateful key="a" />]}</Fragment>
+ ) : (
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should not preserve state between array nested in fragment and double nested array', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>{[<Stateful key="a" />]}</Fragment>
+ ) : (
+ [[<Stateful key="a" />]]
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should preserve state between double nested fragment and double nested array', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment>
+ <Fragment>
+ <Stateful key="a" />
+ </Fragment>
+ </Fragment>
+ ) : (
+ [[<Stateful key="a" />]]
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should not preserve state of children when the keys are different', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment key="a">
+ <Stateful />
+ </Fragment>
+ ) : (
+ <Fragment key="b">
+ <Stateful />
+ <span>World</span>
+ </Fragment>
+ );
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div><span>World</span>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should not preserve state between unkeyed and keyed fragment', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <Fragment key="a">
+ <Stateful />
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Stateful />
+ </Fragment>
+ );
+ }
+
+ // React & Preact: has the same behavior for components
+ // https://codesandbox.io/s/57prmy5mx
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should preserve state with reordering in multiple levels', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment key="c">
+ <div>foo</div>
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ </Fragment>
+ <div>boop</div>
+ </div>
+ ) : (
+ <div>
+ <div>beep</div>
+ <Fragment key="c">
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ <div>bar</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ const htmlForTrue = div([div('foo'), div(div('Hello')), div('boop')]);
+
+ const htmlForFalse = div([div('beep'), div(div('Hello')), div('bar')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForTrue);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal(htmlForFalse);
+ expectDomLogToBe(
+ [
+ '<div>fooHellobeep.insertBefore(<div>beep, <div>foo)',
+ '<div>beepbarHello.appendChild(<div>bar)'
+ ],
+ 'rendering true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal(htmlForTrue);
+ expectDomLogToBe(
+ [
+ '<div>beepHellofoo.insertBefore(<div>foo, <div>beep)',
+ '<div>fooboopHello.appendChild(<div>boop)'
+ ],
+ 'rendering false to true'
+ );
+ });
+
+ it('should not preserve state when switching between a keyed fragment and an array', () => {
+ function Foo({ condition }) {
+ return condition ? (
+ <div>
+ {
+ <Fragment key="foo">
+ <span>1</span>
+ <Stateful />
+ </Fragment>
+ }
+ <span>2</span>
+ </div>
+ ) : (
+ <div>
+ {[<span>1</span>, <Stateful />]}
+ <span>2</span>
+ </div>
+ );
+ }
+
+ const html = div([span('1'), div('Hello'), span('2')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal([]); // Component should not have updated (empty op log)
+ expect(scratch.innerHTML).to.equal(html);
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>1Hello2.insertBefore(<span>1, <span>1)',
+ '<div>.appendChild(#text)',
+ '<div>11Hello2.insertBefore(<div>Hello, <span>1)',
+ '<div>1Hello1Hello2.insertBefore(<span>2, <span>1)',
+ '<span>1.remove()',
+ '<div>Hello.remove()'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal([]); // Component should not have updated (empty op log)
+ expect(scratch.innerHTML).to.equal(html);
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>1Hello2.insertBefore(<span>1, <span>1)',
+ '<div>.appendChild(#text)',
+ '<div>11Hello2.insertBefore(<div>Hello, <span>1)',
+ '<div>1Hello1Hello2.insertBefore(<span>2, <span>1)',
+ '<span>1.remove()',
+ '<div>Hello.remove()'
+ ]);
+ });
+
+ it('should preserve state when it does not change positions', () => {
+ function Foo({ condition }) {
+ return condition
+ ? [
+ <span />,
+ <Fragment>
+ <Stateful />
+ </Fragment>
+ ]
+ : [
+ <span />,
+ <Fragment>
+ <Stateful />
+ </Fragment>
+ ];
+ }
+
+ render(<Foo condition={true} />, scratch);
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<span></span><div>Hello</div>');
+
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal('<span></span><div>Hello</div>');
+ });
+
+ it('should render nested Fragments', () => {
+ clearLog();
+ render(
+ <Fragment>
+ spam
+ <Fragment>foo</Fragment>
+ <Fragment />
+ bar
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('spamfoobar');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>spam.appendChild(#text)',
+ '<div>spamfoo.appendChild(#text)'
+ ]);
+
+ clearLog();
+ render(
+ <Fragment>
+ <Fragment>foo</Fragment>
+ <Fragment>bar</Fragment>
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal('foobar');
+ expectDomLogToBe([
+ '<div>spamfoobar.insertBefore(#text, #text)',
+ '#text.remove()',
+ '#text.remove()'
+ ]);
+ });
+
+ it('should render nested Fragments with siblings', () => {
+ clearLog();
+ render(
+ <div>
+ <div>0</div>
+ <div>1</div>
+ <Fragment>
+ <Fragment>
+ <div>2</div>
+ <div>3</div>
+ </Fragment>
+ </Fragment>
+ <div>4</div>
+ <div>5</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(
+ div([div(0), div(1), div(2), div(3), div(4), div(5)])
+ );
+ });
+
+ it('should respect keyed Fragments', () => {
+ /** @type {() => void} */
+ let update;
+
+ class Comp extends Component {
+ constructor() {
+ super();
+ this.state = { key: 'foo' };
+ update = () => this.setState({ key: 'bar' });
+ }
+
+ render() {
+ return <Fragment key={this.state.key}>foo</Fragment>;
+ }
+ }
+ render(<Comp />, scratch);
+ expect(scratch.innerHTML).to.equal('foo');
+
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('foo');
+ });
+
+ it('should support conditionally rendered children', () => {
+ /** @type {() => void} */
+ let update;
+
+ class Comp extends Component {
+ constructor() {
+ super();
+ this.state = { value: true };
+ update = () => this.setState({ value: !this.state.value });
+ }
+
+ render() {
+ return (
+ <Fragment>
+ <span>0</span>
+ {this.state.value && 'foo'}
+ <span>1</span>
+ </Fragment>
+ );
+ }
+ }
+
+ const html = contents => span('0') + contents + span('1');
+
+ render(<Comp />, scratch);
+ expect(scratch.innerHTML).to.equal(html('foo'));
+
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(html(''));
+
+ update();
+ rerender();
+ expect(scratch.innerHTML).to.equal(html('foo'));
+ });
+
+ it('can modify the children of a Fragment', () => {
+ /** @type {() => void} */
+ let push;
+
+ class List extends Component {
+ constructor() {
+ super();
+ this.state = { values: [0, 1, 2] };
+ push = () =>
+ this.setState({
+ values: [...this.state.values, this.state.values.length]
+ });
+ }
+
+ render() {
+ return (
+ <Fragment>
+ {this.state.values.map(value => (
+ <div>{value}</div>
+ ))}
+ </Fragment>
+ );
+ }
+ }
+
+ render(<List />, scratch);
+ expect(scratch.textContent).to.equal('012');
+
+ push();
+ rerender();
+
+ expect(scratch.textContent).to.equal('0123');
+
+ push();
+ rerender();
+
+ expect(scratch.textContent).to.equal('01234');
+ });
+
+ it('should render sibling array children', () => {
+ const Group = ({ title, values }) => (
+ <Fragment>
+ <li>{title}</li>
+ {values.map(value => (
+ <li>{value}</li>
+ ))}
+ </Fragment>
+ );
+
+ const Todo = () => (
+ <ul>
+ <Group title={'A header'} values={['a', 'b']} />
+ <Group title={'A divider'} values={['c', 'd']} />
+ <li>A footer</li>
+ </ul>
+ );
+
+ render(<Todo />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ ul([
+ li('A header'),
+ li('a'),
+ li('b'),
+ li('A divider'),
+ li('c'),
+ li('d'),
+ li('A footer')
+ ])
+ );
+ });
+
+ it('should reorder Fragment children', () => {
+ let updateState;
+
+ class App extends Component {
+ constructor() {
+ super();
+ this.state = { active: false };
+ updateState = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return (
+ <div>
+ <h1>Heading</h1>
+ {!this.state.active ? (
+ <Fragment>
+ foobar
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ <input type="text" />
+ </Fragment>
+ ) : (
+ <Fragment>
+ <Fragment>
+ Hello World
+ <h2>yo</h2>
+ </Fragment>
+ foobar
+ <input type="text" />
+ </Fragment>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><h1>Heading</h1>foobarHello World<h2>yo</h2><input type="text"></div>'
+ );
+
+ updateState();
+
+ // See "should preserve state between top level fragment and array"
+ // Perhaps rename test to "should reorder **keyed** Fragment children"
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><h1>Heading</h1>Hello World<h2>yo</h2>foobar<input type="text"></div>'
+ );
+ });
+
+ it('should render sibling fragments with multiple children in the correct order', () => {
+ render(
+ <ol>
+ <li>0</li>
+ <Fragment>
+ <li>1</li>
+ <li>2</li>
+ </Fragment>
+ <li>3</li>
+ <li>4</li>
+ <Fragment>
+ <li>5</li>
+ <li>6</li>
+ </Fragment>
+ <li>7</li>
+ </ol>,
+ scratch
+ );
+
+ expect(scratch.textContent).to.equal('01234567');
+ });
+
+ it('should support HOCs that return children', () => {
+ const text =
+ "Don't forget to tell these special people in your life just how special they are to you.";
+
+ class BobRossProvider extends Component {
+ getChildContext() {
+ return { text };
+ }
+
+ render(props) {
+ return props.children;
+ }
+ }
+
+ function BobRossConsumer(props, context) {
+ return props.children(context.text);
+ }
+
+ const Say = props => <div>{props.text}</div>;
+
+ const Speak = () => (
+ <Fragment>
+ <span>the top</span>
+ <BobRossProvider>
+ <span>a span</span>
+ <BobRossConsumer>
+ {text => [<Say text={text} />, <Say text={text} />]}
+ </BobRossConsumer>
+ <span>another span</span>
+ </BobRossProvider>
+ <span>a final span</span>
+ </Fragment>
+ );
+
+ render(<Speak />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ [
+ span('the top'),
+ span('a span'),
+ div(text),
+ div(text),
+ span('another span'),
+ span('a final span')
+ ].join('')
+ );
+ });
+
+ it('should support conditionally rendered Fragment', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ <li>0</li>
+ {condition ? (
+ <Fragment>
+ <li>1</li>
+ <li>2</li>
+ </Fragment>
+ ) : (
+ [<li>1</li>, <li>2</li>]
+ )}
+ <li>3</li>
+ </ol>
+ );
+
+ const html = ol([li('0'), li('1'), li('2'), li('3')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(html, 'initial render of true');
+ expectDomLogToBe(
+ [
+ '<li>.appendChild(#text)',
+ '<ol>.appendChild(<li>0)',
+ '<li>.appendChild(#text)',
+ '<ol>0.appendChild(<li>1)',
+ '<li>.appendChild(#text)',
+ '<ol>01.appendChild(<li>2)',
+ '<li>.appendChild(#text)',
+ '<ol>012.appendChild(<li>3)',
+ '<div>.appendChild(<ol>0123)'
+ ],
+ 'initial render of true'
+ );
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(html, 'rendering from true to false');
+ expectDomLogToBe([], 'rendering from true to false');
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(html, 'rendering from false to true');
+ expectDomLogToBe([], 'rendering from false to true');
+ });
+
+ it('should support conditionally rendered Fragment or null', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ <li>0</li>
+ {condition ? (
+ <Fragment>
+ <li>1</li>
+ <li>2</li>
+ </Fragment>
+ ) : null}
+ <li>3</li>
+ <li>4</li>
+ </ol>
+ );
+
+ const htmlForTrue = ol([li('0'), li('1'), li('2'), li('3'), li('4')]);
+
+ const htmlForFalse = ol([li('0'), li('3'), li('4')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(htmlForTrue, 'initial render of true');
+ expectDomLogToBe(
+ [
+ '<li>.appendChild(#text)',
+ '<ol>.appendChild(<li>0)',
+ '<li>.appendChild(#text)',
+ '<ol>0.appendChild(<li>1)',
+ '<li>.appendChild(#text)',
+ '<ol>01.appendChild(<li>2)',
+ '<li>.appendChild(#text)',
+ '<ol>012.appendChild(<li>3)',
+ '<li>.appendChild(#text)',
+ '<ol>0123.appendChild(<li>4)',
+ '<div>.appendChild(<ol>01234)'
+ ],
+ 'initial render of true'
+ );
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe(
+ ['<li>1.remove()', '<li>2.remove()'],
+ 'rendering from true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe(
+ [
+ '<li>.appendChild(#text)',
+ '<ol>034.insertBefore(<li>1, <li>3)',
+ '<li>.appendChild(#text)',
+ '<ol>0134.insertBefore(<li>2, <li>3)'
+ ],
+ 'rendering from false to true'
+ );
+ });
+
+ it('should support moving Fragments between beginning and end', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ {condition
+ ? [
+ <li>0</li>,
+ <li>1</li>,
+ <li>2</li>,
+ <li>3</li>,
+ <Fragment>
+ <li>4</li>
+ <li>5</li>
+ </Fragment>
+ ]
+ : [
+ <Fragment>
+ <li>4</li>
+ <li>5</li>
+ </Fragment>,
+ <li>0</li>,
+ <li>1</li>,
+ <li>2</li>,
+ <li>3</li>
+ ]}
+ </ol>
+ );
+
+ const htmlForTrue = ol([
+ li('0'),
+ li('1'),
+ li('2'),
+ li('3'),
+ li('4'),
+ li('5')
+ ]);
+
+ const htmlForFalse = ol([
+ li('4'),
+ li('5'),
+ li('0'),
+ li('1'),
+ li('2'),
+ li('3')
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(htmlForTrue, 'initial render of true');
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe([
+ '<ol>012345.insertBefore(<li>4, <li>0)',
+ '<ol>401235.insertBefore(<li>5, <li>0)',
+ // TODO: Hmmm why does this extra append happen?
+ '<ol>453012.appendChild(<li>3)'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe([
+ '<ol>450123.appendChild(<li>4)',
+ '<ol>501234.appendChild(<li>5)'
+ ]);
+ });
+
+ it('should support conditional beginning and end Fragments', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ {condition ? (
+ <Fragment>
+ <li>0</li>
+ <li>1</li>
+ </Fragment>
+ ) : null}
+ <li>2</li>
+ <li>2</li>
+ {condition ? null : (
+ <Fragment>
+ <li>3</li>
+ <li>4</li>
+ </Fragment>
+ )}
+ </ol>
+ );
+
+ const htmlForTrue = ol([li(0), li(1), li(2), li(2)]);
+
+ const htmlForFalse = ol([li(2), li(2), li(3), li(4)]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(htmlForTrue, 'initial render of true');
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe([
+ // Mount 3 & 4
+ '<li>.appendChild(#text)',
+ '<ol>0122.appendChild(<li>3)',
+ '<li>.appendChild(#text)',
+ '<ol>01223.appendChild(<li>4)',
+ // Remove 1 & 2 (replaced with null)
+ '<li>0.remove()',
+ '<li>1.remove()'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe([
+ // Insert 0 and 1
+ '<li>.appendChild(#text)',
+ '<ol>2234.insertBefore(<li>0, <li>2)',
+ '<li>.appendChild(#text)',
+ '<ol>02234.insertBefore(<li>1, <li>2)',
+ // Remove 3 & 4 (replaced by null)
+ '<li>3.remove()',
+ '<li>4.remove()'
+ ]);
+ });
+
+ it('should support nested conditional beginning and end Fragments', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ {condition ? (
+ <Fragment>
+ <Fragment>
+ <Fragment>
+ <li>0</li>
+ <li>1</li>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ ) : null}
+ <li>2</li>
+ <li>3</li>
+ {condition ? null : (
+ <Fragment>
+ <Fragment>
+ <Fragment>
+ <li>4</li>
+ <li>5</li>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ )}
+ </ol>
+ );
+
+ const htmlForTrue = ol([li(0), li(1), li(2), li(3)]);
+
+ const htmlForFalse = ol([li(2), li(3), li(4), li(5)]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(htmlForTrue, 'initial render of true');
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe([
+ // Mount 4 & 5
+ '<li>.appendChild(#text)',
+ '<ol>0123.appendChild(<li>4)',
+ '<li>.appendChild(#text)',
+ '<ol>01234.appendChild(<li>5)',
+ // Remove 1 & 2 (replaced with null)
+ '<li>0.remove()',
+ '<li>1.remove()'
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe([
+ // Insert 0 and 1 back into the DOM
+ '<li>.appendChild(#text)',
+ '<ol>2345.insertBefore(<li>0, <li>2)',
+ '<li>.appendChild(#text)',
+ '<ol>02345.insertBefore(<li>1, <li>2)',
+ // Remove 4 & 5 (replaced by null)
+ '<li>4.remove()',
+ '<li>5.remove()'
+ ]);
+ });
+
+ it('should preserve state with reordering in multiple levels with mixed # of Fragment siblings', () => {
+ // Also fails if the # of divs outside the Fragment equals or exceeds
+ // the # inside the Fragment for both conditions
+ function Foo({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment key="c">
+ <div>foo</div>
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ </Fragment>
+ <div>boop</div>
+ <div>boop</div>
+ </div>
+ ) : (
+ <div>
+ <div>beep</div>
+ <Fragment key="c">
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ <div>bar</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ const htmlForTrue = div([
+ div('foo'),
+ div(div('Hello')),
+ div('boop'),
+ div('boop')
+ ]);
+
+ const htmlForFalse = div([div('beep'), div(div('Hello')), div('bar')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe(
+ [
+ '<div>fooHellobeepboop.insertBefore(<div>Hello, <div>boop)',
+ '<div>barbeepHelloboop.insertBefore(<div>bar, <div>boop)',
+ '<div>boop.remove()'
+ ],
+ 'rendering from true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe(
+ [
+ '<div>beepHellofoo.insertBefore(<div>foo, <div>beep)',
+ '<div>fooboopHello.appendChild(<div>boop)',
+ '<div>.appendChild(#text)',
+ '<div>fooHelloboop.appendChild(<div>boop)'
+ ],
+ 'rendering from false to true'
+ );
+ });
+
+ it('should preserve state with reordering in multiple levels with lots of Fragment siblings', () => {
+ // Also fails if the # of divs outside the Fragment equals or exceeds
+ // the # inside the Fragment for both conditions
+ function Foo({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment key="c">
+ <div>foo</div>
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ </Fragment>
+ <div>boop</div>
+ <div>boop</div>
+ <div>boop</div>
+ </div>
+ ) : (
+ <div>
+ <div>beep</div>
+ <div>beep</div>
+ <div>beep</div>
+ <Fragment key="c">
+ <div key="b">
+ <Stateful key="a" />
+ </div>
+ <div>bar</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ const htmlForTrue = div([
+ div('foo'),
+ div(div('Hello')),
+ div('boop'),
+ div('boop'),
+ div('boop')
+ ]);
+
+ const htmlForFalse = div([
+ div('beep'),
+ div('beep'),
+ div('beep'),
+ div(div('Hello')),
+ div('bar')
+ ]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful']);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe(
+ [
+ '<div>fooHellobeepbeepbeep.appendChild(<div>Hello)',
+ '<div>barbeepbeepbeepHello.appendChild(<div>bar)'
+ ],
+ 'rendering from true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(ops).to.deep.equal(['Update Stateful', 'Update Stateful']);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe(
+ [
+ '<div>beepbeepbeepHellofoo.insertBefore(<div>foo, <div>beep)',
+ '<div>foobeepbeepbeepHello.insertBefore(<div>Hello, <div>beep)',
+ '<div>fooHelloboopboopboop.appendChild(<div>boop)'
+ ],
+ 'rendering from false to true'
+ );
+ });
+
+ it('should correctly append children with siblings', () => {
+ /**
+ * @type {(props: { values: Array<string | number>}) => JSX.Element}
+ */
+ const Foo = ({ values }) => (
+ <ol>
+ <li>a</li>
+ <Fragment>
+ {values.map(value => (
+ <li>{value}</li>
+ ))}
+ </Fragment>
+ <li>b</li>
+ </ol>
+ );
+
+ const getHtml = values =>
+ ol([li('a'), ...values.map(value => li(value)), li('b')]);
+
+ let values = [0, 1, 2];
+ clearLog();
+ render(<Foo values={values} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ getHtml(values),
+ `original list: [${values.join(',')}]`
+ );
+
+ values.push(3);
+
+ clearLog();
+ render(<Foo values={values} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ getHtml(values),
+ `push 3: [${values.join(',')}]`
+ );
+ expectDomLogToBe([
+ '<li>.appendChild(#text)',
+ '<ol>a012b.insertBefore(<li>3, <li>b)'
+ ]);
+
+ values.push(4);
+
+ clearLog();
+ render(<Foo values={values} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ getHtml(values),
+ `push 4: [${values.join(',')}]`
+ );
+ expectDomLogToBe([
+ '<li>.appendChild(#text)',
+ '<ol>a0123b.insertBefore(<li>4, <li>b)'
+ ]);
+ });
+
+ it('should render components that conditionally return Fragments', () => {
+ const Foo = ({ condition }) =>
+ condition ? (
+ <Fragment>
+ <div>1</div>
+ <div>2</div>
+ </Fragment>
+ ) : (
+ <div>
+ <div>3</div>
+ <div>4</div>
+ </div>
+ );
+
+ const htmlForTrue = [div(1), div(2)].join('');
+
+ const htmlForFalse = div([div(3), div(4)]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForTrue);
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForFalse);
+ expectDomLogToBe(
+ [
+ '<div>.appendChild(#text)',
+ '<div>1.insertBefore(<div>3, #text)',
+ '<div>.appendChild(#text)',
+ '<div>31.insertBefore(<div>4, #text)',
+ '#text.remove()',
+ '<div>2.remove()'
+ ],
+ 'rendering from true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForTrue);
+ expectDomLogToBe(
+ [
+ '<div>34.insertBefore(#text, <div>3)',
+ '<div>4.remove()',
+ '<div>3.remove()',
+ '<div>.appendChild(#text)',
+ '<div>1.appendChild(<div>2)'
+ ],
+ 'rendering from false to true'
+ );
+ });
+
+ it('should clear empty Fragments', () => {
+ function Foo(props) {
+ if (props.condition) {
+ return <Fragment>foo</Fragment>;
+ }
+ return <Fragment />;
+ }
+
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.textContent).to.equal('foo');
+
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.textContent).to.equal('');
+ });
+
+ it('should support conditionally rendered nested Fragments or null with siblings', () => {
+ const Foo = ({ condition }) => (
+ <ol>
+ <li>0</li>
+ <Fragment>
+ <li>1</li>
+ {condition ? (
+ <Fragment>
+ <li>2</li>
+ <li>3</li>
+ </Fragment>
+ ) : null}
+ <li>4</li>
+ </Fragment>
+ <li>5</li>
+ </ol>
+ );
+
+ const htmlForTrue = ol([
+ li('0'),
+ li('1'),
+ li('2'),
+ li('3'),
+ li('4'),
+ li('5')
+ ]);
+
+ const htmlForFalse = ol([li('0'), li('1'), li('4'), li('5')]);
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(htmlForTrue, 'initial render of true');
+ expectDomLogToBe(
+ [
+ '<li>.appendChild(#text)',
+ '<ol>.appendChild(<li>0)',
+ '<li>.appendChild(#text)',
+ '<ol>0.appendChild(<li>1)',
+ '<li>.appendChild(#text)',
+ '<ol>01.appendChild(<li>2)',
+ '<li>.appendChild(#text)',
+ '<ol>012.appendChild(<li>3)',
+ '<li>.appendChild(#text)',
+ '<ol>0123.appendChild(<li>4)',
+ '<li>.appendChild(#text)',
+ '<ol>01234.appendChild(<li>5)',
+ '<div>.appendChild(<ol>012345)'
+ ],
+ 'initial render of true'
+ );
+
+ clearLog();
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForFalse,
+ 'rendering from true to false'
+ );
+ expectDomLogToBe(
+ ['<li>2.remove()', '<li>3.remove()'],
+ 'rendering from true to false'
+ );
+
+ clearLog();
+ render(<Foo condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ htmlForTrue,
+ 'rendering from false to true'
+ );
+ expectDomLogToBe(
+ [
+ '<li>.appendChild(#text)',
+ '<ol>0145.insertBefore(<li>2, <li>4)',
+ '<li>.appendChild(#text)',
+ '<ol>01245.insertBefore(<li>3, <li>4)'
+ ],
+ 'rendering from false to true'
+ );
+ });
+
+ it('should render first child Fragment that wrap null components', () => {
+ const Empty = () => null;
+ const Foo = () => (
+ <ol>
+ <Fragment>
+ <Empty />
+ </Fragment>
+ <li>1</li>
+ </ol>
+ );
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal(ol(li(1)));
+ });
+
+ it('should properly render Components that return Fragments and use shouldComponentUpdate #1415', () => {
+ class SubList extends Component {
+ shouldComponentUpdate(nextProps) {
+ return nextProps.prop1 !== this.props.prop1;
+ }
+ render() {
+ return (
+ <Fragment>
+ <div>2</div>
+ <div>3</div>
+ </Fragment>
+ );
+ }
+ }
+
+ /** @type {(update: any) => void} */
+ let setState;
+ class App extends Component {
+ constructor() {
+ super();
+ setState = update => this.setState(update);
+
+ this.state = { error: false };
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.error ? (
+ <div>Error!</div>
+ ) : (
+ <div>
+ <div>1</div>
+ <SubList prop1={this.state.error} />
+ </div>
+ )}
+ </div>
+ );
+ }
+ }
+
+ const successHtml = div(div([div(1), div(2), div(3)]));
+
+ const errorHtml = div(div('Error!'));
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(successHtml);
+
+ setState({}); // Trigger sCU
+ rerender();
+ expect(scratch.innerHTML).to.equal(successHtml);
+
+ setState({ error: true });
+ rerender();
+ expect(scratch.innerHTML).to.equal(errorHtml);
+
+ setState({ error: false });
+ rerender();
+ expect(scratch.innerHTML).to.equal(successHtml);
+
+ setState({}); // Trigger sCU again
+ rerender();
+ expect(scratch.innerHTML).to.equal(successHtml);
+ });
+
+ it('should properly render Fragments whose last child is a component returning null', () => {
+ let Noop = () => null;
+ let update;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ items: ['A', 'B', 'C'] });
+ this.state = {
+ items: null
+ };
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.items && (
+ <Fragment>
+ {this.state.items.map(v => (
+ <div>{v}</div>
+ ))}
+ <Noop />
+ </Fragment>
+ )}
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('');
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.textContent).to.equal('ABC');
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>.appendChild(<div>A)',
+ '<div>.appendChild(#text)',
+ '<div>A.appendChild(<div>B)',
+ '<div>.appendChild(#text)',
+ '<div>AB.appendChild(<div>C)'
+ ]);
+ });
+
+ it('should replace node in-between children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? <section>B2</section> : <div>B1</div>;
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ <SetState />
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B1</div><div>C</div></div>`
+ );
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><section>B2</section><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<section>.appendChild(#text)',
+ '<div>AB1C.insertBefore(<section>B2, <div>B1)',
+ '<div>B1.remove()'
+ ]);
+ });
+
+ it('should replace Fragment in-between children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? (
+ <Fragment>
+ <section>B3</section>
+ <section>B4</section>
+ </Fragment>
+ ) : (
+ <Fragment>
+ <div>B1</div>
+ <div>B2</div>
+ </Fragment>
+ );
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ <SetState />
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(
+ div([div('A'), div('B1'), div('B2'), div('C')])
+ );
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ div([div('A'), section('B3'), section('B4'), div('C')])
+ );
+ expectDomLogToBe([
+ '<section>.appendChild(#text)',
+ '<div>AB1B2C.insertBefore(<section>B3, <div>B1)',
+ '<section>.appendChild(#text)',
+ '<div>AB3B1B2C.insertBefore(<section>B4, <div>B1)',
+ '<div>B2.remove()',
+ '<div>B1.remove()'
+ ]);
+ });
+
+ it('should insert in-between children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? <div>B</div> : null;
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ <SetState />
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B, <div>C)'
+ ]);
+ });
+
+ it('should insert in-between Fragments', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? [<div>B1</div>, <div>B2</div>] : null;
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ <SetState />
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B1</div><div>B2</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B1, <div>C)',
+ '<div>.appendChild(#text)',
+ '<div>AB1C.insertBefore(<div>B2, <div>C)'
+ ]);
+ });
+
+ it('should insert in-between null children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? <div>B</div> : null;
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ {null}
+ <SetState />
+ {null}
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B, <div>C)'
+ ]);
+ });
+
+ it('should insert Fragment in-between null children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? (
+ <Fragment>
+ <div>B1</div>
+ <div>B2</div>
+ </Fragment>
+ ) : null;
+ }
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ {null}
+ <SetState />
+ {null}
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B1</div><div>B2</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B1, <div>C)',
+ '<div>.appendChild(#text)',
+ '<div>AB1C.insertBefore(<div>B2, <div>C)'
+ ]);
+ });
+
+ it('should insert in-between nested null children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? <div>B</div> : null;
+ }
+ }
+
+ function Outer() {
+ return <SetState />;
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ {null}
+ <Outer />
+ {null}
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B, <div>C)'
+ ]);
+ });
+
+ it('should insert Fragment in-between nested null children', () => {
+ let update;
+ class SetState extends Component {
+ constructor(props) {
+ super(props);
+ update = () => this.setState({ active: true });
+ }
+
+ render() {
+ return this.state.active ? (
+ <Fragment>
+ <div>B1</div>
+ <div>B2</div>
+ </Fragment>
+ ) : null;
+ }
+ }
+
+ function Outer() {
+ return <SetState />;
+ }
+
+ render(
+ <div>
+ <div>A</div>
+ {null}
+ <Outer />
+ {null}
+ <div>C</div>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+
+ clearLog();
+ update();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B1</div><div>B2</div><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B1, <div>C)',
+ '<div>.appendChild(#text)',
+ '<div>AB1C.insertBefore(<div>B2, <div>C)'
+ ]);
+ });
+
+ it('should update at correct place', () => {
+ let updateA;
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: true };
+ updateA = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return this.state.active ? <div>A</div> : <span>A2</span>;
+ }
+ }
+
+ function B() {
+ return <div>B</div>;
+ }
+
+ function X(props) {
+ return props.children;
+ }
+
+ function App(props) {
+ let b = props.condition ? <B /> : null;
+ return (
+ <div>
+ <X>
+ <A />
+ </X>
+ <X>
+ {b}
+ <div>C</div>
+ </X>
+ </div>
+ );
+ }
+
+ render(<App condition={true} />, scratch);
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A</div><div>B</div><div>C</div></div>`
+ );
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.eql(`<div><div>A</div><div>C</div></div>`);
+ expectDomLogToBe(['<div>B.remove()']);
+
+ clearLog();
+ updateA();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(`<div><span>A2</span><div>C</div></div>`);
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>AC.insertBefore(<span>A2, <div>A)',
+ '<div>A.remove()'
+ ]);
+ });
+
+ it('should update Fragment at correct place', () => {
+ let updateA;
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: true };
+ updateA = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return this.state.active
+ ? [<div>A1</div>, <div>A2</div>]
+ : [<span>A3</span>, <span>A4</span>];
+ }
+ }
+
+ function B() {
+ return <div>B</div>;
+ }
+
+ function X(props) {
+ return props.children;
+ }
+
+ function App(props) {
+ let b = props.condition ? <B /> : null;
+ return (
+ <div>
+ <X>
+ <A />
+ </X>
+ <X>
+ {b}
+ <div>C</div>
+ </X>
+ </div>
+ );
+ }
+
+ render(<App condition={true} />, scratch);
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A1</div><div>A2</div><div>B</div><div>C</div></div>`
+ );
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><div>A1</div><div>A2</div><div>C</div></div>`
+ );
+ expectDomLogToBe(['<div>B.remove()']);
+
+ clearLog();
+ updateA();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ `<div><span>A3</span><span>A4</span><div>C</div></div>`
+ );
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>A1A2C.insertBefore(<span>A3, <div>A1)',
+ '<span>.appendChild(#text)',
+ '<div>A3A1A2C.insertBefore(<span>A4, <div>A1)',
+ '<div>A2.remove()',
+ '<div>A1.remove()'
+ ]);
+ });
+
+ it('should insert children correctly if sibling component DOM changes', () => {
+ /** @type {() => void} */
+ let updateA;
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: true };
+ updateA = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return this.state.active ? <div>A</div> : <span>A2</span>;
+ }
+ }
+
+ /** @type {() => void} */
+ let updateB;
+ class B extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: false };
+ updateB = () => this.setState(prev => ({ active: !prev.active }));
+ }
+ render() {
+ return this.state.active ? <div>B</div> : null;
+ }
+ }
+
+ function X(props) {
+ return props.children;
+ }
+
+ function App() {
+ return (
+ <div>
+ <X>
+ <A />
+ </X>
+ <X>
+ <B />
+ <div>C</div>
+ </X>
+ </div>
+ );
+ }
+
+ render(<App />, scratch);
+
+ expect(scratch.innerHTML).to.eql(div([div('A'), div('C')]), 'initial');
+
+ clearLog();
+ updateB();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ div([div('A'), div('B'), div('C')]),
+ 'updateB'
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>AC.insertBefore(<div>B, <div>C)'
+ ]);
+
+ clearLog();
+ updateA();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ div([span('A2'), div('B'), div('C')]),
+ 'updateA'
+ );
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>ABC.insertBefore(<span>A2, <div>A)',
+ '<div>A.remove()'
+ ]);
+ });
+
+ it('should correctly append children if last child changes DOM', () => {
+ /** @type {() => void} */
+ let updateA;
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: true };
+ updateA = () => this.setState(prev => ({ active: !prev.active }));
+ }
+
+ render() {
+ return this.state.active
+ ? [<div>A1</div>, <div>A2</div>]
+ : [<span>A3</span>, <span>A4</span>];
+ }
+ }
+
+ /** @type {() => void} */
+ let updateB;
+ class B extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { active: false };
+ updateB = () => this.setState(prev => ({ active: !prev.active }));
+ }
+ render() {
+ return (
+ <Fragment>
+ <A />
+ {this.state.active ? <div>B</div> : null}
+ </Fragment>
+ );
+ }
+ }
+
+ render(<B />, scratch);
+
+ expect(scratch.innerHTML).to.eql(
+ [div('A1'), div('A2')].join(''),
+ 'initial'
+ );
+
+ clearLog();
+ updateA();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ [span('A3'), span('A4')].join(''),
+ 'updateA'
+ );
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>A1A2.insertBefore(<span>A3, <div>A1)',
+ '<span>.appendChild(#text)',
+ '<div>A3A1A2.insertBefore(<span>A4, <div>A1)',
+ '<div>A2.remove()',
+ '<div>A1.remove()'
+ ]);
+
+ clearLog();
+ updateB();
+ rerender();
+
+ expect(scratch.innerHTML).to.eql(
+ [span('A3'), span('A4'), div('B')].join(''),
+ 'updateB'
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>A3A4.appendChild(<div>B)'
+ ]);
+ });
+
+ it('should properly place conditional elements around strictly equal vnodes', () => {
+ let set;
+
+ const Children = () => (
+ <Fragment>
+ <div>Navigation</div>
+ <div>Content</div>
+ </Fragment>
+ );
+
+ class Parent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { panelPosition: 'bottom' };
+ set = this.tooglePanelPosition = this.tooglePanelPosition.bind(this);
+ }
+
+ tooglePanelPosition() {
+ this.setState({
+ panelPosition: this.state.panelPosition === 'top' ? 'bottom' : 'top'
+ });
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.panelPosition === 'top' && <div>top panel</div>}
+ {this.props.children}
+ {this.state.panelPosition === 'bottom' && <div>bottom panel</div>}
+ </div>
+ );
+ }
+ }
+
+ const App = () => (
+ <Parent>
+ <Children />
+ </Parent>
+ );
+
+ const content = `<div>Navigation</div><div>Content</div>`;
+ const top = `<div><div>top panel</div>${content}</div>`;
+ const bottom = `<div>${content}<div>bottom panel</div></div>`;
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(bottom);
+
+ clearLog();
+ set();
+ rerender();
+ expect(scratch.innerHTML).to.equal(top);
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>NavigationContentbottom panel.insertBefore(<div>top panel, <div>Navigation)',
+ '<div>bottom panel.remove()'
+ ]);
+
+ clearLog();
+ set();
+ rerender();
+ expect(scratch.innerHTML).to.equal(bottom);
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>top panelNavigationContent.appendChild(<div>bottom panel)',
+ '<div>top panel.remove()'
+ ]);
+
+ clearLog();
+ set();
+ rerender();
+ expect(scratch.innerHTML).to.equal(top);
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>NavigationContentbottom panel.insertBefore(<div>top panel, <div>Navigation)',
+ '<div>bottom panel.remove()'
+ ]);
+ });
+
+ it('should efficiently unmount Fragment children', () => {
+ // <div>1 => <span>1 and Fragment sibling unmounts. Does <span>1 get correct _nextDom pointer?
+ function App({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment>
+ <div>1</div>
+ <div>2</div>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ </Fragment>
+ </div>
+ ) : (
+ <div>
+ <Fragment>
+ <div>1</div>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ render(<App condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(div([div(1), div(2), div('A')]));
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(div([div(1), div('A')]));
+ expectDomLogToBe(['<div>2.remove()']);
+ });
+
+ it('should efficiently unmount nested Fragment children', () => {
+ // Fragment wrapping <div>2 and <div>3 unmounts. Does <div>1 get correct
+ // _nextDom pointer to efficiently update DOM? _nextDom should be <div>A
+ function App({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment>
+ <div>1</div>
+ <Fragment>
+ <div>2</div>
+ <div>3</div>
+ </Fragment>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ ) : (
+ <div>
+ <Fragment>
+ <div>1</div>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ clearLog();
+ render(<App condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div(2), div(3), div('A'), div('B')])
+ );
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(div([div(1), div('A'), div('B')]));
+ expectDomLogToBe(['<div>2.remove()', '<div>3.remove()']);
+ });
+
+ it('should efficiently place new children and unmount nested Fragment children', () => {
+ // <div>4 is added and Fragment sibling unmounts. Does <div>4 get correct _nextDom pointer?
+ function App({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment>
+ <div>1</div>
+ <Fragment>
+ <div>2</div>
+ <div>3</div>
+ </Fragment>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ ) : (
+ <div>
+ <Fragment>
+ <div>1</div>
+ <div>4</div>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ render(<App condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div(2), div(3), div('A'), div('B')])
+ );
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div(4), div('A'), div('B')])
+ );
+ expectDomLogToBe([
+ '<div>.appendChild(#text)',
+ '<div>123AB.insertBefore(<div>4, <div>2)',
+ '<div>2.remove()',
+ '<div>3.remove()'
+ ]);
+ });
+
+ it('should efficiently unmount nested Fragment children when changing node type', () => {
+ // <div>1 => <span>1 and Fragment sibling unmounts. Does <span>1 get correct _nextDom pointer?
+ function App({ condition }) {
+ return condition ? (
+ <div>
+ <Fragment>
+ <div>1</div>
+ <Fragment>
+ <div>2</div>
+ <div>3</div>
+ </Fragment>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ ) : (
+ <div>
+ <Fragment>
+ <span>1</span>
+ </Fragment>
+ <Fragment>
+ <div>A</div>
+ <div>B</div>
+ </Fragment>
+ </div>
+ );
+ }
+
+ render(<App condition={true} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div(2), div(3), div('A'), div('B')])
+ );
+
+ clearLog();
+ render(<App condition={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(div([span(1), div('A'), div('B')]));
+ expectDomLogToBe([
+ '<span>.appendChild(#text)',
+ '<div>123AB.insertBefore(<span>1, <div>1)',
+ '<div>2.remove()',
+ '<div>3.remove()',
+ '<div>1.remove()'
+ ]);
+ });
+});
diff --git a/preact/test/browser/getDomSibling.test.js b/preact/test/browser/getDomSibling.test.js
new file mode 100644
index 0000000..8dc9b75
--- /dev/null
+++ b/preact/test/browser/getDomSibling.test.js
@@ -0,0 +1,362 @@
+import { createElement, render, Fragment } from '../../src/';
+import { getDomSibling } from '../../src/component';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('getDomSibling', () => {
+ /** @type {import('../../src/internal').PreactElement} */
+ let scratch;
+
+ const getRoot = dom => dom._children;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should find direct sibling', () => {
+ render(
+ <div>
+ <div>A</div>
+ <div>B</div>
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find direct text node sibling', () => {
+ render(
+ <div>
+ <div>A</div>B
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find nested text node sibling', () => {
+ render(
+ <div>
+ <Fragment>
+ <div>A</div>
+ </Fragment>
+ <Fragment>B</Fragment>
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find text node sibling with placeholder', () => {
+ render(<div>A{null}B</div>, scratch);
+ let vnode = getRoot(scratch)._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find sibling with placeholder', () => {
+ render(
+ <div key="parent">
+ <div key="A">A</div>
+ {null}
+ <div key="B">B</div>
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find sibling with nested placeholder', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <div key="A">A</div>
+ </Fragment>
+ <Fragment key="0.1">{null}</Fragment>
+ <Fragment key="0.2">
+ <div key="B">B</div>
+ </Fragment>
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find sibling in parent', () => {
+ render(
+ <div>
+ <Fragment>
+ <div>A</div>
+ </Fragment>
+ <div>B</div>
+ </div>,
+ scratch
+ );
+ let vnode = getRoot(scratch)._children[0]._children[0]._children[0];
+ expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find unrelated sibling from a DOM VNode', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <Fragment key="0.0.0">
+ <Fragment key="0.0.0.0">
+ <div key="A">A</div>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ <Fragment key="0.1">
+ <Fragment key="0.1.0" />
+ <Fragment key="0.1.1" />
+ <Fragment key="0.1.2" />
+ </Fragment>
+ <Fragment key="0.2">
+ <Fragment key="0.2.0" />
+ <Fragment key="0.2.1" />
+ <Fragment key="0.2.2">
+ <div key="B">B</div>
+ </Fragment>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0]._children[0]
+ ._children[0]._children[0];
+ expect(divAVNode.type).to.equal('div');
+ expect(getDomSibling(divAVNode)).to.equalNode(
+ scratch.firstChild.childNodes[1]
+ );
+ });
+
+ it('should find unrelated sibling from a Fragment VNode', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <Fragment key="0.0.0">
+ <Fragment key="0.0.0.0">
+ <div key="A">A</div>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ <Fragment key="0.1">
+ <Fragment key="0.1.0">
+ <div key="B">B</div>
+ </Fragment>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ let fragment = getRoot(scratch)._children[0]._children[0]._children[0]
+ ._children[0];
+ expect(fragment.type).to.equal(Fragment);
+ expect(getDomSibling(fragment)).to.equalNode(
+ scratch.firstChild.childNodes[1]
+ );
+ });
+
+ it('should find unrelated sibling from a Component VNode', () => {
+ const Foo = props => props.children;
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <Fragment key="0.0.0">
+ <Foo key="0.0.0.0">
+ <div key="A">A</div>
+ </Foo>
+ </Fragment>
+ </Fragment>
+ <Fragment key="0.1">
+ <Fragment key="0.1.0">
+ <div key="B">B</div>
+ </Fragment>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ let foo = getRoot(scratch)._children[0]._children[0]._children[0]
+ ._children[0];
+ expect(foo.type).to.equal(Foo);
+ expect(getDomSibling(foo)).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find sibling through components', () => {
+ const Foo = props => props.children;
+ render(
+ <div key="0">
+ <Foo key="0.0">
+ <div key="A">A</div>
+ </Foo>
+ <Foo key="0.1" />
+ <Foo key="0.2">
+ <Foo key="0.2.0">
+ <div key="B">B</div>
+ </Foo>
+ </Foo>
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0]._children[0];
+ expect(divAVNode.type).to.equal('div');
+ expect(getDomSibling(divAVNode)).to.equalNode(
+ scratch.firstChild.childNodes[1]
+ );
+ });
+
+ it('should find sibling rendered in Components that wrap JSX children', () => {
+ const Foo = props => <p key="p">{props.children}</p>;
+ render(
+ <div key="0">
+ <div key="A">A</div>
+ <Foo key="Foo">
+ <span key="span">a span</span>
+ </Foo>
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0];
+ expect(divAVNode.type).to.equal('div');
+
+ let sibling = getDomSibling(divAVNode);
+ expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should find sibling rendered in Components without JSX children', () => {
+ const Foo = props => <p key="p">A paragraph</p>;
+ render(
+ <div key="0">
+ <div key="A">A</div>
+ <Foo key="Foo" />
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0];
+ expect(divAVNode.type).to.equal('div');
+
+ let sibling = getDomSibling(divAVNode);
+ expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should climb through Components without JSX children', () => {
+ const divAVNode = <div key="A">A</div>;
+ const Foo = () => divAVNode;
+
+ render(
+ <div key="0">
+ <Foo key="Foo" />
+ <div key="B">B</div>
+ </div>,
+ scratch
+ );
+
+ let sibling = getDomSibling(divAVNode);
+ expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
+ });
+
+ it('should return null if last sibling', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <div key="A">A</div>
+ </Fragment>
+ <Fragment key="0.1">
+ <div key="B">B</div>
+ </Fragment>
+ <Fragment key="0.2">
+ <div key="C">C</div>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ const divCVNode = getRoot(scratch)._children[0]._children[2]._children[0];
+ expect(getDomSibling(divCVNode)).to.equal(null);
+ });
+
+ it('should return null if no sibling', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <Fragment key="0.0.0">
+ <Fragment key="0.0.0.0">
+ <div key="A">A</div>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ <Fragment key="0.1">
+ <Fragment key="0.1.0">{null}</Fragment>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0]._children[0]
+ ._children[0]._children[0];
+ expect(getDomSibling(divAVNode)).to.equal(null);
+ });
+
+ it('should return null if no sibling with lots of empty trees', () => {
+ render(
+ <div key="0">
+ <Fragment key="0.0">
+ <Fragment key="0.0.0">
+ <Fragment key="0.0.0.0">
+ <div key="A">A</div>
+ </Fragment>
+ </Fragment>
+ </Fragment>
+ <Fragment key="0.1">
+ <Fragment key="0.1.0" />
+ <Fragment key="0.1.1" />
+ <Fragment key="0.1.2" />
+ </Fragment>
+ <Fragment key="0.2">
+ <Fragment key="0.2.0" />
+ <Fragment key="0.2.1" />
+ <Fragment key="0.2.2">{null}</Fragment>
+ </Fragment>
+ </div>,
+ scratch
+ );
+
+ let divAVNode = getRoot(scratch)._children[0]._children[0]._children[0]
+ ._children[0]._children[0];
+ expect(getDomSibling(divAVNode)).to.equal(null);
+ });
+
+ it('should return null if current parent has no siblings (even if parent has siblings at same level)', () => {
+ let divAVNode = <div key="A">A</div>;
+
+ render(
+ <div key="0">
+ <div key="0.0">
+ <div key="0.0.0" />
+ {divAVNode}
+ <Fragment key="0.1.2" />
+ </div>
+ <div key="0.1">
+ <Fragment key="0.1.0" />
+ <div key="B">B</div>
+ </div>
+ </div>,
+ scratch
+ );
+
+ expect(getDomSibling(divAVNode)).to.equal(null);
+ });
+});
diff --git a/preact/test/browser/hydrate.test.js b/preact/test/browser/hydrate.test.js
new file mode 100644
index 0000000..5f6e537
--- /dev/null
+++ b/preact/test/browser/hydrate.test.js
@@ -0,0 +1,454 @@
+import { createElement, hydrate, Fragment } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ sortAttributes,
+ serializeHtml,
+ spyOnElementAttributes,
+ createEvent
+} from '../_util/helpers';
+import { ul, li, div } from '../_util/dom';
+import { logCall, clearLog, getLog } from '../_util/logCall';
+
+/** @jsx createElement */
+
+describe('hydrate()', () => {
+ /** @type {HTMLElement} */
+ let scratch;
+ let attributesSpy;
+
+ const List = ({ children }) => <ul>{children}</ul>;
+ const ListItem = ({ children, onClick = null }) => (
+ <li onClick={onClick}>{children}</li>
+ );
+
+ let resetAppendChild;
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+ let resetSetAttribute;
+ let resetRemoveAttribute;
+
+ before(() => {
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ resetRemove = logCall(Element.prototype, 'remove');
+ resetSetAttribute = logCall(Element.prototype, 'setAttribute');
+ resetRemoveAttribute = logCall(Element.prototype, 'removeAttribute');
+ });
+
+ after(() => {
+ resetAppendChild();
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ resetSetAttribute();
+ resetRemoveAttribute();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ attributesSpy = spyOnElementAttributes();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ clearLog();
+ });
+
+ it('should reuse existing DOM', () => {
+ const onClickSpy = sinon.spy();
+ const html = ul([li('1'), li('2'), li('3')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ hydrate(
+ <ul>
+ <li>1</li>
+ <li>2</li>
+ <li onClick={onClickSpy}>3</li>
+ </ul>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ expect(onClickSpy).not.to.have.been.called;
+
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+
+ expect(onClickSpy).to.have.been.called.calledOnce;
+ });
+
+ it('should reuse existing DOM when given components', () => {
+ const onClickSpy = sinon.spy();
+ const html = ul([li('1'), li('2'), li('3')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ hydrate(
+ <List>
+ <ListItem>1</ListItem>
+ <ListItem>2</ListItem>
+ <ListItem onClick={onClickSpy}>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ expect(onClickSpy).not.to.have.been.called;
+
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+
+ expect(onClickSpy).to.have.been.called.calledOnce;
+ });
+
+ it('should properly set event handlers to existing DOM when given components', () => {
+ const proto = Element.prototype;
+ sinon.spy(proto, 'addEventListener');
+
+ const clickHandlers = [sinon.spy(), sinon.spy(), sinon.spy()];
+
+ const html = ul([li('1'), li('2'), li('3')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ hydrate(
+ <List>
+ <ListItem onClick={clickHandlers[0]}>1</ListItem>
+ <ListItem onClick={clickHandlers[1]}>2</ListItem>
+ <ListItem onClick={clickHandlers[2]}>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ expect(proto.addEventListener).to.have.been.calledThrice;
+ expect(clickHandlers[2]).not.to.have.been.called;
+
+ scratch.querySelector('li:last-child').dispatchEvent(createEvent('click'));
+ expect(clickHandlers[2]).to.have.been.calledOnce;
+ });
+
+ it('should add missing nodes to existing DOM when hydrating', () => {
+ const html = ul([li('1')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ hydrate(
+ <List>
+ <ListItem>1</ListItem>
+ <ListItem>2</ListItem>
+ <ListItem>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(ul([li('1'), li('2'), li('3')]));
+ expect(getLog()).to.deep.equal([
+ '<li>.appendChild(#text)',
+ '<ul>1.appendChild(<li>2)',
+ '<li>.appendChild(#text)',
+ '<ul>12.appendChild(<li>3)'
+ ]);
+ });
+
+ it('should remove extra nodes from existing DOM when hydrating', () => {
+ const html = ul([li('1'), li('2'), li('3'), li('4')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ hydrate(
+ <List>
+ <ListItem>1</ListItem>
+ <ListItem>2</ListItem>
+ <ListItem>3</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(ul([li('1'), li('2'), li('3')]));
+ expect(getLog()).to.deep.equal(['<li>4.remove()']);
+ });
+
+ it('should not update attributes on existing DOM', () => {
+ scratch.innerHTML =
+ '<div><span before-hydrate="test" same-value="foo" different-value="a">Test</span></div>';
+ let vnode = (
+ <div>
+ <span same-value="foo" different-value="b" new-value="c">
+ Test
+ </span>
+ </div>
+ );
+
+ clearLog();
+ hydrate(vnode, scratch);
+
+ // IE11 doesn't support spying on Element.prototype
+ if (!/Trident/.test(navigator.userAgent)) {
+ expect(attributesSpy.get).to.not.have.been.called;
+ }
+
+ expect(serializeHtml(scratch)).to.equal(
+ sortAttributes(
+ '<div><span before-hydrate="test" different-value="a" same-value="foo">Test</span></div>'
+ )
+ );
+ expect(getLog()).to.deep.equal([]);
+ });
+
+ it('should update class attribute via className prop', () => {
+ scratch.innerHTML = '<div class="foo">bar</div>';
+ hydrate(<div className="foo">bar</div>, scratch);
+ expect(scratch.innerHTML).to.equal('<div class="foo">bar</div>');
+ });
+
+ it('should correctly hydrate with Fragments', () => {
+ const html = ul([li('1'), li('2'), li('3'), li('4')]);
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ const clickHandlers = [sinon.spy(), sinon.spy(), sinon.spy(), sinon.spy()];
+
+ hydrate(
+ <List>
+ <ListItem onClick={clickHandlers[0]}>1</ListItem>
+ <Fragment>
+ <ListItem onClick={clickHandlers[1]}>2</ListItem>
+ <ListItem onClick={clickHandlers[2]}>3</ListItem>
+ </Fragment>
+ <ListItem onClick={clickHandlers[3]}>4</ListItem>
+ </List>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ expect(clickHandlers[2]).not.to.have.been.called;
+
+ scratch
+ .querySelector('li:nth-child(3)')
+ .dispatchEvent(createEvent('click'));
+
+ expect(clickHandlers[2]).to.have.been.called.calledOnce;
+ });
+
+ it('should correctly hydrate root Fragments', () => {
+ const html = [
+ ul([li('1'), li('2'), li('3'), li('4')]),
+ div('sibling')
+ ].join('');
+
+ scratch.innerHTML = html;
+ clearLog();
+
+ const clickHandlers = [
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy(),
+ sinon.spy()
+ ];
+
+ hydrate(
+ <Fragment>
+ <List>
+ <Fragment>
+ <ListItem onClick={clickHandlers[0]}>1</ListItem>
+ <ListItem onClick={clickHandlers[1]}>2</ListItem>
+ </Fragment>
+ <ListItem onClick={clickHandlers[2]}>3</ListItem>
+ <ListItem onClick={clickHandlers[3]}>4</ListItem>
+ </List>
+ <div onClick={clickHandlers[4]}>sibling</div>
+ </Fragment>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(html);
+ expect(getLog()).to.deep.equal([]);
+ expect(clickHandlers[2]).not.to.have.been.called;
+
+ scratch
+ .querySelector('li:nth-child(3)')
+ .dispatchEvent(createEvent('click'));
+
+ expect(clickHandlers[2]).to.have.been.calledOnce;
+ expect(clickHandlers[4]).not.to.have.been.called;
+
+ scratch.querySelector('div').dispatchEvent(createEvent('click'));
+
+ expect(clickHandlers[2]).to.have.been.calledOnce;
+ expect(clickHandlers[4]).to.have.been.calledOnce;
+ });
+
+ // Failing because the following condition in diffElementNodes doesn't evaluate to true
+ // when hydrating a dom node which is not correct
+ // dom===d && newVNode.text!==oldVNode.text
+ // We don't set `d` when hydrating. If we did, then newVNode.text would never equal
+ // oldVNode.text since oldVNode is always EMPTY_OBJ when hydrating
+ it.skip('should override incorrect pre-existing DOM with VNodes passed into render', () => {
+ const initialHtml = [
+ div('sibling'),
+ ul([li('1'), li('4'), li('3'), li('2')])
+ ].join('');
+
+ scratch.innerHTML = initialHtml;
+ clearLog();
+
+ hydrate(
+ <Fragment>
+ <List>
+ <Fragment>
+ <ListItem>1</ListItem>
+ <ListItem>2</ListItem>
+ </Fragment>
+ <ListItem>3</ListItem>
+ <ListItem>4</ListItem>
+ </List>
+ <div>sibling</div>
+ </Fragment>,
+ scratch
+ );
+
+ const finalHtml = [
+ ul([li('1'), li('2'), li('3'), li('4')]),
+ div('sibling')
+ ].join('');
+
+ expect(scratch.innerHTML).to.equal(finalHtml);
+ // TODO: Fill in with proper log once this test is passing
+ expect(getLog()).to.deep.equal([]);
+ });
+
+ it('should not merge attributes with node created by the DOM', () => {
+ const html = htmlString => {
+ const div = document.createElement('div');
+ div.innerHTML = htmlString;
+ return div.firstChild;
+ };
+
+ // prettier-ignore
+ const DOMElement = html`<div><a foo="bar"></a></div>`;
+ scratch.appendChild(DOMElement);
+
+ const preactElement = (
+ <div>
+ <a />
+ </div>
+ );
+
+ hydrate(preactElement, scratch);
+ // IE11 doesn't support spies on built-in prototypes
+ if (!/Trident/.test(navigator.userAgent)) {
+ expect(attributesSpy.get).to.not.have.been.called;
+ }
+ expect(scratch).to.have.property(
+ 'innerHTML',
+ '<div><a foo="bar"></a></div>'
+ );
+ });
+
+ it('should attach event handlers', () => {
+ let spy = sinon.spy();
+ scratch.innerHTML = '<span>Test</span>';
+ let vnode = <span onClick={spy}>Test</span>;
+
+ hydrate(vnode, scratch);
+
+ scratch.firstChild.click();
+ expect(spy).to.be.calledOnce;
+ });
+
+ // #2237
+ it('should not redundantly add text nodes', () => {
+ scratch.innerHTML = '<div id="test"><p>hello bar</p></div>';
+ const element = document.getElementById('test');
+ const Component = props => <p>hello {props.foo}</p>;
+
+ hydrate(<Component foo="bar" />, element);
+ expect(element.innerHTML).to.equal('<p>hello bar</p>');
+ });
+
+ it('should not remove values', () => {
+ scratch.innerHTML =
+ '<select><option value="0">Zero</option><option selected value="2">Two</option></select>';
+ const App = () => {
+ const options = [
+ {
+ value: '0',
+ label: 'Zero'
+ },
+ {
+ value: '2',
+ label: 'Two'
+ }
+ ];
+
+ return (
+ <select value="2">
+ {options.map(({ disabled, label, value }) => (
+ <option key={label} disabled={disabled} value={value}>
+ {label}
+ </option>
+ ))}
+ </select>
+ );
+ };
+
+ hydrate(<App />, scratch);
+ expect(sortAttributes(scratch.innerHTML)).to.equal(
+ sortAttributes(
+ '<select><option value="0">Zero</option><option selected="" value="2">Two</option></select>'
+ )
+ );
+ });
+
+ it('should deopt for trees introduced in hydrate (append)', () => {
+ scratch.innerHTML = '<div id="test"><p class="hi">hello bar</p></div>';
+ const Component = props => <p class="hi">hello {props.foo}</p>;
+ const element = document.getElementById('test');
+ hydrate(
+ <Fragment>
+ <Component foo="bar" />
+ <Component foo="baz" />
+ </Fragment>,
+ element
+ );
+ expect(element.innerHTML).to.equal(
+ '<p class="hi">hello bar</p><p class="hi">hello baz</p>'
+ );
+ });
+
+ it('should deopt for trees introduced in hydrate (insert before)', () => {
+ scratch.innerHTML = '<div id="test"><p class="hi">hello bar</p></div>';
+ const Component = props => <p class="hi">hello {props.foo}</p>;
+ const element = document.getElementById('test');
+ hydrate(
+ <Fragment>
+ <Component foo="baz" />
+ <Component foo="bar" />
+ </Fragment>,
+ element
+ );
+ expect(element.innerHTML).to.equal(
+ '<p class="hi">hello baz</p><p class="hi">hello bar</p>'
+ );
+ });
+
+ it('should skip comment nodes', () => {
+ scratch.innerHTML = '<p>hello <!-- c -->foo</p>';
+ hydrate(<p>hello {'foo'}</p>, scratch);
+ expect(scratch.innerHTML).to.equal('<p>hello foo</p>');
+ });
+});
diff --git a/preact/test/browser/isValidElement.test.js b/preact/test/browser/isValidElement.test.js
new file mode 100644
index 0000000..fe2e6a0
--- /dev/null
+++ b/preact/test/browser/isValidElement.test.js
@@ -0,0 +1,4 @@
+import { createElement, isValidElement, Component } from 'preact';
+import { isValidElementTests } from '../shared/isValidElementTests';
+
+isValidElementTests(expect, isValidElement, createElement, Component);
diff --git a/preact/test/browser/keys.test.js b/preact/test/browser/keys.test.js
new file mode 100644
index 0000000..7f6c0e8
--- /dev/null
+++ b/preact/test/browser/keys.test.js
@@ -0,0 +1,627 @@
+import { createElement, Component, render } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+import { logCall, clearLog, getLog } from '../_util/logCall';
+import { div } from '../_util/dom';
+
+/** @jsx createElement */
+
+describe('keys', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {string[]} */
+ let ops;
+
+ function createStateful(name) {
+ return class Stateful extends Component {
+ componentDidUpdate() {
+ ops.push(`Update ${name}`);
+ }
+ componentDidMount() {
+ ops.push(`Mount ${name}`);
+ }
+ componentWillUnmount() {
+ ops.push(`Unmount ${name}`);
+ }
+ render() {
+ return <div>{name}</div>;
+ }
+ };
+ }
+
+ /** @type {(props: {values: any[]}) => any} */
+ const List = props => (
+ <ol>
+ {props.values.map(value => (
+ <li key={value}>{value}</li>
+ ))}
+ </ol>
+ );
+
+ /**
+ * Move an element in an array from one index to another
+ * @param {any[]} values The array of values
+ * @param {number} from The index to move from
+ * @param {number} to The index to move to
+ */
+ function move(values, from, to) {
+ const value = values[from];
+ values.splice(from, 1);
+ values.splice(to, 0, value);
+ }
+
+ let resetAppendChild;
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+
+ before(() => {
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ resetRemove = logCall(Element.prototype, 'remove');
+ });
+
+ after(() => {
+ resetAppendChild();
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ ops = [];
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ clearLog();
+ });
+
+ // https://fb.me/react-special-props
+ it('should not pass key in props', () => {
+ const Foo = sinon.spy(() => null);
+ render(<Foo key="foo" />, scratch);
+ expect(Foo.args[0][0]).to.deep.equal({});
+ });
+
+ // See preactjs/preact-compat#21
+ it('should remove orphaned keyed nodes', () => {
+ render(
+ <div>
+ <div>1</div>
+ <li key="a">a</li>
+ <li key="b">b</li>
+ </div>,
+ scratch
+ );
+
+ render(
+ <div>
+ <div>2</div>
+ <li key="b">b</li>
+ <li key="c">c</li>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>2</div><li>b</li><li>c</li></div>'
+ );
+ });
+
+ it('should remove keyed nodes (#232)', () => {
+ class App extends Component {
+ componentDidMount() {
+ setTimeout(() => this.setState({ opened: true, loading: true }), 10);
+ setTimeout(() => this.setState({ opened: true, loading: false }), 20);
+ }
+
+ render({ opened, loading }) {
+ return (
+ <BusyIndicator id="app" busy={loading}>
+ <div>This div needs to be here for this to break</div>
+ {opened && !loading && <div>{[]}</div>}
+ </BusyIndicator>
+ );
+ }
+ }
+
+ class BusyIndicator extends Component {
+ render({ children, busy }) {
+ return (
+ <div class={busy ? 'busy' : ''}>
+ {children && children.length ? (
+ children
+ ) : (
+ <div class="busy-placeholder" />
+ )}
+ <div class="indicator">
+ <div>indicator</div>
+ <div>indicator</div>
+ <div>indicator</div>
+ </div>
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ render(<App opened loading />, scratch);
+ render(<App opened />, scratch);
+
+ const html = String(scratch.firstChild.innerHTML).replace(/ class=""/g, '');
+ expect(html).to.equal(
+ '<div>This div needs to be here for this to break</div><div></div><div class="indicator"><div>indicator</div><div>indicator</div><div>indicator</div></div>'
+ );
+ });
+
+ it('should append new keyed elements', () => {
+ const values = ['a', 'b'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('ab');
+
+ values.push('c');
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abc');
+ expect(getLog()).to.deep.equal([
+ '<li>.appendChild(#text)',
+ '<ol>ab.appendChild(<li>c)'
+ ]);
+ });
+
+ it('should remove keyed elements from the end', () => {
+ const values = ['a', 'b', 'c', 'd'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd');
+
+ values.pop();
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abc');
+ expect(getLog()).to.deep.equal(['<li>d.remove()']);
+ });
+
+ it('should prepend keyed elements to the beginning', () => {
+ const values = ['b', 'c'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('bc');
+
+ values.unshift('a');
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abc');
+ expect(getLog()).to.deep.equal([
+ '<li>.appendChild(#text)',
+ '<ol>bc.insertBefore(<li>a, <li>b)'
+ ]);
+ });
+
+ it('should remove keyed elements from the beginning', () => {
+ const values = ['z', 'a', 'b', 'c'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('zabc');
+
+ values.shift();
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abc');
+ expect(getLog()).to.deep.equal(['<li>z.remove()']);
+ });
+
+ it('should insert new keyed children in the middle', () => {
+ const values = ['a', 'c'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('ac');
+
+ values.splice(1, 0, 'b');
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abc');
+ expect(getLog()).to.deep.equal([
+ '<li>.appendChild(#text)',
+ '<ol>ac.insertBefore(<li>b, <li>c)'
+ ]);
+ });
+
+ it('should remove keyed children from the middle', () => {
+ const values = ['a', 'b', 'x', 'y', 'z', 'c', 'd'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abxyzcd');
+
+ values.splice(2, 3);
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd');
+ expect(getLog()).to.deep.equal([
+ '<li>z.remove()',
+ '<li>y.remove()',
+ '<li>x.remove()'
+ ]);
+ });
+
+ it('should swap keyed children efficiently', () => {
+ render(<List values={['a', 'b']} />, scratch);
+ expect(scratch.textContent).to.equal('ab');
+
+ clearLog();
+
+ render(<List values={['b', 'a']} />, scratch);
+ expect(scratch.textContent).to.equal('ba');
+
+ expect(getLog()).to.deep.equal(['<ol>ab.appendChild(<li>a)']);
+ });
+
+ it('should swap existing keyed children in the middle of a list efficiently', () => {
+ const values = ['a', 'b', 'c', 'd'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd');
+
+ // swap
+ move(values, 1, 2);
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('acbd', 'initial swap');
+ expect(getLog()).to.deep.equal(
+ ['<ol>abcd.insertBefore(<li>b, <li>d)'],
+ 'initial swap'
+ );
+
+ // swap back
+ move(values, 2, 1);
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd', 'swap back');
+ expect(getLog()).to.deep.equal(
+ ['<ol>acbd.insertBefore(<li>c, <li>d)'],
+ 'swap back'
+ );
+ });
+
+ it('should move keyed children to the end of the list', () => {
+ const values = ['a', 'b', 'c', 'd'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd');
+
+ // move to end
+ move(values, 0, values.length - 1);
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('bcda', 'move to end');
+ expect(getLog()).to.deep.equal(
+ ['<ol>abcd.appendChild(<li>a)'],
+ 'move to end'
+ );
+
+ // move to beginning
+ move(values, values.length - 1, 0);
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal('abcd', 'move to beginning');
+ expect(getLog()).to.deep.equal(
+ ['<ol>bcda.insertBefore(<li>a, <li>b)'],
+ 'move to beginning'
+ );
+ });
+
+ it('should reverse keyed children effectively', () => {
+ const values = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal(values.join(''));
+
+ // reverse list
+ values.reverse();
+ clearLog();
+
+ render(<List values={values} />, scratch);
+ expect(scratch.textContent).to.equal(values.join(''));
+ expect(getLog()).to.deep.equal([
+ '<ol>abcdefghij.insertBefore(<li>j, <li>a)',
+ '<ol>jabcdefghi.insertBefore(<li>i, <li>a)',
+ '<ol>jiabcdefgh.insertBefore(<li>h, <li>a)',
+ '<ol>jihabcdefg.insertBefore(<li>g, <li>a)',
+ '<ol>jihgabcdef.appendChild(<li>e)',
+ '<ol>jihgabcdfe.appendChild(<li>d)',
+ '<ol>jihgabcfed.appendChild(<li>c)',
+ '<ol>jihgabfedc.appendChild(<li>b)',
+ '<ol>jihgafedcb.appendChild(<li>a)'
+ ]);
+ });
+
+ it("should not preserve state when a component's keys are different", () => {
+ const Stateful = createStateful('Stateful');
+
+ function Foo({ condition }) {
+ return condition ? <Stateful key="a" /> : <Stateful key="b" />;
+ }
+
+ ops = [];
+ render(<Foo condition />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(['Mount Stateful'], 'initial mount');
+
+ ops = [];
+ render(<Foo condition={false} />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(
+ ['Unmount Stateful', 'Mount Stateful'],
+ 'switching keys 1'
+ );
+
+ ops = [];
+ render(<Foo condition />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(
+ ['Unmount Stateful', 'Mount Stateful'],
+ 'switching keys 2'
+ );
+ });
+
+ it('should not preserve state between an unkeyed and keyed component', () => {
+ // React and Preact v8 behavior: https://codesandbox.io/s/57prmy5mx
+
+ const Stateful = createStateful('Stateful');
+
+ function Foo({ keyed }) {
+ return keyed ? <Stateful key="a" /> : <Stateful />;
+ }
+
+ ops = [];
+ render(<Foo keyed />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(['Mount Stateful'], 'initial mount with key');
+
+ ops = [];
+ render(<Foo keyed={false} />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(
+ ['Unmount Stateful', 'Mount Stateful'],
+ 'switching from keyed to unkeyed'
+ );
+
+ ops = [];
+ render(<Foo keyed />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Stateful</div>');
+ expect(ops).to.deep.equal(
+ ['Unmount Stateful', 'Mount Stateful'],
+ 'switching from unkeyed to keyed'
+ );
+ });
+
+ it('should not preserve state when keys change with multiple children', () => {
+ // React & Preact v8 behavior: https://codesandbox.io/s/8l3p6lz9kj
+
+ const Stateful1 = createStateful('Stateful1');
+ const Stateful2 = createStateful('Stateful2');
+
+ let Stateful1Ref;
+ let Stateful2Ref;
+ let Stateful1MovedRef;
+ let Stateful2MovedRef;
+
+ function Foo({ moved }) {
+ return moved ? (
+ <div>
+ <div>1</div>
+ <Stateful1 key="c" ref={c => (Stateful1MovedRef = c)} />
+ <div>2</div>
+ <Stateful2 key="d" ref={c => (Stateful2MovedRef = c)} />
+ </div>
+ ) : (
+ <div>
+ <div>1</div>
+ <Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
+ <div>2</div>
+ <Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
+ </div>
+ );
+ }
+
+ const expectedHtml = div([
+ div(1),
+ div('Stateful1'),
+ div(2),
+ div('Stateful2')
+ ]);
+
+ ops = [];
+ render(<Foo moved={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal(['Mount Stateful1', 'Mount Stateful2']);
+ expect(Stateful1Ref).to.exist;
+ expect(Stateful2Ref).to.exist;
+
+ ops = [];
+ render(<Foo moved />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal([
+ 'Unmount Stateful2',
+ 'Unmount Stateful1',
+ 'Mount Stateful1',
+ 'Mount Stateful2'
+ ]);
+ expect(Stateful1MovedRef).to.not.equal(Stateful1Ref);
+ expect(Stateful2MovedRef).to.not.equal(Stateful2Ref);
+
+ ops = [];
+ render(<Foo moved={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal([
+ 'Unmount Stateful2',
+ 'Unmount Stateful1',
+ 'Mount Stateful1',
+ 'Mount Stateful2'
+ ]);
+ expect(Stateful1Ref).to.not.equal(Stateful1MovedRef);
+ expect(Stateful2Ref).to.not.equal(Stateful2MovedRef);
+ });
+
+ it('should preserve state when moving keyed children components', () => {
+ // React & Preact v8 behavior: https://codesandbox.io/s/8l3p6lz9kj
+
+ const Stateful1 = createStateful('Stateful1');
+ const Stateful2 = createStateful('Stateful2');
+
+ let Stateful1Ref;
+ let Stateful2Ref;
+ let Stateful1MovedRef;
+ let Stateful2MovedRef;
+
+ function Foo({ moved }) {
+ return moved ? (
+ <div>
+ <div>1</div>
+ <Stateful2
+ key="b"
+ ref={c => (c ? (Stateful2MovedRef = c) : undefined)}
+ />
+ <div>2</div>
+ <Stateful1
+ key="a"
+ ref={c => (c ? (Stateful1MovedRef = c) : undefined)}
+ />
+ </div>
+ ) : (
+ <div>
+ <div>1</div>
+ <Stateful1 key="a" ref={c => (c ? (Stateful1Ref = c) : undefined)} />
+ <div>2</div>
+ <Stateful2 key="b" ref={c => (c ? (Stateful2Ref = c) : undefined)} />
+ </div>
+ );
+ }
+
+ const htmlForFalse = div([
+ div(1),
+ div('Stateful1'),
+ div(2),
+ div('Stateful2')
+ ]);
+
+ const htmlForTrue = div([
+ div(1),
+ div('Stateful2'),
+ div(2),
+ div('Stateful1')
+ ]);
+
+ ops = [];
+ render(<Foo moved={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForFalse);
+ expect(ops).to.deep.equal(['Mount Stateful1', 'Mount Stateful2']);
+ expect(Stateful1Ref).to.exist;
+ expect(Stateful2Ref).to.exist;
+
+ ops = [];
+ render(<Foo moved />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForTrue);
+ expect(ops).to.deep.equal(['Update Stateful2', 'Update Stateful1']);
+ expect(Stateful1MovedRef).to.equal(Stateful1Ref);
+ expect(Stateful2MovedRef).to.equal(Stateful2Ref);
+
+ ops = [];
+ render(<Foo moved={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(htmlForFalse);
+ expect(ops).to.deep.equal(['Update Stateful1', 'Update Stateful2']);
+ expect(Stateful1Ref).to.equal(Stateful1MovedRef);
+ expect(Stateful2Ref).to.equal(Stateful2MovedRef);
+ });
+
+ it('should not preserve state when switching between keyed and unkeyed components as children', () => {
+ // React & Preact v8 behavior: https://codesandbox.io/s/8l3p6lz9kj
+
+ const Stateful1 = createStateful('Stateful1');
+ const Stateful2 = createStateful('Stateful2');
+
+ let Stateful1Ref;
+ let Stateful2Ref;
+ let Stateful1MovedRef;
+ let Stateful2MovedRef;
+
+ function Foo({ unkeyed }) {
+ return unkeyed ? (
+ <div>
+ <div>1</div>
+ <Stateful1 ref={c => (Stateful2MovedRef = c)} />
+ <div>2</div>
+ <Stateful2 ref={c => (Stateful1MovedRef = c)} />
+ </div>
+ ) : (
+ <div>
+ <div>1</div>
+ <Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
+ <div>2</div>
+ <Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
+ </div>
+ );
+ }
+
+ const expectedHtml = div([
+ div(1),
+ div('Stateful1'),
+ div(2),
+ div('Stateful2')
+ ]);
+
+ ops = [];
+ render(<Foo unkeyed={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal(['Mount Stateful1', 'Mount Stateful2']);
+ expect(Stateful1Ref).to.exist;
+ expect(Stateful2Ref).to.exist;
+
+ ops = [];
+ render(<Foo unkeyed />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal([
+ 'Unmount Stateful2',
+ 'Unmount Stateful1',
+ 'Mount Stateful1',
+ 'Mount Stateful2'
+ ]);
+ expect(Stateful1MovedRef).to.not.equal(Stateful1Ref);
+ expect(Stateful2MovedRef).to.not.equal(Stateful2Ref);
+
+ ops = [];
+ render(<Foo unkeyed={false} />, scratch);
+
+ expect(scratch.innerHTML).to.equal(expectedHtml);
+ expect(ops).to.deep.equal([
+ 'Unmount Stateful2',
+ 'Unmount Stateful1',
+ 'Mount Stateful1',
+ 'Mount Stateful2'
+ ]);
+ expect(Stateful1Ref).to.not.equal(Stateful1MovedRef);
+ expect(Stateful2Ref).to.not.equal(Stateful2MovedRef);
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentDidCatch.test.js b/preact/test/browser/lifecycles/componentDidCatch.test.js
new file mode 100644
index 0000000..6587dd6
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentDidCatch.test.js
@@ -0,0 +1,672 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, Fragment } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /* eslint-disable react/display-name */
+
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentDidCatch', () => {
+ /** @type {Error} */
+ let expectedError;
+
+ /** @type {typeof import('../../../').Component} */
+ let ThrowErr;
+ class Receiver extends Component {
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+
+ render() {
+ return this.state.error
+ ? String(this.state.error)
+ : this.props.children;
+ }
+ }
+
+ let thrower;
+
+ sinon.spy(Receiver.prototype, 'componentDidCatch');
+ sinon.spy(Receiver.prototype, 'render');
+
+ function throwExpectedError() {
+ throw (expectedError = new Error('Error!'));
+ }
+
+ beforeEach(() => {
+ ThrowErr = class ThrowErr extends Component {
+ constructor(props) {
+ super(props);
+ thrower = this;
+ }
+
+ componentDidCatch() {
+ expect.fail("Throwing component should not catch it's own error.");
+ }
+ render() {
+ return <div>ThrowErr: componentDidCatch</div>;
+ }
+ };
+ sinon.spy(ThrowErr.prototype, 'componentDidCatch');
+
+ expectedError = undefined;
+
+ Receiver.prototype.componentDidCatch.resetHistory();
+ Receiver.prototype.render.resetHistory();
+ });
+
+ afterEach(() => {
+ expect(
+ ThrowErr.prototype.componentDidCatch,
+ "Throwing component should not catch it's own error."
+ ).to.not.be.called;
+ thrower = undefined;
+ });
+
+ it('should be called when child fails in constructor', () => {
+ class ThrowErr extends Component {
+ constructor(props, context) {
+ super(props, context);
+ throwExpectedError();
+ }
+ componentDidCatch() {
+ expect.fail("Throwing component should not catch it's own error");
+ }
+ render() {
+ return <div />;
+ }
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ // https://github.com/preactjs/preact/issues/1570
+ it('should handle double child throws', () => {
+ const Child = ({ i }) => {
+ throw new Error(`error! ${i}`);
+ };
+
+ const fn = () =>
+ render(
+ <Receiver>
+ {[1, 2].map(i => (
+ <Child key={i} i={i} />
+ ))}
+ </Receiver>,
+ scratch
+ );
+ expect(fn).to.not.throw();
+
+ rerender();
+ expect(scratch.innerHTML).to.equal('Error: error! 2');
+ });
+
+ it('should be called when child fails in componentWillMount', () => {
+ ThrowErr.prototype.componentWillMount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in render', () => {
+ ThrowErr.prototype.render = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentDidMount', () => {
+ ThrowErr.prototype.componentDidMount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in getDerivedStateFromProps', () => {
+ ThrowErr.getDerivedStateFromProps = throwExpectedError;
+
+ sinon.spy(ThrowErr.prototype, 'render');
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ expect(ThrowErr.prototype.render).not.to.have.been.called;
+ });
+
+ it('should be called when child fails in getSnapshotBeforeUpdate', () => {
+ ThrowErr.prototype.getSnapshotBeforeUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ thrower.forceUpdate();
+ rerender();
+
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentDidUpdate', () => {
+ ThrowErr.prototype.componentDidUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ thrower.forceUpdate();
+ rerender();
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillUpdate', () => {
+ ThrowErr.prototype.componentWillUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ thrower.forceUpdate();
+ rerender();
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillReceiveProps', () => {
+ ThrowErr.prototype.componentWillReceiveProps = throwExpectedError;
+
+ let receiver;
+ class Receiver extends Component {
+ constructor() {
+ super();
+ this.state = { foo: 'bar' };
+ receiver = this;
+ }
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <ThrowErr foo={this.state.foo} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver.prototype, 'componentDidCatch');
+ render(<Receiver />, scratch);
+
+ receiver.setState({ foo: 'baz' });
+ rerender();
+
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in shouldComponentUpdate', () => {
+ ThrowErr.prototype.shouldComponentUpdate = throwExpectedError;
+
+ let receiver;
+ class Receiver extends Component {
+ constructor() {
+ super();
+ this.state = { foo: 'bar' };
+ receiver = this;
+ }
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <ThrowErr foo={this.state.foo} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver.prototype, 'componentDidCatch');
+ render(<Receiver />, scratch);
+
+ receiver.setState({ foo: 'baz' });
+ rerender();
+
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillUnmount', () => {
+ ThrowErr.prototype.componentWillUnmount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ render(
+ <Receiver>
+ <div />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when applying a Component ref', () => {
+ const Foo = () => <div />;
+
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ // In React, an error boundary handles it's own refs:
+ // https://codesandbox.io/s/react-throwing-refs-lk958
+ class Receiver extends Component {
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <Foo ref={ref} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver.prototype, 'componentDidCatch');
+ render(<Receiver />, scratch);
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when applying a DOM ref', () => {
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ // In React, an error boundary handles it's own refs:
+ // https://codesandbox.io/s/react-throwing-refs-lk958
+ class Receiver extends Component {
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <div ref={ref} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver.prototype, 'componentDidCatch');
+ render(<Receiver />, scratch);
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when unmounting a ref', () => {
+ const ref = value => {
+ if (value == null) {
+ throwExpectedError();
+ }
+ };
+
+ ThrowErr.prototype.render = () => <div ref={ref} />;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ render(
+ <Receiver>
+ <div />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledOnceWith(
+ expectedError
+ );
+ });
+
+ it('should be called when functional child fails', () => {
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child inside a Fragment fails', () => {
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ render(
+ <Receiver>
+ <Fragment>
+ <ThrowErr />
+ </Fragment>
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should re-render with new content', () => {
+ class ThrowErr extends Component {
+ componentWillMount() {
+ throw new Error('Error contents');
+ }
+ render() {
+ return 'No error!?!?';
+ }
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+ expect(scratch).to.have.property('textContent', 'Error: Error contents');
+ });
+
+ it('should be able to adapt and rethrow errors', () => {
+ let adaptedError;
+ class Adapter extends Component {
+ componentDidCatch(error) {
+ throw (adaptedError = new Error(
+ 'Adapted ' +
+ String(error && 'message' in error ? error.message : error)
+ ));
+ }
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(Adapter.prototype, 'componentDidCatch');
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+
+ expect(Adapter.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ adaptedError
+ );
+
+ rerender();
+ expect(scratch).to.have.property('textContent', 'Error: Adapted Error!');
+ });
+
+ it('should bubble on repeated errors', () => {
+ class Adapter extends Component {
+ componentDidCatch(error) {
+ // Try to handle the error
+ this.setState({ error });
+ }
+ render() {
+ // But fail at doing so
+ if (this.state.error) {
+ throw this.state.error;
+ }
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(Adapter.prototype, 'componentDidCatch');
+
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Adapter.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should bubble on ignored errors', () => {
+ class Adapter extends Component {
+ componentDidCatch() {
+ // Ignore the error
+ }
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throw new Error('Error!');
+ }
+
+ sinon.spy(Adapter.prototype, 'componentDidCatch');
+
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Adapter.prototype.componentDidCatch, 'Adapter').to.have.been
+ .called;
+ expect(Receiver.prototype.componentDidCatch, 'Receiver').to.have.been
+ .called;
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should not bubble on caught errors', () => {
+ class TopReceiver extends Component {
+ componentDidCatch(error) {
+ this.setState({ error });
+ }
+ render() {
+ return (
+ <div>
+ {this.state.error
+ ? String(this.state.error)
+ : this.props.children}
+ </div>
+ );
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(TopReceiver.prototype, 'componentDidCatch');
+
+ render(
+ <TopReceiver>
+ <Receiver>
+ <ThrowErr />
+ </Receiver>
+ </TopReceiver>,
+ scratch
+ );
+ rerender();
+
+ expect(TopReceiver.prototype.componentDidCatch).not.to.have.been.called;
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should be called through non-component parent elements', () => {
+ ThrowErr.prototype.render = throwExpectedError;
+ render(
+ <Receiver>
+ <div>
+ <ThrowErr />
+ </div>
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should bubble up when ref throws on component that is not an error boundary', () => {
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ function ThrowErr() {
+ return <div ref={ref} />;
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.prototype.componentDidCatch).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it.skip('should successfully unmount constantly throwing ref', () => {
+ const buggyRef = throwExpectedError;
+
+ function ThrowErr() {
+ return <div ref={buggyRef}>ThrowErr</div>;
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div>Error: Error!</div>');
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentDidMount.test.js b/preact/test/browser/lifecycles/componentDidMount.test.js
new file mode 100644
index 0000000..086702b
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentDidMount.test.js
@@ -0,0 +1,36 @@
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentDidMount', () => {
+ it('is invoked after refs are set', () => {
+ const spy = sinon.spy();
+
+ class App extends Component {
+ componentDidMount() {
+ expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
+ }
+
+ render() {
+ return <div ref={spy} />;
+ }
+ }
+
+ render(<App />, scratch);
+ expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentDidUpdate.test.js b/preact/test/browser/lifecycles/componentDidUpdate.test.js
new file mode 100644
index 0000000..647adb8
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentDidUpdate.test.js
@@ -0,0 +1,385 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentDidUpdate', () => {
+ it('should be passed previous props and state', () => {
+ /** @type {() => void} */
+ let updateState;
+
+ let prevPropsArg;
+ let prevStateArg;
+ let snapshotArg;
+ let curProps;
+ let curState;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ updateState = () =>
+ this.setState({
+ value: this.state.value + 1
+ });
+ }
+ static getDerivedStateFromProps(props, state) {
+ // NOTE: Don't do this in real production code!
+ // https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
+ return {
+ value: state.value + 1
+ };
+ }
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ // These object references might be updated later so copy
+ // object so we can assert their values at this snapshot in time
+ prevPropsArg = { ...prevProps };
+ prevStateArg = { ...prevState };
+ snapshotArg = snapshot;
+
+ curProps = { ...this.props };
+ curState = { ...this.state };
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ // Expectation:
+ // `prevState` in componentDidUpdate should be
+ // the state before setState and getDerivedStateFromProps was called.
+ // `this.state` in componentDidUpdate should be
+ // the updated state after getDerivedStateFromProps was called.
+
+ // Initial render
+ // state.value: initialized to 0 in constructor, 0 -> 1 in gDSFP
+ render(<Foo foo="foo" />, scratch);
+ expect(scratch.firstChild.textContent).to.be.equal('1');
+ expect(prevPropsArg).to.be.undefined;
+ expect(prevStateArg).to.be.undefined;
+ expect(snapshotArg).to.be.undefined;
+ expect(curProps).to.be.undefined;
+ expect(curState).to.be.undefined;
+
+ // New props
+ // state.value: 1 -> 2 in gDSFP
+ render(<Foo foo="bar" />, scratch);
+ expect(scratch.firstChild.textContent).to.be.equal('2');
+ expect(prevPropsArg).to.deep.equal({ foo: 'foo' });
+ expect(prevStateArg).to.deep.equal({ value: 1 });
+ expect(snapshotArg).to.be.undefined;
+ expect(curProps).to.deep.equal({ foo: 'bar' });
+ expect(curState).to.deep.equal({ value: 2 });
+
+ // New state
+ // state.value: 2 -> 3 in updateState, 3 -> 4 in gDSFP
+ updateState();
+ rerender();
+ expect(scratch.firstChild.textContent).to.be.equal('4');
+ expect(prevPropsArg).to.deep.equal({ foo: 'bar' });
+ expect(prevStateArg).to.deep.equal({ value: 2 });
+ expect(snapshotArg).to.be.undefined;
+ expect(curProps).to.deep.equal({ foo: 'bar' });
+ expect(curState).to.deep.equal({ value: 4 });
+ });
+
+ it('cDU should not be called when sDU returned false', () => {
+ let spy = sinon.spy();
+ let c;
+
+ class App extends Component {
+ constructor() {
+ super();
+ c = this;
+ }
+
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ componentDidUpdate(prevProps) {
+ spy(prevProps);
+ }
+ }
+
+ render(<App />, scratch);
+ c.setState({});
+ rerender();
+
+ expect(spy).to.not.be.called;
+ });
+
+ it("prevState argument should be the same object if state doesn't change", () => {
+ let changeProps, cduPrevState, cduCurrentState;
+
+ class PropsProvider extends Component {
+ constructor() {
+ super();
+ this.state = { value: 0 };
+ changeProps = this.changeReceiverProps.bind(this);
+ }
+ changeReceiverProps() {
+ let value = (this.state.value + 1) % 2;
+ this.setState({
+ value
+ });
+ }
+ render() {
+ return <PropsReceiver value={this.state.value} />;
+ }
+ }
+
+ class PropsReceiver extends Component {
+ componentDidUpdate(prevProps, prevState) {
+ cduPrevState = prevState;
+ cduCurrentState = this.state;
+ }
+ render({ value }) {
+ return <div>{value}</div>;
+ }
+ }
+
+ render(<PropsProvider />, scratch);
+
+ changeProps();
+ rerender();
+
+ expect(cduPrevState).to.equal(cduCurrentState);
+ });
+
+ it('prevState argument should be a different object if state does change', () => {
+ let updateState, cduPrevState, cduCurrentState;
+
+ class Foo extends Component {
+ constructor() {
+ super();
+ this.state = { value: 0 };
+ updateState = this.updateState.bind(this);
+ }
+ updateState() {
+ let value = (this.state.value + 1) % 2;
+ this.setState({
+ value
+ });
+ }
+ componentDidUpdate(prevProps, prevState) {
+ cduPrevState = prevState;
+ cduCurrentState = this.state;
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+
+ updateState();
+ rerender();
+
+ expect(cduPrevState).to.not.equal(cduCurrentState);
+ });
+
+ it("prevProps argument should be the same object if props don't change", () => {
+ let updateState, cduPrevProps, cduCurrentProps;
+
+ class Foo extends Component {
+ constructor() {
+ super();
+ this.state = { value: 0 };
+ updateState = this.updateState.bind(this);
+ }
+ updateState() {
+ let value = (this.state.value + 1) % 2;
+ this.setState({
+ value
+ });
+ }
+ componentDidUpdate(prevProps) {
+ cduPrevProps = prevProps;
+ cduCurrentProps = this.props;
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ render(<Foo />, scratch);
+
+ updateState();
+ rerender();
+
+ expect(cduPrevProps).to.equal(cduCurrentProps);
+ });
+
+ it('prevProps argument should be a different object if props do change', () => {
+ let changeProps, cduPrevProps, cduCurrentProps;
+
+ class PropsProvider extends Component {
+ constructor() {
+ super();
+ this.state = { value: 0 };
+ changeProps = this.changeReceiverProps.bind(this);
+ }
+ changeReceiverProps() {
+ let value = (this.state.value + 1) % 2;
+ this.setState({
+ value
+ });
+ }
+ render() {
+ return <PropsReceiver value={this.state.value} />;
+ }
+ }
+
+ class PropsReceiver extends Component {
+ componentDidUpdate(prevProps) {
+ cduPrevProps = prevProps;
+ cduCurrentProps = this.props;
+ }
+ render({ value }) {
+ return <div>{value}</div>;
+ }
+ }
+
+ render(<PropsProvider />, scratch);
+
+ changeProps();
+ rerender();
+
+ expect(cduPrevProps).to.not.equal(cduCurrentProps);
+ });
+
+ it('is invoked after refs are set', () => {
+ const spy = sinon.spy();
+ let inst;
+ let i = 0;
+
+ class App extends Component {
+ componentDidUpdate() {
+ expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
+ }
+
+ render() {
+ let ref = null;
+
+ if (i > 0) {
+ // Add ref after mount (i > 0)
+ ref = spy;
+ }
+
+ i++;
+ inst = this;
+ return <div ref={ref} />;
+ }
+ }
+
+ render(<App />, scratch);
+ expect(spy).not.to.have.been.called;
+
+ inst.setState({});
+ rerender();
+
+ expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
+ });
+
+ it('should be called after children are mounted', () => {
+ let log = [];
+
+ class Inner extends Component {
+ componentDidMount() {
+ log.push('Inner mounted');
+
+ // Verify that the component is actually mounted when this
+ // callback is invoked.
+ expect(scratch.querySelector('#inner')).to.equalNode(this.base);
+ }
+
+ render() {
+ return <div id="inner" />;
+ }
+ }
+
+ class Outer extends Component {
+ componentDidUpdate() {
+ log.push('Outer updated');
+ }
+
+ render(props) {
+ return props.renderInner ? <Inner /> : <div />;
+ }
+ }
+
+ render(<Outer renderInner={false} />, scratch);
+ render(<Outer renderInner />, scratch);
+
+ expect(log).to.deep.equal(['Inner mounted', 'Outer updated']);
+ });
+
+ it('should be called after parent DOM elements are updated', () => {
+ let setValue;
+ let outerChildText;
+
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+
+ this.state = { i: 0 };
+ setValue = i => this.setState({ i });
+ }
+
+ render(props, { i }) {
+ return (
+ <div>
+ <Inner i={i} {...props} />
+ <p id="parent-child">Outer: {i}</p>
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ componentDidUpdate() {
+ // At this point, the parent's <p> tag should've been updated with the latest value
+ outerChildText = scratch.querySelector('#parent-child').textContent;
+ }
+
+ render(props, { i }) {
+ return <div>Inner: {i}</div>;
+ }
+ }
+
+ sinon.spy(Inner.prototype, 'componentDidUpdate');
+
+ // Initial render
+ render(<Outer />, scratch);
+ expect(Inner.prototype.componentDidUpdate).to.not.have.been.called;
+
+ // Set state with a new i
+ const newValue = 5;
+ setValue(newValue);
+ rerender();
+
+ expect(Inner.prototype.componentDidUpdate).to.have.been.called;
+ expect(outerChildText).to.equal(`Outer: ${newValue.toString()}`);
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentWillMount.test.js b/preact/test/browser/lifecycles/componentWillMount.test.js
new file mode 100644
index 0000000..880803e
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentWillMount.test.js
@@ -0,0 +1,43 @@
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentWillMount', () => {
+ it('should update state when called setState in componentWillMount', () => {
+ let componentState;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ }
+ componentWillMount() {
+ this.setState({ value: 1 });
+ }
+ render() {
+ componentState = this.state;
+ return <div />;
+ }
+ }
+
+ render(<Foo />, scratch);
+
+ expect(componentState).to.deep.equal({ value: 1 });
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentWillReceiveProps.test.js b/preact/test/browser/lifecycles/componentWillReceiveProps.test.js
new file mode 100644
index 0000000..0e10b9b
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentWillReceiveProps.test.js
@@ -0,0 +1,296 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentWillReceiveProps', () => {
+ it('should update state when called setState in componentWillReceiveProps', () => {
+ let componentState;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ dummy: 0
+ };
+ }
+ componentDidMount() {
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ dummy: 1 });
+ }
+ render() {
+ return <Bar dummy={this.state.dummy} />;
+ }
+ }
+ class Bar extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ }
+ componentWillReceiveProps() {
+ this.setState({ value: 1 });
+ }
+ render() {
+ componentState = this.state;
+ return <div />;
+ }
+ }
+
+ render(<Foo />, scratch);
+ rerender();
+
+ expect(componentState).to.deep.equal({ value: 1 });
+
+ const cWRP = Foo.prototype.componentWillReceiveProps;
+ delete Foo.prototype.componentWillReceiveProps;
+
+ Foo.prototype.shouldComponentUpdate = cWRP;
+
+ render(null, scratch);
+ render(<Foo />, scratch);
+ rerender();
+
+ expect(componentState, 'via shouldComponentUpdate').to.deep.equal({
+ value: 1
+ });
+
+ delete Foo.prototype.shouldComponentUpdate;
+ Foo.prototype.componentWillUpdate = cWRP;
+
+ render(null, scratch);
+ render(<Foo />, scratch);
+ rerender();
+
+ expect(componentState, 'via componentWillUpdate').to.deep.equal({
+ value: 1
+ });
+ });
+
+ it('should NOT be called on initial render', () => {
+ class ReceivePropsComponent extends Component {
+ componentWillReceiveProps() {}
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(ReceivePropsComponent.prototype, 'componentWillReceiveProps');
+ render(<ReceivePropsComponent />, scratch);
+ expect(ReceivePropsComponent.prototype.componentWillReceiveProps).not.to
+ .have.been.called;
+ });
+
+ // See last paragraph of cWRP section https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
+ it('should not be called on setState or forceUpdate', () => {
+ let spy = sinon.spy();
+ let spyInner = sinon.spy();
+ let c;
+
+ class Inner extends Component {
+ componentWillReceiveProps() {
+ spyInner();
+ }
+
+ render() {
+ return <div>foo</div>;
+ }
+ }
+
+ class Outer extends Component {
+ constructor() {
+ super();
+ c = this;
+ }
+
+ componentWillReceiveProps() {
+ spy();
+ }
+
+ render() {
+ return <Inner />;
+ }
+ }
+
+ render(<Outer />, scratch);
+ expect(spy).to.not.be.called;
+
+ c.setState({});
+ rerender();
+ expect(spy).to.not.be.called;
+ expect(spyInner).to.be.calledOnce;
+ spy.resetHistory();
+ spyInner.resetHistory();
+
+ c.forceUpdate();
+ rerender();
+ expect(spy).to.not.be.called;
+ expect(spyInner).to.be.calledOnce;
+ });
+
+ it('should be called when rerender with new props from parent', () => {
+ let doRender;
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+ this.state = { i: 0 };
+ }
+ componentDidMount() {
+ doRender = () => this.setState({ i: this.state.i + 1 });
+ }
+ render(props, { i }) {
+ return <Inner i={i} {...props} />;
+ }
+ }
+ class Inner extends Component {
+ componentWillMount() {
+ expect(this.props.i).to.be.equal(0);
+ }
+ componentWillReceiveProps(nextProps) {
+ expect(nextProps.i).to.be.equal(1);
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(Inner.prototype, 'componentWillReceiveProps');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+
+ // Initial render
+ render(<Outer />, scratch);
+ expect(Inner.prototype.componentWillReceiveProps).not.to.have.been.called;
+
+ // Rerender inner with new props
+ doRender();
+ rerender();
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
+ });
+
+ it('should be called when rerender with new props from parent even with setState/forceUpdate in child', () => {
+ let setStateAndUpdateProps;
+ let forceUpdateAndUpdateProps;
+ let cWRPSpy = sinon.spy();
+
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+ this.state = { i: 0 };
+ this.update = this.update.bind(this);
+ }
+ update() {
+ this.setState({ i: this.state.i + 1 });
+ }
+ render(props, { i }) {
+ return <Inner i={i} update={this.update} />;
+ }
+ }
+ class Inner extends Component {
+ componentDidMount() {
+ expect(this.props.i).to.be.equal(0);
+
+ setStateAndUpdateProps = () => {
+ this.setState({});
+ this.props.update();
+ };
+ forceUpdateAndUpdateProps = () => {
+ this.forceUpdate();
+ this.props.update();
+ };
+ }
+ componentWillReceiveProps(nextProps) {
+ cWRPSpy(nextProps.i);
+ }
+ render() {
+ return <div />;
+ }
+ }
+ // Initial render
+ render(<Outer />, scratch);
+ expect(cWRPSpy).not.to.have.been.called;
+
+ // setState in inner component and update with new props
+ setStateAndUpdateProps();
+ rerender();
+ expect(cWRPSpy).to.have.been.calledWith(1);
+
+ // forceUpdate in inner component and update with new props
+ forceUpdateAndUpdateProps();
+ rerender();
+ expect(cWRPSpy).to.have.been.calledWith(2);
+ });
+
+ it('should be called in right execution order', () => {
+ let doRender;
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+ this.state = { i: 0 };
+ }
+ componentDidMount() {
+ doRender = () => this.setState({ i: this.state.i + 1 });
+ }
+ render(props, { i }) {
+ return <Inner i={i} {...props} />;
+ }
+ }
+ class Inner extends Component {
+ componentDidUpdate() {
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
+ expect(Inner.prototype.componentWillUpdate).to.have.been.called;
+ }
+ componentWillReceiveProps() {
+ expect(Inner.prototype.componentWillUpdate).not.to.have.been.called;
+ expect(Inner.prototype.componentDidUpdate).not.to.have.been.called;
+ }
+ componentWillUpdate() {
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
+ expect(Inner.prototype.componentDidUpdate).not.to.have.been.called;
+ }
+ shouldComponentUpdate() {
+ expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
+ expect(Inner.prototype.componentWillUpdate).not.to.have.been.called;
+ return true;
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(Inner.prototype, 'componentWillReceiveProps');
+ sinon.spy(Inner.prototype, 'componentDidUpdate');
+ sinon.spy(Inner.prototype, 'componentWillUpdate');
+ sinon.spy(Inner.prototype, 'shouldComponentUpdate');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+
+ render(<Outer />, scratch);
+ doRender();
+ rerender();
+
+ expect(
+ Inner.prototype.componentWillReceiveProps
+ ).to.have.been.calledBefore(Inner.prototype.componentWillUpdate);
+ expect(
+ Inner.prototype.componentWillReceiveProps
+ ).to.have.been.calledBefore(Inner.prototype.shouldComponentUpdate);
+ expect(Inner.prototype.componentWillUpdate).to.have.been.calledBefore(
+ Inner.prototype.componentDidUpdate
+ );
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentWillUnmount.test.js b/preact/test/browser/lifecycles/componentWillUnmount.test.js
new file mode 100644
index 0000000..5aa0a84
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentWillUnmount.test.js
@@ -0,0 +1,72 @@
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('top-level componentWillUnmount', () => {
+ it('should invoke componentWillUnmount for top-level components', () => {
+ class Foo extends Component {
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render() {
+ return 'foo';
+ }
+ }
+ class Bar extends Component {
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render() {
+ return 'bar';
+ }
+ }
+ sinon.spy(Foo.prototype, 'componentDidMount');
+ sinon.spy(Foo.prototype, 'componentWillUnmount');
+ sinon.spy(Foo.prototype, 'render');
+
+ sinon.spy(Bar.prototype, 'componentDidMount');
+ sinon.spy(Bar.prototype, 'componentWillUnmount');
+ sinon.spy(Bar.prototype, 'render');
+
+ render(<Foo />, scratch);
+ expect(Foo.prototype.componentDidMount, 'initial render').to.have.been
+ .calledOnce;
+
+ render(<Bar />, scratch);
+ expect(Foo.prototype.componentWillUnmount, 'when replaced').to.have.been
+ .calledOnce;
+ expect(Bar.prototype.componentDidMount, 'when replaced').to.have.been
+ .calledOnce;
+
+ render(<div />, scratch);
+ expect(Bar.prototype.componentWillUnmount, 'when removed').to.have.been
+ .calledOnce;
+ });
+
+ it('should only remove dom after componentWillUnmount was called', () => {
+ class Foo extends Component {
+ componentWillUnmount() {
+ expect(document.getElementById('foo')).to.not.equal(null);
+ }
+
+ render() {
+ return <div id="foo" />;
+ }
+ }
+
+ render(<Foo />, scratch);
+ render(null, scratch);
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/componentWillUpdate.test.js b/preact/test/browser/lifecycles/componentWillUpdate.test.js
new file mode 100644
index 0000000..73d8f1f
--- /dev/null
+++ b/preact/test/browser/lifecycles/componentWillUpdate.test.js
@@ -0,0 +1,95 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#componentWillUpdate', () => {
+ it('should NOT be called on initial render', () => {
+ class ReceivePropsComponent extends Component {
+ componentWillUpdate() {}
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(ReceivePropsComponent.prototype, 'componentWillUpdate');
+ render(<ReceivePropsComponent />, scratch);
+ expect(ReceivePropsComponent.prototype.componentWillUpdate).not.to.have
+ .been.called;
+ });
+
+ it('should be called when rerender with new props from parent', () => {
+ let doRender;
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+ this.state = { i: 0 };
+ }
+ componentDidMount() {
+ doRender = () => this.setState({ i: this.state.i + 1 });
+ }
+ render(props, { i }) {
+ return <Inner i={i} {...props} />;
+ }
+ }
+ class Inner extends Component {
+ componentWillUpdate(nextProps, nextState) {
+ expect(nextProps).to.be.deep.equal({ i: 1 });
+ expect(nextState).to.be.deep.equal({});
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(Inner.prototype, 'componentWillUpdate');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+
+ // Initial render
+ render(<Outer />, scratch);
+ expect(Inner.prototype.componentWillUpdate).not.to.have.been.called;
+
+ // Rerender inner with new props
+ doRender();
+ rerender();
+ expect(Inner.prototype.componentWillUpdate).to.have.been.called;
+ });
+
+ it('should be called on new state', () => {
+ let doRender;
+ class ReceivePropsComponent extends Component {
+ componentWillUpdate() {}
+ componentDidMount() {
+ doRender = () => this.setState({ i: this.state.i + 1 });
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(ReceivePropsComponent.prototype, 'componentWillUpdate');
+ render(<ReceivePropsComponent />, scratch);
+ expect(ReceivePropsComponent.prototype.componentWillUpdate).not.to.have
+ .been.called;
+
+ doRender();
+ rerender();
+ expect(ReceivePropsComponent.prototype.componentWillUpdate).to.have.been
+ .called;
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/getDerivedStateFromError.test.js b/preact/test/browser/lifecycles/getDerivedStateFromError.test.js
new file mode 100644
index 0000000..4c279a8
--- /dev/null
+++ b/preact/test/browser/lifecycles/getDerivedStateFromError.test.js
@@ -0,0 +1,659 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /* eslint-disable react/display-name */
+
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#getDerivedStateFromError', () => {
+ /** @type {Error} */
+ let expectedError;
+
+ /** @type {typeof import('../../../').Component} */
+ let ThrowErr;
+
+ let thrower;
+
+ class Receiver extends Component {
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return this.state.error
+ ? String(this.state.error)
+ : this.props.children;
+ }
+ }
+
+ sinon.spy(Receiver, 'getDerivedStateFromError');
+ sinon.spy(Receiver.prototype, 'render');
+
+ function throwExpectedError() {
+ throw (expectedError = new Error('Error!'));
+ }
+
+ beforeEach(() => {
+ ThrowErr = class ThrowErr extends Component {
+ constructor(props) {
+ super(props);
+ thrower = this;
+ }
+
+ static getDerivedStateFromError() {
+ expect.fail("Throwing component should not catch it's own error.");
+ return {};
+ }
+ render() {
+ return <div>ThrowErr: getDerivedStateFromError</div>;
+ }
+ };
+ sinon.spy(ThrowErr, 'getDerivedStateFromError');
+
+ expectedError = undefined;
+
+ Receiver.getDerivedStateFromError.resetHistory();
+ Receiver.prototype.render.resetHistory();
+ });
+
+ afterEach(() => {
+ expect(
+ ThrowErr.getDerivedStateFromError,
+ "Throwing component should not catch it's own error."
+ ).to.not.be.called;
+ thrower = undefined;
+ });
+
+ it('should be called when child fails in constructor', () => {
+ class ThrowErr extends Component {
+ constructor(props, context) {
+ super(props, context);
+ throwExpectedError();
+ }
+ static getDerivedStateFromError() {
+ expect.fail("Throwing component should not catch it's own error");
+ return {};
+ }
+ render() {
+ return <div />;
+ }
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ // https://github.com/preactjs/preact/issues/1570
+ it('should handle double child throws', () => {
+ const Child = ({ i }) => {
+ throw new Error(`error! ${i}`);
+ };
+
+ const fn = () =>
+ render(
+ <Receiver>
+ {[1, 2].map(i => (
+ <Child key={i} i={i} />
+ ))}
+ </Receiver>,
+ scratch
+ );
+ expect(fn).to.not.throw();
+
+ rerender();
+ expect(scratch.innerHTML).to.equal('Error: error! 2');
+ });
+
+ it('should be called when child fails in componentWillMount', () => {
+ ThrowErr.prototype.componentWillMount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in render', () => {
+ ThrowErr.prototype.render = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentDidMount', () => {
+ ThrowErr.prototype.componentDidMount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in getDerivedStateFromProps', () => {
+ ThrowErr.getDerivedStateFromProps = throwExpectedError;
+
+ sinon.spy(ThrowErr.prototype, 'render');
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ expect(ThrowErr.prototype.render).not.to.have.been.called;
+ });
+
+ it('should be called when child fails in getSnapshotBeforeUpdate', () => {
+ ThrowErr.prototype.getSnapshotBeforeUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ thrower.forceUpdate();
+ rerender();
+
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentDidUpdate', () => {
+ ThrowErr.prototype.componentDidUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ thrower.forceUpdate();
+ rerender();
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillUpdate', () => {
+ ThrowErr.prototype.componentWillUpdate = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+
+ thrower.forceUpdate();
+ rerender();
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillReceiveProps', () => {
+ ThrowErr.prototype.componentWillReceiveProps = throwExpectedError;
+
+ let receiver;
+ class Receiver extends Component {
+ constructor() {
+ super();
+ this.state = { foo: 'bar' };
+ receiver = this;
+ }
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <ThrowErr foo={this.state.foo} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver, 'getDerivedStateFromError');
+ render(<Receiver />, scratch);
+
+ receiver.setState({ foo: 'baz' });
+ rerender();
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in shouldComponentUpdate', () => {
+ ThrowErr.prototype.shouldComponentUpdate = throwExpectedError;
+
+ let receiver;
+ class Receiver extends Component {
+ constructor() {
+ super();
+ this.state = { foo: 'bar' };
+ receiver = this;
+ }
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <ThrowErr foo={this.state.foo} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver, 'getDerivedStateFromError');
+ render(<Receiver />, scratch);
+
+ receiver.setState({ foo: 'baz' });
+ rerender();
+
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when child fails in componentWillUnmount', () => {
+ ThrowErr.prototype.componentWillUnmount = throwExpectedError;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ render(
+ <Receiver>
+ <div />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when applying a Component ref', () => {
+ const Foo = () => <div />;
+
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ // In React, an error boundary handles it's own refs:
+ // https://codesandbox.io/s/react-throwing-refs-lk958
+ class Receiver extends Component {
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <Foo ref={ref} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver, 'getDerivedStateFromError');
+ render(<Receiver />, scratch);
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when applying a DOM ref', () => {
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ // In React, an error boundary handles it's own refs:
+ // https://codesandbox.io/s/react-throwing-refs-lk958
+ class Receiver extends Component {
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return this.state.error ? (
+ String(this.state.error)
+ ) : (
+ <div ref={ref} />
+ );
+ }
+ }
+
+ sinon.spy(Receiver, 'getDerivedStateFromError');
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should be called when unmounting a ref', () => {
+ const ref = value => {
+ if (value == null) {
+ throwExpectedError();
+ }
+ };
+
+ ThrowErr.prototype.render = () => <div ref={ref} />;
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ render(
+ <Receiver>
+ <div />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledOnceWith(
+ expectedError
+ );
+ });
+
+ it('should be called when functional child fails', () => {
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should re-render with new content', () => {
+ class ThrowErr extends Component {
+ componentWillMount() {
+ throw new Error('Error contents');
+ }
+ render() {
+ return 'No error!?!?';
+ }
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+ expect(scratch).to.have.property('textContent', 'Error: Error contents');
+ });
+
+ it('should be able to adapt and rethrow errors', () => {
+ let adaptedError;
+ class Adapter extends Component {
+ static getDerivedStateFromError(error) {
+ throw (adaptedError = new Error(
+ 'Adapted ' +
+ String(error && 'message' in error ? error.message : error)
+ ));
+ }
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(Adapter, 'getDerivedStateFromError');
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+
+ expect(Adapter.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ adaptedError
+ );
+
+ rerender();
+ expect(scratch).to.have.property('textContent', 'Error: Adapted Error!');
+ });
+
+ it('should bubble on repeated errors', () => {
+ class Adapter extends Component {
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ // But fail at doing so
+ if (this.state.error) {
+ throw this.state.error;
+ }
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(Adapter, 'getDerivedStateFromError');
+
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Adapter.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should bubble on ignored errors', () => {
+ class Adapter extends Component {
+ static getDerivedStateFromError(error) {
+ // Ignore the error
+ return null;
+ }
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+ }
+
+ function ThrowErr() {
+ throw new Error('Error!');
+ }
+
+ sinon.spy(Adapter, 'getDerivedStateFromError');
+
+ render(
+ <Receiver>
+ <Adapter>
+ <ThrowErr />
+ </Adapter>
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(Adapter.getDerivedStateFromError).to.have.been.called;
+ expect(Receiver.getDerivedStateFromError).to.have.been.called;
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should not bubble on caught errors', () => {
+ class TopReceiver extends Component {
+ static getDerivedStateFromError(error) {
+ return { error };
+ }
+ render() {
+ return (
+ <div>
+ {this.state.error
+ ? String(this.state.error)
+ : this.props.children}
+ </div>
+ );
+ }
+ }
+
+ function ThrowErr() {
+ throwExpectedError();
+ }
+
+ sinon.spy(TopReceiver, 'getDerivedStateFromError');
+
+ render(
+ <TopReceiver>
+ <Receiver>
+ <ThrowErr />
+ </Receiver>
+ </TopReceiver>,
+ scratch
+ );
+ rerender();
+
+ expect(TopReceiver.getDerivedStateFromError).not.to.have.been.called;
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ expect(scratch).to.have.property('textContent', 'Error: Error!');
+ });
+
+ it('should be called through non-component parent elements', () => {
+ ThrowErr.prototype.render = throwExpectedError;
+
+ render(
+ <Receiver>
+ <div>
+ <ThrowErr />
+ </div>
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it('should bubble up when ref throws on component that is not an error boundary', () => {
+ const ref = value => {
+ if (value) {
+ throwExpectedError();
+ }
+ };
+
+ function ThrowErr() {
+ return <div ref={ref} />;
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ expect(Receiver.getDerivedStateFromError).to.have.been.calledWith(
+ expectedError
+ );
+ });
+
+ it.skip('should successfully unmount constantly throwing ref', () => {
+ const buggyRef = throwExpectedError;
+
+ function ThrowErr() {
+ return <div ref={buggyRef}>ThrowErr</div>;
+ }
+
+ render(
+ <Receiver>
+ <ThrowErr />
+ </Receiver>,
+ scratch
+ );
+ rerender();
+
+ expect(scratch.innerHTML).to.equal('<div>Error: Error!</div>');
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/getDerivedStateFromProps.test.js b/preact/test/browser/lifecycles/getDerivedStateFromProps.test.js
new file mode 100644
index 0000000..0fa1394
--- /dev/null
+++ b/preact/test/browser/lifecycles/getDerivedStateFromProps.test.js
@@ -0,0 +1,419 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('static getDerivedStateFromProps', () => {
+ it('should set initial state with value returned from getDerivedStateFromProps', () => {
+ class Foo extends Component {
+ static getDerivedStateFromProps(props) {
+ return {
+ foo: props.foo,
+ bar: 'bar'
+ };
+ }
+ render() {
+ return <div className={`${this.state.foo} ${this.state.bar}`} />;
+ }
+ }
+
+ render(<Foo foo="foo" />, scratch);
+ expect(scratch.firstChild.className).to.be.equal('foo bar');
+ });
+
+ it('should update initial state with value returned from getDerivedStateFromProps', () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ foo: 'foo',
+ bar: 'bar'
+ };
+ }
+ static getDerivedStateFromProps(props, state) {
+ return {
+ foo: `not-${state.foo}`
+ };
+ }
+ render() {
+ return <div className={`${this.state.foo} ${this.state.bar}`} />;
+ }
+ }
+
+ render(<Foo />, scratch);
+ expect(scratch.firstChild.className).to.equal('not-foo bar');
+ });
+
+ it("should update the instance's state with the value returned from getDerivedStateFromProps when props change", () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ value: 'initial'
+ };
+ }
+ static getDerivedStateFromProps(props) {
+ if (props.update) {
+ return {
+ value: 'updated'
+ };
+ }
+
+ return null;
+ }
+ componentDidMount() {}
+ componentDidUpdate() {}
+ render() {
+ return <div className={this.state.value} />;
+ }
+ }
+
+ sinon.spy(Foo, 'getDerivedStateFromProps');
+ sinon.spy(Foo.prototype, 'componentDidMount');
+ sinon.spy(Foo.prototype, 'componentDidUpdate');
+
+ render(<Foo update={false} />, scratch);
+ expect(scratch.firstChild.className).to.equal('initial');
+ expect(Foo.getDerivedStateFromProps).to.have.callCount(1);
+ expect(Foo.prototype.componentDidMount).to.have.callCount(1); // verify mount occurred
+ expect(Foo.prototype.componentDidUpdate).to.have.callCount(0);
+
+ render(<Foo update />, scratch);
+ expect(scratch.firstChild.className).to.equal('updated');
+ expect(Foo.getDerivedStateFromProps).to.have.callCount(2);
+ expect(Foo.prototype.componentDidMount).to.have.callCount(1);
+ expect(Foo.prototype.componentDidUpdate).to.have.callCount(1); // verify update occurred
+ });
+
+ it("should update the instance's state with the value returned from getDerivedStateFromProps when state changes", () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ value: 'initial'
+ };
+ }
+ static getDerivedStateFromProps(props, state) {
+ // Don't change state for call that happens after the constructor
+ if (state.value === 'initial') {
+ return null;
+ }
+
+ return {
+ value: state.value + ' derived'
+ };
+ }
+ componentDidMount() {
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ value: 'updated' });
+ }
+ render() {
+ return <div className={this.state.value} />;
+ }
+ }
+
+ sinon.spy(Foo, 'getDerivedStateFromProps');
+
+ render(<Foo />, scratch);
+ expect(scratch.firstChild.className).to.equal('initial');
+ expect(Foo.getDerivedStateFromProps).to.have.been.calledOnce;
+
+ rerender(); // call rerender to handle cDM setState call
+ expect(scratch.firstChild.className).to.equal('updated derived');
+ expect(Foo.getDerivedStateFromProps).to.have.been.calledTwice;
+ });
+
+ it('should NOT modify state if null is returned', () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ foo: 'foo',
+ bar: 'bar'
+ };
+ }
+ static getDerivedStateFromProps() {
+ return null;
+ }
+ render() {
+ return <div className={`${this.state.foo} ${this.state.bar}`} />;
+ }
+ }
+
+ sinon.spy(Foo, 'getDerivedStateFromProps');
+
+ render(<Foo />, scratch);
+ expect(scratch.firstChild.className).to.equal('foo bar');
+ expect(Foo.getDerivedStateFromProps).to.have.been.called;
+ });
+
+ // NOTE: Difference from React
+ // React v16.3.2 warns if undefined if returned from getDerivedStateFromProps
+ it('should NOT modify state if undefined is returned', () => {
+ class Foo extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ foo: 'foo',
+ bar: 'bar'
+ };
+ }
+ static getDerivedStateFromProps() {}
+ render() {
+ return <div className={`${this.state.foo} ${this.state.bar}`} />;
+ }
+ }
+
+ sinon.spy(Foo, 'getDerivedStateFromProps');
+
+ render(<Foo />, scratch);
+ expect(scratch.firstChild.className).to.equal('foo bar');
+ expect(Foo.getDerivedStateFromProps).to.have.been.called;
+ });
+
+ it('should NOT invoke deprecated lifecycles (cWM/cWRP) if new static gDSFP is present', () => {
+ class Foo extends Component {
+ static getDerivedStateFromProps() {}
+ componentWillMount() {}
+ componentWillReceiveProps() {}
+ render() {
+ return <div />;
+ }
+ }
+
+ sinon.spy(Foo, 'getDerivedStateFromProps');
+ sinon.spy(Foo.prototype, 'componentWillMount');
+ sinon.spy(Foo.prototype, 'componentWillReceiveProps');
+
+ render(<Foo />, scratch);
+ expect(Foo.getDerivedStateFromProps).to.have.been.called;
+ expect(Foo.prototype.componentWillMount).to.not.have.been.called;
+ expect(Foo.prototype.componentWillReceiveProps).to.not.have.been.called;
+ });
+
+ it('is not called if neither state nor props have changed', () => {
+ let logs = [];
+ let childRef;
+
+ class Parent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { parentRenders: 0 };
+ }
+
+ static getDerivedStateFromProps(props, state) {
+ logs.push('parent getDerivedStateFromProps');
+ return state.parentRenders + 1;
+ }
+
+ render() {
+ logs.push('parent render');
+ return <Child parentRenders={this.state.parentRenders} />;
+ }
+ }
+
+ class Child extends Component {
+ constructor(props) {
+ super(props);
+ childRef = this;
+ }
+ render() {
+ logs.push('child render');
+ return this.props.parentRenders;
+ }
+ }
+
+ render(<Parent />, scratch);
+ expect(logs).to.deep.equal([
+ 'parent getDerivedStateFromProps',
+ 'parent render',
+ 'child render'
+ ]);
+
+ logs = [];
+ childRef.setState({});
+ rerender();
+ expect(logs).to.deep.equal(['child render']);
+ });
+
+ // TODO: Investigate this test:
+ // [should not override state with stale values if prevState is spread within getDerivedStateFromProps](https://github.com/facebook/react/blob/25dda90c1ecb0c662ab06e2c80c1ee31e0ae9d36/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js#L1035)
+
+ it('should be passed next props and state', () => {
+ /** @type {() => void} */
+ let updateState;
+
+ let propsArg;
+ let stateArg;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ updateState = () =>
+ this.setState({
+ value: this.state.value + 1
+ });
+ }
+ static getDerivedStateFromProps(props, state) {
+ // These object references might be updated later so copy
+ // object so we can assert their values at this snapshot in time
+ propsArg = { ...props };
+ stateArg = { ...state };
+
+ // NOTE: Don't do this in real production code!
+ // https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
+ return {
+ value: state.value + 1
+ };
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ // Initial render
+ // state.value: initialized to 0 in constructor, 0 -> 1 in gDSFP
+ render(<Foo foo="foo" />, scratch);
+
+ let element = scratch.firstChild;
+ expect(element.textContent).to.be.equal('1');
+ expect(propsArg).to.deep.equal({
+ foo: 'foo'
+ });
+ expect(stateArg).to.deep.equal({
+ value: 0
+ });
+
+ // New Props
+ // state.value: 1 -> 2 in gDSFP
+ render(<Foo foo="bar" />, scratch);
+ expect(element.textContent).to.be.equal('2');
+ expect(propsArg).to.deep.equal({
+ foo: 'bar'
+ });
+ expect(stateArg).to.deep.equal({
+ value: 1
+ });
+
+ // New state
+ // state.value: 2 -> 3 in updateState, 3 -> 4 in gDSFP
+ updateState();
+ rerender();
+ expect(element.textContent).to.be.equal('4');
+ expect(propsArg).to.deep.equal({
+ foo: 'bar'
+ });
+ expect(stateArg).to.deep.equal({
+ value: 3
+ });
+
+ // New Props (see #1446)
+ // 4 -> 5 in gDSFP
+ render(<Foo foo="baz" />, scratch);
+ expect(element.textContent).to.be.equal('5');
+ expect(stateArg).to.deep.equal({
+ value: 4
+ });
+
+ // New Props (see #1446)
+ // 5 -> 6 in gDSFP
+ render(<Foo foo="qux" />, scratch);
+ expect(element.textContent).to.be.equal('6');
+ expect(stateArg).to.deep.equal({
+ value: 5
+ });
+ });
+
+ // From preactjs/preact#1170
+ it('should NOT mutate state on mount, only create new versions', () => {
+ const stateConstant = {};
+ let componentState;
+
+ class Stateful extends Component {
+ static getDerivedStateFromProps() {
+ return { key: 'value' };
+ }
+
+ constructor() {
+ super(...arguments);
+ this.state = stateConstant;
+ }
+
+ componentDidMount() {
+ componentState = this.state;
+ }
+
+ render() {
+ return <div />;
+ }
+ }
+
+ render(<Stateful />, scratch);
+
+ // Verify captured object references didn't get mutated
+ expect(componentState).to.deep.equal({ key: 'value' });
+ expect(stateConstant).to.deep.equal({});
+ });
+
+ it('should NOT mutate state on update, only create new versions', () => {
+ const initialState = {};
+ const capturedStates = [];
+
+ let setState;
+
+ class Stateful extends Component {
+ static getDerivedStateFromProps(props, state) {
+ return { value: (state.value || 0) + 1 };
+ }
+
+ constructor() {
+ super(...arguments);
+ this.state = initialState;
+ capturedStates.push(this.state);
+
+ setState = this.setState.bind(this);
+ }
+
+ componentDidMount() {
+ capturedStates.push(this.state);
+ }
+
+ componentDidUpdate() {
+ capturedStates.push(this.state);
+ }
+
+ render() {
+ return <div />;
+ }
+ }
+
+ render(<Stateful />, scratch);
+
+ setState({ value: 10 });
+ rerender();
+
+ // Verify captured object references didn't get mutated
+ expect(capturedStates).to.deep.equal([{}, { value: 1 }, { value: 11 }]);
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/getSnapshotBeforeUpdate.test.js b/preact/test/browser/lifecycles/getSnapshotBeforeUpdate.test.js
new file mode 100644
index 0000000..645424b
--- /dev/null
+++ b/preact/test/browser/lifecycles/getSnapshotBeforeUpdate.test.js
@@ -0,0 +1,211 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#getSnapshotBeforeUpdate', () => {
+ it('should pass the return value from getSnapshotBeforeUpdate to componentDidUpdate', () => {
+ let log = [];
+
+ class MyComponent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ }
+ static getDerivedStateFromProps(nextProps, prevState) {
+ return {
+ value: prevState.value + 1
+ };
+ }
+ getSnapshotBeforeUpdate(prevProps, prevState) {
+ log.push(
+ `getSnapshotBeforeUpdate() prevProps:${prevProps.value} prevState:${prevState.value}`
+ );
+ return 'abc';
+ }
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ log.push(
+ `componentDidUpdate() prevProps:${prevProps.value} prevState:${prevState.value} snapshot:${snapshot}`
+ );
+ }
+ render() {
+ log.push('render');
+ return null;
+ }
+ }
+
+ render(<MyComponent value="foo" />, scratch);
+ expect(log).to.deep.equal(['render']);
+ log = [];
+
+ render(<MyComponent value="bar" />, scratch);
+ expect(log).to.deep.equal([
+ 'render',
+ 'getSnapshotBeforeUpdate() prevProps:foo prevState:1',
+ 'componentDidUpdate() prevProps:foo prevState:1 snapshot:abc'
+ ]);
+ log = [];
+
+ render(<MyComponent value="baz" />, scratch);
+ expect(log).to.deep.equal([
+ 'render',
+ 'getSnapshotBeforeUpdate() prevProps:bar prevState:2',
+ 'componentDidUpdate() prevProps:bar prevState:2 snapshot:abc'
+ ]);
+ log = [];
+
+ render(<div />, scratch, scratch.firstChild);
+ expect(log).to.deep.equal([]);
+ });
+
+ it('should call getSnapshotBeforeUpdate before mutations are committed', () => {
+ let log = [];
+
+ class MyComponent extends Component {
+ getSnapshotBeforeUpdate(prevProps) {
+ log.push('getSnapshotBeforeUpdate');
+ expect(this.divRef.textContent).to.equal(`value:${prevProps.value}`);
+ return 'foobar';
+ }
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ log.push('componentDidUpdate');
+ expect(this.divRef.textContent).to.equal(`value:${this.props.value}`);
+ expect(snapshot).to.equal('foobar');
+ }
+ render() {
+ log.push('render');
+ return (
+ <div
+ ref={ref => (this.divRef = ref)}
+ >{`value:${this.props.value}`}</div>
+ );
+ }
+ }
+
+ render(<MyComponent value="foo" />, scratch);
+ expect(log).to.deep.equal(['render']);
+ log = [];
+
+ render(<MyComponent value="bar" />, scratch);
+ expect(log).to.deep.equal([
+ 'render',
+ 'getSnapshotBeforeUpdate',
+ 'componentDidUpdate'
+ ]);
+ });
+
+ it('should be passed the previous props and state', () => {
+ /** @type {() => void} */
+ let updateState;
+
+ let prevPropsArg;
+ let prevStateArg;
+ let curProps;
+ let curState;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ updateState = () =>
+ this.setState({
+ value: this.state.value + 1
+ });
+ }
+ static getDerivedStateFromProps(props, state) {
+ // NOTE: Don't do this in real production code!
+ // https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
+ return {
+ value: state.value + 1
+ };
+ }
+ getSnapshotBeforeUpdate(prevProps, prevState) {
+ // These object references might be updated later so copy
+ // object so we can assert their values at this snapshot in time
+ prevPropsArg = { ...prevProps };
+ prevStateArg = { ...prevState };
+
+ curProps = { ...this.props };
+ curState = { ...this.state };
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ // Expectation:
+ // `prevState` in getSnapshotBeforeUpdate should be
+ // the state before setState or getDerivedStateFromProps was called.
+ // `this.state` in getSnapshotBeforeUpdate should be
+ // the updated state after getDerivedStateFromProps was called.
+
+ // Initial render
+ // state.value: initialized to 0 in constructor, 0 -> 1 in gDSFP
+ render(<Foo foo="foo" />, scratch);
+ const element = scratch.firstChild;
+
+ expect(element.textContent).to.be.equal('1');
+ expect(prevPropsArg).to.be.undefined;
+ expect(prevStateArg).to.be.undefined;
+ expect(curProps).to.be.undefined;
+ expect(curState).to.be.undefined;
+
+ // New props
+ // state.value: 1 -> 2 in gDSFP
+ render(<Foo foo="bar" />, scratch);
+
+ expect(element.textContent).to.be.equal('2');
+ expect(prevPropsArg).to.deep.equal({
+ foo: 'foo'
+ });
+ expect(prevStateArg).to.deep.equal({
+ value: 1
+ });
+ expect(curProps).to.deep.equal({
+ foo: 'bar'
+ });
+ expect(curState).to.deep.equal({
+ value: 2
+ });
+
+ // New state
+ // state.value: 2 -> 3 in updateState, 3 -> 4 in gDSFP
+ updateState();
+ rerender();
+ expect(element.textContent).to.be.equal('4');
+ expect(prevPropsArg).to.deep.equal({
+ foo: 'bar'
+ });
+ expect(prevStateArg).to.deep.equal({
+ value: 2
+ });
+ expect(curProps).to.deep.equal({
+ foo: 'bar'
+ });
+ expect(curState).to.deep.equal({
+ value: 4
+ });
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/lifecycle.test.js b/preact/test/browser/lifecycles/lifecycle.test.js
new file mode 100644
index 0000000..56cced6
--- /dev/null
+++ b/preact/test/browser/lifecycles/lifecycle.test.js
@@ -0,0 +1,672 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should call nested new lifecycle methods in the right order', () => {
+ let updateOuterState;
+ let updateInnerState;
+ let forceUpdateOuter;
+ let forceUpdateInner;
+
+ let log;
+ function logger(msg) {
+ return function() {
+ // return true for shouldComponentUpdate
+ log.push(msg);
+ return true;
+ };
+ }
+
+ class Outer extends Component {
+ static getDerivedStateFromProps() {
+ log.push('outer getDerivedStateFromProps');
+ return null;
+ }
+ constructor() {
+ super();
+ log.push('outer constructor');
+
+ this.state = { value: 0 };
+ forceUpdateOuter = () =>
+ this.forceUpdate(() => log.push('outer forceUpdate callback'));
+ updateOuterState = () =>
+ this.setState(
+ prevState => ({ value: prevState.value % 2 }),
+ () => log.push('outer setState callback')
+ );
+ }
+ render() {
+ log.push('outer render');
+ return (
+ <div>
+ <Inner x={this.props.x} outerValue={this.state.value} />
+ </div>
+ );
+ }
+ }
+ Object.assign(Outer.prototype, {
+ componentDidMount: logger('outer componentDidMount'),
+ shouldComponentUpdate: logger('outer shouldComponentUpdate'),
+ getSnapshotBeforeUpdate: logger('outer getSnapshotBeforeUpdate'),
+ componentDidUpdate: logger('outer componentDidUpdate'),
+ componentWillUnmount: logger('outer componentWillUnmount')
+ });
+
+ class Inner extends Component {
+ static getDerivedStateFromProps() {
+ log.push('inner getDerivedStateFromProps');
+ return null;
+ }
+ constructor() {
+ super();
+ log.push('inner constructor');
+
+ this.state = { value: 0 };
+ forceUpdateInner = () =>
+ this.forceUpdate(() => log.push('inner forceUpdate callback'));
+ updateInnerState = () =>
+ this.setState(
+ prevState => ({ value: prevState.value % 2 }),
+ () => log.push('inner setState callback')
+ );
+ }
+ render() {
+ log.push('inner render');
+ return (
+ <span>
+ {this.props.x} {this.props.outerValue} {this.state.value}
+ </span>
+ );
+ }
+ }
+ Object.assign(Inner.prototype, {
+ componentDidMount: logger('inner componentDidMount'),
+ shouldComponentUpdate: logger('inner shouldComponentUpdate'),
+ getSnapshotBeforeUpdate: logger('inner getSnapshotBeforeUpdate'),
+ componentDidUpdate: logger('inner componentDidUpdate'),
+ componentWillUnmount: logger('inner componentWillUnmount')
+ });
+
+ // Constructor & mounting
+ log = [];
+ render(<Outer x={1} />, scratch);
+ expect(log).to.deep.equal([
+ 'outer constructor',
+ 'outer getDerivedStateFromProps',
+ 'outer render',
+ 'inner constructor',
+ 'inner getDerivedStateFromProps',
+ 'inner render',
+ 'inner componentDidMount',
+ 'outer componentDidMount'
+ ]);
+
+ // Outer & Inner props update
+ log = [];
+ render(<Outer x={2} />, scratch);
+ // Note: we differ from react here in that we apply changes to the dom
+ // as we find them while diffing. React on the other hand separates this
+ // into specific phases, meaning changes to the dom are only flushed
+ // once the whole diff-phase is complete. This is why
+ // "outer getSnapshotBeforeUpdate" is called just before the "inner" hooks.
+ // For react this call would be right before "outer componentDidUpdate"
+ expect(log).to.deep.equal([
+ 'outer getDerivedStateFromProps',
+ 'outer shouldComponentUpdate',
+ 'outer render',
+ 'outer getSnapshotBeforeUpdate',
+ 'inner getDerivedStateFromProps',
+ 'inner shouldComponentUpdate',
+ 'inner render',
+ 'inner getSnapshotBeforeUpdate',
+ 'inner componentDidUpdate',
+ 'outer componentDidUpdate'
+ ]);
+
+ // Outer state update & Inner props update
+ log = [];
+ updateOuterState();
+ rerender();
+ expect(log).to.deep.equal([
+ 'outer getDerivedStateFromProps',
+ 'outer shouldComponentUpdate',
+ 'outer render',
+ 'outer getSnapshotBeforeUpdate',
+ 'inner getDerivedStateFromProps',
+ 'inner shouldComponentUpdate',
+ 'inner render',
+ 'inner getSnapshotBeforeUpdate',
+ 'inner componentDidUpdate',
+ 'outer setState callback',
+ 'outer componentDidUpdate'
+ ]);
+
+ // Inner state update
+ log = [];
+ updateInnerState();
+ rerender();
+ expect(log).to.deep.equal([
+ 'inner getDerivedStateFromProps',
+ 'inner shouldComponentUpdate',
+ 'inner render',
+ 'inner getSnapshotBeforeUpdate',
+ 'inner setState callback',
+ 'inner componentDidUpdate'
+ ]);
+
+ // Force update Outer
+ log = [];
+ forceUpdateOuter();
+ rerender();
+ expect(log).to.deep.equal([
+ 'outer getDerivedStateFromProps',
+ 'outer render',
+ 'outer getSnapshotBeforeUpdate',
+ 'inner getDerivedStateFromProps',
+ 'inner shouldComponentUpdate',
+ 'inner render',
+ 'inner getSnapshotBeforeUpdate',
+ 'inner componentDidUpdate',
+ 'outer forceUpdate callback',
+ 'outer componentDidUpdate'
+ ]);
+
+ // Force update Inner
+ log = [];
+ forceUpdateInner();
+ rerender();
+ expect(log).to.deep.equal([
+ 'inner getDerivedStateFromProps',
+ 'inner render',
+ 'inner getSnapshotBeforeUpdate',
+ 'inner forceUpdate callback',
+ 'inner componentDidUpdate'
+ ]);
+
+ // Unmounting Outer & Inner
+ log = [];
+ render(<table />, scratch);
+ expect(log).to.deep.equal([
+ 'outer componentWillUnmount',
+ 'inner componentWillUnmount'
+ ]);
+ });
+
+ describe('#constructor and component(Did|Will)(Mount|Unmount)', () => {
+ let setState;
+ class Outer extends Component {
+ constructor(p, c) {
+ super(p, c);
+ this.state = { show: true };
+ setState = s => this.setState(s);
+ }
+ render(props, { show }) {
+ return <div>{show && <Inner {...props} />}</div>;
+ }
+ }
+
+ class LifecycleTestComponent extends Component {
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render() {
+ return <div />;
+ }
+ }
+
+ class Inner extends LifecycleTestComponent {
+ render() {
+ return (
+ <div>
+ <InnerMost />
+ </div>
+ );
+ }
+ }
+
+ class InnerMost extends LifecycleTestComponent {
+ render() {
+ return <div />;
+ }
+ }
+
+ let spies = [
+ 'componentWillMount',
+ 'componentDidMount',
+ 'componentWillUnmount'
+ ];
+
+ let verifyLifecycleMethods = TestComponent => {
+ let proto = TestComponent.prototype;
+ spies.forEach(s => sinon.spy(proto, s));
+ let reset = () => spies.forEach(s => proto[s].resetHistory());
+
+ it('should be invoked for components on initial render', () => {
+ reset();
+ render(<Outer />, scratch);
+ expect(proto.componentDidMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+ });
+
+ it('should be invoked for components on unmount', () => {
+ reset();
+ setState({ show: false });
+ rerender();
+
+ expect(proto.componentWillUnmount).to.have.been.called;
+ });
+
+ it('should be invoked for components on re-render', () => {
+ reset();
+ setState({ show: true });
+ rerender();
+
+ expect(proto.componentDidMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+ });
+ };
+
+ describe('inner components', () => {
+ verifyLifecycleMethods(Inner);
+ });
+
+ describe('innermost components', () => {
+ verifyLifecycleMethods(InnerMost);
+ });
+
+ describe('when shouldComponentUpdate() returns false', () => {
+ let setState;
+
+ class Outer extends Component {
+ constructor() {
+ super();
+ this.state = { show: true };
+ setState = s => this.setState(s);
+ }
+ render(props, { show }) {
+ return (
+ <div>
+ {show && (
+ <div>
+ <Inner {...props} />
+ </div>
+ )}
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ render() {
+ return <div />;
+ }
+ }
+
+ let proto = Inner.prototype;
+ let spies = [
+ 'componentWillMount',
+ 'componentDidMount',
+ 'componentWillUnmount'
+ ];
+ spies.forEach(s => sinon.spy(proto, s));
+
+ let reset = () => spies.forEach(s => proto[s].resetHistory());
+
+ beforeEach(() => reset());
+
+ it('should be invoke normally on initial mount', () => {
+ render(<Outer />, scratch);
+ expect(proto.componentWillMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+ });
+
+ it('should be invoked normally on unmount', () => {
+ setState({ show: false });
+ rerender();
+
+ expect(proto.componentWillUnmount).to.have.been.called;
+ });
+
+ it('should still invoke mount for shouldComponentUpdate():false', () => {
+ setState({ show: true });
+ rerender();
+
+ expect(proto.componentWillMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+ });
+
+ it('should still invoke unmount for shouldComponentUpdate():false', () => {
+ setState({ show: false });
+ rerender();
+
+ expect(proto.componentWillUnmount).to.have.been.called;
+ });
+ });
+ });
+
+ describe('#setState', () => {
+ // From preactjs/preact#1170
+ it('should NOT mutate state, only create new versions', () => {
+ const stateConstant = {};
+ let didMount = false;
+ let componentState;
+
+ class Stateful extends Component {
+ constructor() {
+ super(...arguments);
+ this.state = stateConstant;
+ }
+
+ componentDidMount() {
+ didMount = true;
+
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ key: 'value' }, () => {
+ componentState = this.state;
+ });
+ }
+
+ render() {
+ return <div />;
+ }
+ }
+
+ render(<Stateful />, scratch);
+ rerender();
+
+ expect(didMount).to.equal(true);
+ expect(componentState).to.deep.equal({ key: 'value' });
+ expect(stateConstant).to.deep.equal({});
+ });
+
+ // This feature is not mentioned in the docs, but is part of the release
+ // notes for react v16.0.0: https://reactjs.org/blog/2017/09/26/react-v16.0.html#breaking-changes
+ it('should abort if updater function returns null', () => {
+ let updateState;
+ class Foo extends Component {
+ constructor() {
+ super();
+ this.state = { value: 0 };
+ updateState = () =>
+ this.setState(prev => {
+ prev.value++;
+ return null;
+ });
+ }
+
+ render() {
+ return 'value: ' + this.state.value;
+ }
+ }
+
+ let renderSpy = sinon.spy(Foo.prototype, 'render');
+ render(<Foo />, scratch);
+ renderSpy.resetHistory();
+
+ updateState();
+ rerender();
+ expect(renderSpy).to.not.be.called;
+ });
+
+ it('should call callback with correct this binding', () => {
+ let inst;
+ let updateState;
+ class Foo extends Component {
+ constructor() {
+ super();
+ updateState = () => this.setState({}, this.onUpdate);
+ }
+
+ onUpdate() {
+ inst = this;
+ }
+ }
+
+ render(<Foo />, scratch);
+ updateState();
+ rerender();
+
+ expect(inst).to.be.instanceOf(Foo);
+ });
+ });
+
+ describe('Lifecycle DOM Timing', () => {
+ it('should be invoked when dom does (DidMount, WillUnmount) or does not (WillMount, DidUnmount) exist', () => {
+ let setState;
+ class Outer extends Component {
+ constructor() {
+ super();
+ this.state = { show: true };
+ setState = s => {
+ this.setState(s);
+ this.forceUpdate();
+ };
+ }
+ componentWillMount() {
+ expect(
+ document.getElementById('OuterDiv'),
+ 'Outer componentWillMount'
+ ).to.not.exist;
+ }
+ componentDidMount() {
+ expect(document.getElementById('OuterDiv'), 'Outer componentDidMount')
+ .to.exist;
+ }
+ componentWillUnmount() {
+ expect(
+ document.getElementById('OuterDiv'),
+ 'Outer componentWillUnmount'
+ ).to.exist;
+ setTimeout(() => {
+ expect(
+ document.getElementById('OuterDiv'),
+ 'Outer after componentWillUnmount'
+ ).to.not.exist;
+ }, 0);
+ }
+ render(props, { show }) {
+ return (
+ <div id="OuterDiv">
+ {show && (
+ <div>
+ <Inner {...props} />
+ </div>
+ )}
+ </div>
+ );
+ }
+ }
+
+ class Inner extends Component {
+ componentWillMount() {
+ expect(
+ document.getElementById('InnerDiv'),
+ 'Inner componentWillMount'
+ ).to.not.exist;
+ }
+ componentDidMount() {
+ expect(document.getElementById('InnerDiv'), 'Inner componentDidMount')
+ .to.exist;
+ }
+ componentWillUnmount() {
+ // @TODO Component mounted into elements (non-components)
+ // are currently unmounted after those elements, so their
+ // DOM is unmounted prior to the method being called.
+ //expect(document.getElementById('InnerDiv'), 'Inner componentWillUnmount').to.exist;
+ setTimeout(() => {
+ expect(
+ document.getElementById('InnerDiv'),
+ 'Inner after componentWillUnmount'
+ ).to.not.exist;
+ }, 0);
+ }
+
+ render() {
+ return <div id="InnerDiv" />;
+ }
+ }
+
+ let proto = Inner.prototype;
+ let spies = [
+ 'componentWillMount',
+ 'componentDidMount',
+ 'componentWillUnmount'
+ ];
+ spies.forEach(s => sinon.spy(proto, s));
+
+ let reset = () => spies.forEach(s => proto[s].resetHistory());
+
+ render(<Outer />, scratch);
+ expect(proto.componentWillMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+
+ reset();
+ setState({ show: false });
+ rerender();
+
+ expect(proto.componentWillUnmount).to.have.been.called;
+
+ reset();
+ setState({ show: true });
+ rerender();
+
+ expect(proto.componentWillMount).to.have.been.called;
+ expect(proto.componentWillMount).to.have.been.calledBefore(
+ proto.componentDidMount
+ );
+ expect(proto.componentDidMount).to.have.been.called;
+ });
+
+ it('should be able to use getDerivedStateFromError and componentDidCatch together', () => {
+ let didCatch = sinon.spy(),
+ getDerived = sinon.spy();
+ const error = new Error('hi');
+
+ class Boundary extends Component {
+ static getDerivedStateFromError(err) {
+ getDerived(err);
+ return { err };
+ }
+
+ componentDidCatch(err) {
+ didCatch(err);
+ }
+
+ render() {
+ return this.state.err ? <div /> : this.props.children;
+ }
+ }
+
+ const ThrowErr = () => {
+ throw error;
+ };
+
+ render(
+ <Boundary>
+ <ThrowErr />
+ </Boundary>,
+ scratch
+ );
+ rerender();
+
+ expect(didCatch).to.have.been.calledWith(error);
+
+ expect(getDerived).to.have.been.calledWith(error);
+ });
+
+ it('should remove this.base for HOC', () => {
+ let createComponent = (name, fn) => {
+ class C extends Component {
+ componentWillUnmount() {
+ expect(this.base, `${name}.componentWillUnmount`).to.exist;
+ setTimeout(() => {
+ expect(this.base, `after ${name}.componentWillUnmount`).not.to
+ .exist;
+ }, 0);
+ }
+ render(props) {
+ return fn(props);
+ }
+ }
+ sinon.spy(C.prototype, 'componentWillUnmount');
+ sinon.spy(C.prototype, 'render');
+ return C;
+ };
+
+ class Wrapper extends Component {
+ render({ children }) {
+ return <div class="wrapper">{children}</div>;
+ }
+ }
+
+ let One = createComponent('One', () => <Wrapper>one</Wrapper>);
+ let Two = createComponent('Two', () => <Wrapper>two</Wrapper>);
+ let Three = createComponent('Three', () => <Wrapper>three</Wrapper>);
+
+ let components = [One, Two, Three];
+
+ let Selector = createComponent('Selector', ({ page }) => {
+ let Child = components[page];
+ return Child && <Child />;
+ });
+
+ let app;
+ class App extends Component {
+ constructor() {
+ super();
+ app = this;
+ }
+
+ render(_, { page }) {
+ return <Selector page={page} />;
+ }
+ }
+
+ render(<App />, scratch);
+
+ for (let i = 0; i < 20; i++) {
+ app.setState({ page: i % components.length });
+ app.forceUpdate();
+ }
+ });
+ });
+});
diff --git a/preact/test/browser/lifecycles/shouldComponentUpdate.test.js b/preact/test/browser/lifecycles/shouldComponentUpdate.test.js
new file mode 100644
index 0000000..6b5f187
--- /dev/null
+++ b/preact/test/browser/lifecycles/shouldComponentUpdate.test.js
@@ -0,0 +1,916 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, Fragment } from 'preact';
+import { setupScratch, teardown } from '../../_util/helpers';
+import { logCall, clearLog } from '../../_util/logCall';
+
+/** @jsx createElement */
+
+describe('Lifecycle methods', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ // function expectDomLogToBe(expectedOperations, message) {
+ // expect(getLog()).to.deep.equal(expectedOperations, message);
+ // }
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+
+ before(() => {
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'appendChild');
+ resetRemove = logCall(Element.prototype, 'removeChild');
+ });
+
+ after(() => {
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+
+ clearLog();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('#shouldComponentUpdate', () => {
+ let setState;
+
+ class Should extends Component {
+ constructor() {
+ super();
+ this.state = { show: true };
+ setState = s => this.setState(s);
+ }
+ render(props, { show }) {
+ return show ? <div /> : null;
+ }
+ }
+
+ class ShouldNot extends Should {
+ shouldComponentUpdate() {
+ return false;
+ }
+ }
+
+ sinon.spy(Should.prototype, 'render');
+ sinon.spy(ShouldNot.prototype, 'shouldComponentUpdate');
+
+ beforeEach(() => Should.prototype.render.resetHistory());
+
+ it('should rerender component on change by default', () => {
+ render(<Should />, scratch);
+ setState({ show: false });
+ rerender();
+
+ expect(Should.prototype.render).to.have.been.calledTwice;
+ });
+
+ it('should not rerender component if shouldComponentUpdate returns false', () => {
+ render(<ShouldNot />, scratch);
+ setState({ show: false });
+ rerender();
+
+ expect(ShouldNot.prototype.shouldComponentUpdate).to.have.been.calledOnce;
+ expect(ShouldNot.prototype.render).to.have.been.calledOnce;
+ });
+
+ it('should reorder non-updating text children', () => {
+ const rows = [
+ { id: '1', a: 5, b: 100 },
+ { id: '2', a: 50, b: 10 },
+ { id: '3', a: 25, b: 1000 }
+ ];
+
+ class Row extends Component {
+ shouldComponentUpdate(nextProps) {
+ return nextProps.id !== this.props.id;
+ }
+
+ render() {
+ return this.props.id;
+ }
+ }
+
+ const App = ({ sortBy }) => (
+ <div>
+ <table>
+ {rows
+ .sort((a, b) => (a[sortBy] > b[sortBy] ? -1 : 1))
+ .map(row => (
+ <Row id={row.id} key={row.id} />
+ ))}
+ </table>
+ </div>
+ );
+
+ render(<App sortBy="a" />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><table>231</table></div>');
+
+ render(<App sortBy="b" />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><table>312</table></div>');
+ });
+
+ it('should rerender when sCU returned false before', () => {
+ let c;
+ let spy = sinon.spy();
+
+ class App extends Component {
+ constructor() {
+ super();
+ c = this;
+ }
+
+ shouldComponentUpdate(_, nextState) {
+ return !!nextState.update;
+ }
+
+ render() {
+ spy();
+ return <div>foo</div>;
+ }
+ }
+
+ render(<App />, scratch);
+
+ c.setState({});
+ rerender();
+ spy.resetHistory();
+
+ c.setState({ update: true });
+ rerender();
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should be called with nextState', () => {
+ let c;
+ let spy = sinon.spy();
+
+ class App extends Component {
+ constructor() {
+ super();
+ c = this;
+ this.state = { a: false };
+ }
+
+ shouldComponentUpdate(_, nextState) {
+ return this.state !== nextState;
+ }
+
+ render() {
+ spy();
+ return <div>foo</div>;
+ }
+ }
+
+ render(<App />, scratch);
+
+ c.setState({});
+ rerender();
+ spy.resetHistory();
+
+ c.setState({ a: true });
+ rerender();
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should clear renderCallbacks', () => {
+ const spy = sinon.spy();
+ let c,
+ renders = 0;
+
+ class App extends Component {
+ constructor() {
+ super();
+ c = this;
+ this.state = { a: false };
+ }
+
+ shouldComponentUpdate(_, nextState) {
+ return false;
+ }
+
+ render() {
+ renders += 1;
+ return <div>foo</div>;
+ }
+ }
+
+ render(<App />, scratch);
+ expect(renders).to.equal(1);
+
+ c.setState({}, spy);
+ rerender();
+ expect(renders).to.equal(1);
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should not be called on forceUpdate', () => {
+ let Comp;
+ class Foo extends Component {
+ constructor() {
+ super();
+ Comp = this;
+ }
+
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return <ShouldNot />;
+ }
+ }
+
+ sinon.spy(Foo.prototype, 'shouldComponentUpdate');
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo />, scratch);
+ Comp.forceUpdate();
+ rerender();
+
+ expect(Foo.prototype.shouldComponentUpdate).to.not.have.been.called;
+ expect(Foo.prototype.render).to.have.been.calledTwice;
+ });
+
+ it('should not be called on forceUpdate followed by setState', () => {
+ let Comp;
+ class Foo extends Component {
+ constructor() {
+ super();
+ Comp = this;
+ }
+
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return <ShouldNot />;
+ }
+ }
+
+ sinon.spy(Foo.prototype, 'shouldComponentUpdate');
+ sinon.spy(Foo.prototype, 'render');
+
+ render(<Foo />, scratch);
+ Comp.forceUpdate();
+ Comp.setState({});
+ rerender();
+
+ expect(Foo.prototype.render).to.have.been.calledTwice;
+ expect(Foo.prototype.shouldComponentUpdate).to.not.have.been.called;
+ });
+
+ it('should not block queued child forceUpdate', () => {
+ let i = 0;
+ let updateInner;
+ class Inner extends Component {
+ shouldComponentUpdate() {
+ return i === 0;
+ }
+ render() {
+ updateInner = () => this.forceUpdate();
+ return <div>{++i}</div>;
+ }
+ }
+
+ let updateOuter;
+ class Outer extends Component {
+ shouldComponentUpdate() {
+ return i === 0;
+ }
+ render() {
+ updateOuter = () => this.forceUpdate();
+ return <Inner />;
+ }
+ }
+
+ class App extends Component {
+ render() {
+ return <Outer />;
+ }
+ }
+
+ render(<App />, scratch);
+
+ updateOuter();
+ updateInner();
+ rerender();
+
+ expect(scratch.textContent).to.equal('2');
+
+ // The inner sCU should return false on second render because
+ // it was not enqueued via forceUpdate
+ updateOuter();
+ rerender();
+ expect(scratch.textContent).to.equal('2');
+ });
+
+ it('should be passed next props and state', () => {
+ /** @type {() => void} */
+ let updateState;
+
+ let curProps;
+ let curState;
+ let nextPropsArg;
+ let nextStateArg;
+
+ class Foo extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ updateState = () =>
+ this.setState({
+ value: this.state.value + 1
+ });
+ }
+ static getDerivedStateFromProps(props, state) {
+ // NOTE: Don't do this in real production code!
+ // https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
+ return {
+ value: state.value + 1
+ };
+ }
+ shouldComponentUpdate(nextProps, nextState) {
+ nextPropsArg = { ...nextProps };
+ nextStateArg = { ...nextState };
+
+ curProps = { ...this.props };
+ curState = { ...this.state };
+
+ return true;
+ }
+ render() {
+ return <div>{this.state.value}</div>;
+ }
+ }
+
+ // Expectation:
+ // `this.state` in shouldComponentUpdate should be
+ // the state before setState or getDerivedStateFromProps was called
+ // `nextState` in shouldComponentUpdate should be
+ // the updated state after getDerivedStateFromProps was called
+
+ // Initial render
+ // state.value: initialized to 0 in constructor, 0 -> 1 in gDSFP
+ render(<Foo foo="foo" />, scratch);
+ expect(scratch.firstChild.textContent).to.be.equal('1');
+ expect(curProps).to.be.undefined;
+ expect(curState).to.be.undefined;
+ expect(nextPropsArg).to.be.undefined;
+ expect(nextStateArg).to.be.undefined;
+
+ // New props
+ // state.value: 1 -> 2 in gDSFP
+ render(<Foo foo="bar" />, scratch);
+ expect(scratch.firstChild.textContent).to.be.equal('2');
+ expect(curProps).to.deep.equal({ foo: 'foo' });
+ expect(curState).to.deep.equal({ value: 1 });
+ expect(nextPropsArg).to.deep.equal({ foo: 'bar' });
+ expect(nextStateArg).to.deep.equal({ value: 2 });
+
+ // New state
+ // state.value: 2 -> 3 in updateState, 3 -> 4 in gDSFP
+ updateState();
+ rerender();
+
+ expect(scratch.firstChild.textContent).to.be.equal('4');
+ expect(curProps).to.deep.equal({ foo: 'bar' });
+ expect(curState).to.deep.equal({ value: 2 });
+ expect(nextPropsArg).to.deep.equal({ foo: 'bar' });
+ expect(nextStateArg).to.deep.equal({ value: 4 });
+ });
+
+ it('should update props reference when sCU returns false', () => {
+ let spy = sinon.spy();
+
+ let updateState;
+ class Foo extends Component {
+ constructor() {
+ super();
+ updateState = () => this.setState({});
+ }
+
+ shouldComponentUpdate(nextProps) {
+ if (nextProps !== this.props) {
+ spy();
+ return false;
+ }
+ return true;
+ }
+ }
+
+ render(<Foo foo="foo" />, scratch);
+ render(<Foo foo="bar" />, scratch);
+ expect(spy).to.be.calledOnce;
+
+ updateState();
+ rerender();
+
+ expect(spy).to.be.calledOnce;
+ });
+
+ it('should update state reference when sCU returns false', () => {
+ let spy = sinon.spy();
+
+ let updateState;
+ class Foo extends Component {
+ constructor() {
+ super();
+ this.state = { foo: 1 };
+ updateState = () => this.setState({ foo: 2 });
+ }
+
+ shouldComponentUpdate(_, nextState) {
+ if (nextState !== this.state) {
+ spy(this.state, nextState);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ render(<Foo />, scratch);
+ updateState();
+ rerender();
+
+ expect(spy).to.be.calledOnce;
+ expect(spy).to.be.calledWithMatch({ foo: 1 }, { foo: 2 });
+
+ updateState();
+ rerender();
+
+ expect(spy).to.be.calledWithMatch({ foo: 2 }, { foo: 2 });
+ expect(spy).to.be.calledTwice;
+ });
+
+ // issue #1864
+ it('should update dom pointers correctly when returning an empty string', () => {
+ function Child({ showMe, counter }) {
+ return showMe ? <div>Counter: {counter}</div> : '';
+ }
+
+ class Parent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return <Inner />;
+ }
+ }
+
+ let updateChild = () => null;
+ class Inner extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showMe: false };
+ updateChild = () => {
+ this.setState({ showMe: (display = !display) });
+ };
+ }
+ render() {
+ return <Child showMe={this.state.showMe} counter={0} />;
+ }
+ }
+
+ let display = false;
+ let updateApp = () => null;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ updateApp = () => this.setState({});
+ }
+ render() {
+ return (
+ <div>
+ <div />
+ <div />
+ <Parent />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('');
+
+ updateApp();
+ rerender();
+ expect(scratch.textContent).to.equal('');
+ });
+
+ // issue #1864 second case
+ it('should update dom pointers correctly when returning a string', () => {
+ function Child({ showMe, counter }) {
+ return showMe ? <div>Counter: {counter}</div> : 'foo';
+ }
+
+ class Parent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return <Inner />;
+ }
+ }
+
+ let updateChild = () => null;
+ class Inner extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showMe: false };
+ updateChild = () => {
+ this.setState({ showMe: (display = !display) });
+ };
+ }
+ render() {
+ return <Child showMe={this.state.showMe} counter={0} />;
+ }
+ }
+
+ let display = false;
+ let updateApp = () => null;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ updateApp = () => this.setState({});
+ }
+ render() {
+ return (
+ <div>
+ <div />
+ <div />
+ <Parent />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('foo');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+
+ updateApp();
+ rerender();
+ expect(scratch.textContent).to.equal('foo');
+ });
+
+ it('should correctly update nested children', () => {
+ let hideThree, incrementThree;
+
+ class One extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render(p) {
+ return p.children;
+ }
+ }
+
+ class Two extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { hideMe: false };
+ hideThree = () => this.setState(s => ({ hideMe: !s.hideMe }));
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.hideMe !== nextState.hideMe;
+ }
+
+ render(p, { hideMe }) {
+ return hideMe ? <Fragment /> : p.children;
+ }
+ }
+
+ class Three extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { counter: 1 };
+ incrementThree = () =>
+ this.setState(s => ({ counter: s.counter + 1 }));
+ }
+
+ render(p, { counter }) {
+ return <span>{counter}</span>;
+ }
+ }
+
+ render(
+ <One>
+ <Two>
+ <Three />
+ </Two>
+ </One>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<span>1</span>');
+
+ hideThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+
+ hideThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<span>1</span>');
+
+ incrementThree();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<span>2</span>');
+ });
+
+ // issue #1864 third case
+ it('should update dom pointers correctly without siblings', () => {
+ function Child({ showMe, counter }) {
+ return showMe ? <div>Counter: {counter}</div> : 'foo';
+ }
+
+ class Parent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return <Inner />;
+ }
+ }
+
+ let updateChild = () => null;
+ class Inner extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { showMe: false };
+ updateChild = () => {
+ this.setState({ showMe: (display = !display) });
+ };
+ }
+ render() {
+ return <Child showMe={this.state.showMe} counter={0} />;
+ }
+ }
+
+ let display = false;
+ let updateApp = () => null;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ updateApp = () => this.setState({});
+ }
+ render() {
+ return (
+ <div>
+ <Parent />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('foo');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('Counter: 0');
+
+ updateChild();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('foo');
+ });
+ });
+
+ it('should correctly render when sCU component has null children', () => {
+ class App extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return [null, <div>Hello World!</div>, null];
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Hello World!</div>');
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Hello World!</div>');
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>Hello World!</div>');
+ });
+
+ it('should support nested update with strict-equal vnodes', () => {
+ let wrapperSetState, childSetState;
+
+ class Child extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { foo: 'baz' };
+ }
+
+ render() {
+ childSetState = this.setState.bind(this);
+ return <p>{this.state.foo}</p>;
+ }
+ }
+
+ class Wrapper extends Component {
+ render() {
+ wrapperSetState = this.setState.bind(this);
+ return this.props.children;
+ }
+ }
+
+ const App = () => (
+ <Wrapper>
+ <Child />
+ </Wrapper>
+ );
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<p>baz</p>');
+
+ wrapperSetState({ hi: 'world' });
+ childSetState({ foo: 'bar' });
+ rerender();
+ expect(scratch.innerHTML).to.equal('<p>bar</p>');
+ });
+
+ it('should reorder non-updating nested Fragment children', () => {
+ const rows = [
+ { id: '1', a: 5, b: 100 },
+ { id: '2', a: 50, b: 10 },
+ { id: '3', a: 25, b: 1000 }
+ ];
+
+ function Cell({ id, a, b }) {
+ // Return an array to really test out the reordering algorithm :)
+ return (
+ <Fragment>
+ <div>id: {id}</div>
+ <Fragment>
+ <div>a: {a}</div>
+ <div>b: {b}</div>
+ </Fragment>
+ </Fragment>
+ );
+ }
+
+ class Row extends Component {
+ shouldComponentUpdate(nextProps) {
+ return nextProps.id !== this.props.id;
+ }
+
+ render(props) {
+ return <Cell id={props.id} a={props.a} b={props.b} />;
+ }
+ }
+
+ const App = ({ sortBy }) => (
+ <div>
+ <table>
+ {rows
+ .sort((a, b) => (a[sortBy] > b[sortBy] ? -1 : 1))
+ .map(row => (
+ <Row key={row.id} id={row.id} a={row.a} b={row.b} />
+ ))}
+ </table>
+ </div>
+ );
+
+ render(<App sortBy="a" />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ `<div><table>${[
+ '<div>id: 2</div><div>a: 50</div><div>b: 10</div>',
+ '<div>id: 3</div><div>a: 25</div><div>b: 1000</div>',
+ '<div>id: 1</div><div>a: 5</div><div>b: 100</div>'
+ ].join('')}</table></div>`
+ );
+
+ clearLog();
+ render(<App sortBy="b" />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ `<div><table>${[
+ '<div>id: 3</div><div>a: 25</div><div>b: 1000</div>',
+ '<div>id: 1</div><div>a: 5</div><div>b: 100</div>',
+ '<div>id: 2</div><div>a: 50</div><div>b: 10</div>'
+ ].join('')}</table></div>`
+ );
+ // TODO: these tests pass in isolation but not when all tests are running, figure out why logCall stops appending to log.
+ // expectDomLogToBe([
+ // '<table>id: 2a: 50b: 10id: 3a: 25b: 1000id: 1a: 5b: 100.insertBefore(<div>id: 3, <div>id: 2)',
+ // '<table>id: 3id: 2a: 50b: 10a: 25b: 1000id: 1a: 5b: 100.insertBefore(<div>a: 25, <div>id: 2)',
+ // '<table>id: 3a: 25id: 2a: 50b: 10b: 1000id: 1a: 5b: 100.insertBefore(<div>b: 1000, <div>id: 2)',
+ // '<table>id: 3a: 25b: 1000id: 2a: 50b: 10id: 1a: 5b: 100.insertBefore(<div>id: 1, <div>id: 2)',
+ // '<table>id: 3a: 25b: 1000id: 1id: 2a: 50b: 10a: 5b: 100.insertBefore(<div>a: 5, <div>id: 2)',
+ // '<table>id: 3a: 25b: 1000id: 1a: 5id: 2a: 50b: 10b: 100.insertBefore(<div>b: 100, <div>id: 2)'
+ // ]);
+ });
+
+ it('should maintain the order if memoised component initially rendered empty content', () => {
+ let showText, updateParent;
+ class Child extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ show: false
+ };
+ showText = () => this.setState({ show: true });
+ }
+ render(props, { show }) {
+ if (!show) return null;
+
+ return <div>Component</div>;
+ }
+ }
+
+ class Memoized extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+ render() {
+ return <Child />;
+ }
+ }
+ class Parent extends Component {
+ constructor(props) {
+ super(props);
+ updateParent = () => this.setState({});
+ }
+ render() {
+ return (
+ <Fragment>
+ <div>Before</div>
+ <Memoized />
+ <div>After</div>
+ </Fragment>
+ );
+ }
+ }
+
+ render(<Parent />, scratch);
+ expect(scratch.innerHTML).to.equal(`<div>Before</div><div>After</div>`);
+
+ updateParent();
+ rerender();
+ expect(scratch.innerHTML).to.equal(`<div>Before</div><div>After</div>`);
+
+ showText();
+ rerender();
+
+ expect(scratch.innerHTML).to.equal(
+ `<div>Before</div><div>Component</div><div>After</div>`
+ );
+ });
+});
diff --git a/preact/test/browser/placeholders.test.js b/preact/test/browser/placeholders.test.js
new file mode 100644
index 0000000..5b52ee6
--- /dev/null
+++ b/preact/test/browser/placeholders.test.js
@@ -0,0 +1,308 @@
+import { createElement, Component, render, createRef } from 'preact';
+import { setupRerender } from 'preact/test-utils';
+import { setupScratch, teardown } from '../_util/helpers';
+import { logCall, clearLog, getLog } from '../_util/logCall';
+import { div } from '../_util/dom';
+
+/** @jsx createElement */
+
+describe('null placeholders', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ /** @type {() => void} */
+ let rerender;
+
+ /** @type {string[]} */
+ let ops;
+
+ function createNullable(name) {
+ return function Nullable(props) {
+ return props.show ? name : null;
+ };
+ }
+
+ /**
+ * @param {string} name
+ * @returns {[import('preact').ComponentClass, import('preact').RefObject<{ toggle(): void }>]}
+ */
+ function createStatefulNullable(name) {
+ let ref = createRef();
+ class Nullable extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: props.initialShow || true };
+ ref.current = this;
+ }
+ toggle() {
+ this.setState({ show: !this.state.show });
+ }
+ componentDidUpdate() {
+ ops.push(`Update ${name}`);
+ }
+ componentDidMount() {
+ ops.push(`Mount ${name}`);
+ }
+ componentWillUnmount() {
+ ops.push(`Unmount ${name}`);
+ }
+ render() {
+ return this.state.show ? <div>{name}</div> : null;
+ }
+ }
+
+ return [Nullable, ref];
+ }
+
+ let resetAppendChild;
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+
+ before(() => {
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ resetRemove = logCall(Element.prototype, 'remove');
+ });
+
+ after(() => {
+ resetAppendChild();
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ });
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ ops = [];
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ clearLog();
+ });
+
+ it('should treat undefined as a hole', () => {
+ let Bar = () => <div>bar</div>;
+
+ function Foo(props) {
+ let sibling;
+ if (props.condition) {
+ sibling = <Bar />;
+ }
+
+ return (
+ <div>
+ <div>Hello</div>
+ {sibling}
+ </div>
+ );
+ }
+
+ render(<Foo condition />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div><div>Hello</div><div>bar</div></div>'
+ );
+ clearLog();
+
+ render(<Foo />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><div>Hello</div></div>');
+ expect(getLog()).to.deep.equal(['<div>bar.remove()']);
+ });
+
+ it('should preserve state of Components when using null or booleans as placeholders', () => {
+ // Must be the same class for all children in <App /> for this test to be valid
+ class Stateful extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { count: 0 };
+ }
+ increment() {
+ this.setState({ count: this.state.count + 1 });
+ }
+ componentDidUpdate() {
+ ops.push(`Update ${this.props.name}`);
+ }
+ componentDidMount() {
+ ops.push(`Mount ${this.props.name}`);
+ }
+ componentWillUnmount() {
+ ops.push(`Unmount ${this.props.name}`);
+ }
+ render() {
+ return (
+ <div>
+ {this.props.name}: {this.state.count}
+ </div>
+ );
+ }
+ }
+
+ const s1ref = createRef();
+ const s2ref = createRef();
+ const s3ref = createRef();
+
+ function App({ first = null, second = false }) {
+ return [first, second, <Stateful name="third" ref={s3ref} />];
+ }
+
+ // Mount third stateful - Initial render
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>third: 0</div>');
+ expect(ops).to.deep.equal(['Mount third'], 'mount third');
+
+ // Update third stateful
+ ops = [];
+ s3ref.current.increment();
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>third: 1</div>');
+ expect(ops).to.deep.equal(['Update third'], 'update third');
+
+ // Mount first stateful
+ ops = [];
+ render(<App first={<Stateful name="first" ref={s1ref} />} />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div>first: 0</div><div>third: 1</div>'
+ );
+ expect(ops).to.deep.equal(['Mount first', 'Update third'], 'mount first');
+
+ // Update first stateful
+ ops = [];
+ s1ref.current.increment();
+ s3ref.current.increment();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div>first: 1</div><div>third: 2</div>'
+ );
+ expect(ops).to.deep.equal(['Update first', 'Update third'], 'update first');
+
+ // Mount second stateful
+ ops = [];
+ render(
+ <App
+ first={<Stateful name="first" ref={s1ref} />}
+ second={<Stateful name="second" ref={s2ref} />}
+ />,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div>first: 1</div><div>second: 0</div><div>third: 2</div>'
+ );
+ expect(ops).to.deep.equal(
+ ['Update first', 'Mount second', 'Update third'],
+ 'mount second'
+ );
+
+ // Update second stateful
+ ops = [];
+ s1ref.current.increment();
+ s2ref.current.increment();
+ s3ref.current.increment();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div>first: 2</div><div>second: 1</div><div>third: 3</div>'
+ );
+ expect(ops).to.deep.equal(
+ ['Update first', 'Update second', 'Update third'],
+ 'update second'
+ );
+ });
+
+ it('should efficiently replace self-updating null placeholders', () => {
+ // These Nullable components replace themselves with null without the parent re-rendering
+ const [Nullable, ref] = createStatefulNullable('Nullable');
+ const [Nullable2, ref2] = createStatefulNullable('Nullable2');
+ function App() {
+ return (
+ <div>
+ <div>1</div>
+ <Nullable />
+ <div>3</div>
+ <Nullable2 />
+ </div>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div('Nullable'), div(3), div('Nullable2')])
+ );
+
+ clearLog();
+ ref2.current.toggle();
+ ref.current.toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(div([div(1), div(3)]));
+ expect(getLog()).to.deep.equal([
+ '<div>Nullable2.remove()',
+ '<div>Nullable.remove()'
+ ]);
+
+ clearLog();
+ ref2.current.toggle();
+ ref.current.toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ div([div(1), div('Nullable'), div(3), div('Nullable2')])
+ );
+ expect(getLog()).to.deep.equal([
+ '<div>.appendChild(#text)',
+ '<div>13.appendChild(<div>Nullable2)',
+ '<div>.appendChild(#text)',
+ '<div>13Nullable2.insertBefore(<div>Nullable, <div>3)'
+ ]);
+ });
+
+ // See preactjs/preact#2350
+ it('should efficiently replace null placeholders in parent rerenders (#2350)', () => {
+ // This Nullable only changes when it's parent rerenders
+ const Nullable1 = createNullable('Nullable 1');
+ const Nullable2 = createNullable('Nullable 2');
+
+ /** @type {() => void} */
+ let toggle;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { show: false };
+ toggle = () => this.setState({ show: !this.state.show });
+ }
+ render() {
+ return (
+ <div>
+ <div>{this.state.show.toString()}</div>
+ <Nullable1 show={this.state.show} />
+ <div>the middle</div>
+ <Nullable2 show={this.state.show} />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal(div([div('false'), div('the middle')]));
+
+ clearLog();
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ div([div('true'), 'Nullable 1', div('the middle'), 'Nullable 2'])
+ );
+ expect(getLog()).to.deep.equal([
+ '<div>truethe middle.insertBefore(#text, <div>the middle)',
+ '<div>trueNullable 1the middle.appendChild(#text)'
+ ]);
+
+ clearLog();
+ toggle();
+ rerender();
+ expect(scratch.innerHTML).to.equal(div([div('false'), div('the middle')]));
+ expect(getLog()).to.deep.equal([
+ '#text.remove()',
+ // '<div>falsethe middleNullable 2.appendChild(<div>the middle)',
+ '#text.remove()'
+ ]);
+ });
+});
diff --git a/preact/test/browser/refs.test.js b/preact/test/browser/refs.test.js
new file mode 100644
index 0000000..b697a4f
--- /dev/null
+++ b/preact/test/browser/refs.test.js
@@ -0,0 +1,481 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, createRef } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+// gives call count and argument errors names (otherwise sinon just uses "spy"):
+let spy = (name, ...args) => {
+ let spy = sinon.spy(...args);
+ spy.displayName = `spy('${name}')`;
+ return spy;
+};
+
+describe('refs', () => {
+ let scratch;
+ let rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should invoke refs in render()', () => {
+ let ref = spy('ref');
+ render(<div ref={ref} />, scratch);
+ expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild);
+ });
+
+ it('should not call stale refs', () => {
+ let ref = spy('ref');
+ let ref2 = spy('ref2');
+ let bool = true;
+ const App = () => <div ref={bool ? ref : ref2} />;
+
+ render(<App />, scratch);
+ expect(ref).to.have.been.calledOnce.and.calledWith(scratch.firstChild);
+
+ bool = false;
+ render(<App />, scratch);
+ expect(ref).to.have.been.calledTwice.and.calledWith(null);
+ expect(ref2).to.have.been.calledOnce.and.calledWith(scratch.firstChild);
+ });
+
+ it('should support createRef', () => {
+ const r = createRef();
+ expect(r.current).to.equal(null);
+
+ render(<div ref={r} />, scratch);
+ expect(r.current).to.equalNode(scratch.firstChild);
+ });
+
+ it('should invoke refs in Component.render()', () => {
+ let outer = spy('outer'),
+ inner = spy('inner');
+ class Foo extends Component {
+ render() {
+ return (
+ <div ref={outer}>
+ <span ref={inner} />
+ </div>
+ );
+ }
+ }
+ render(<Foo />, scratch);
+
+ expect(outer).to.have.been.calledWith(scratch.firstChild);
+ expect(inner).to.have.been.calledWith(scratch.firstChild.firstChild);
+ });
+
+ it('should pass components to ref functions', () => {
+ let ref = spy('ref'),
+ instance;
+ class Foo extends Component {
+ constructor() {
+ super();
+ instance = this;
+ }
+ render() {
+ return <div />;
+ }
+ }
+ render(<Foo ref={ref} />, scratch);
+
+ expect(ref).to.have.been.calledOnce.and.calledWith(instance);
+ });
+
+ it('should have a consistent order', () => {
+ const events = [];
+ const App = () => (
+ <div ref={r => events.push('called with ' + (r && r.tagName))}>
+ <h1 ref={r => events.push('called with ' + (r && r.tagName))}>hi</h1>
+ </div>
+ );
+
+ render(<App />, scratch);
+ render(<App />, scratch);
+ expect(events.length).to.equal(6);
+ expect(events).to.deep.equal([
+ 'called with H1',
+ 'called with DIV',
+ 'called with null',
+ 'called with H1',
+ 'called with null',
+ 'called with DIV'
+ ]);
+ });
+
+ it('should pass rendered DOM from functional components to ref functions', () => {
+ let ref = spy('ref');
+
+ const Foo = () => <div />;
+
+ render(<Foo ref={ref} />, scratch);
+ expect(ref).to.have.been.calledOnce;
+
+ ref.resetHistory();
+ render(<Foo ref={ref} />, scratch);
+ expect(ref).not.to.have.been.called;
+
+ ref.resetHistory();
+ render(<span />, scratch);
+ expect(ref).to.have.been.calledOnce.and.calledWith(null);
+ });
+
+ it('should pass children to ref functions', () => {
+ let outer = spy('outer'),
+ inner = spy('inner'),
+ InnermostComponent = 'span',
+ update,
+ inst;
+ class Outer extends Component {
+ constructor() {
+ super();
+ update = () => this.forceUpdate();
+ }
+ render() {
+ return (
+ <div>
+ <Inner ref={outer} />
+ </div>
+ );
+ }
+ }
+ class Inner extends Component {
+ constructor() {
+ super();
+ inst = this;
+ }
+ render() {
+ return <InnermostComponent ref={inner} />;
+ }
+ }
+
+ render(<Outer />, scratch);
+
+ expect(outer).to.have.been.calledOnce.and.calledWith(inst);
+ expect(inner).to.have.been.calledOnce.and.calledWith(inst.base);
+
+ outer.resetHistory();
+ inner.resetHistory();
+ update();
+ rerender();
+
+ expect(outer, 're-render').not.to.have.been.called;
+ expect(inner, 're-render').not.to.have.been.called;
+
+ inner.resetHistory();
+ InnermostComponent = 'x-span';
+ update();
+ rerender();
+
+ expect(inner, 're-render swap');
+ expect(inner.firstCall, 're-render swap').to.have.been.calledWith(null);
+ expect(inner.secondCall, 're-render swap').to.have.been.calledWith(
+ inst.base
+ );
+
+ InnermostComponent = 'span';
+ outer.resetHistory();
+ inner.resetHistory();
+ render(<div />, scratch);
+
+ expect(outer, 'unrender').to.have.been.calledOnce.and.calledWith(null);
+ expect(inner, 'unrender').to.have.been.calledOnce.and.calledWith(null);
+ });
+
+ it('should pass high-order children to ref functions', () => {
+ let outer = spy('outer'),
+ inner = spy('inner'),
+ innermost = spy('innermost'),
+ InnermostComponent = 'span',
+ outerInst,
+ innerInst;
+ class Outer extends Component {
+ constructor() {
+ super();
+ outerInst = this;
+ }
+ render() {
+ return <Inner ref={inner} />;
+ }
+ }
+ class Inner extends Component {
+ constructor() {
+ super();
+ innerInst = this;
+ }
+ render() {
+ return <InnermostComponent ref={innermost} />;
+ }
+ }
+
+ render(<Outer ref={outer} />, scratch);
+
+ expect(outer, 'outer initial').to.have.been.calledOnce.and.calledWith(
+ outerInst
+ );
+ expect(inner, 'inner initial').to.have.been.calledOnce.and.calledWith(
+ innerInst
+ );
+ expect(
+ innermost,
+ 'innerMost initial'
+ ).to.have.been.calledOnce.and.calledWith(innerInst.base);
+
+ outer.resetHistory();
+ inner.resetHistory();
+ innermost.resetHistory();
+ render(<Outer ref={outer} />, scratch);
+
+ expect(outer, 'outer update').not.to.have.been.called;
+ expect(inner, 'inner update').not.to.have.been.called;
+ expect(innermost, 'innerMost update').not.to.have.been.called;
+
+ innermost.resetHistory();
+ InnermostComponent = 'x-span';
+ render(<Outer ref={outer} />, scratch);
+
+ expect(innermost, 'innerMost swap');
+ expect(innermost.firstCall, 'innerMost swap').to.have.been.calledWith(null);
+ expect(innermost.secondCall, 'innerMost swap').to.have.been.calledWith(
+ innerInst.base
+ );
+ InnermostComponent = 'span';
+
+ outer.resetHistory();
+ inner.resetHistory();
+ innermost.resetHistory();
+ render(<div />, scratch);
+
+ expect(outer, 'outer unmount').to.have.been.calledOnce.and.calledWith(null);
+ expect(inner, 'inner unmount').to.have.been.calledOnce.and.calledWith(null);
+ expect(
+ innermost,
+ 'innerMost unmount'
+ ).to.have.been.calledOnce.and.calledWith(null);
+ });
+
+ // Test for #1143
+ it('should not pass ref into component as a prop', () => {
+ let foo = spy('foo'),
+ bar = spy('bar');
+
+ class Foo extends Component {
+ render() {
+ return <div />;
+ }
+ }
+ const Bar = spy('Bar', () => <div />);
+
+ sinon.spy(Foo.prototype, 'render');
+
+ render(
+ <div>
+ <Foo ref={foo} a="a" />
+ <Bar ref={bar} b="b" />
+ </div>,
+ scratch
+ );
+
+ expect(Foo.prototype.render).to.have.been.calledWithMatch(
+ { ref: sinon.match.falsy, a: 'a' },
+ {},
+ {}
+ );
+ expect(Bar).to.have.been.calledWithMatch(
+ { b: 'b', ref: sinon.match.falsy },
+ {}
+ );
+ });
+
+ // Test for #232
+ it('should only null refs after unmount', () => {
+ let outer, inner;
+
+ class TestUnmount extends Component {
+ componentWillUnmount() {
+ expect(this).to.have.property('outer', outer);
+ expect(this).to.have.property('inner', inner);
+
+ setTimeout(() => {
+ expect(this).to.have.property('outer', null);
+ expect(this).to.have.property('inner', null);
+ });
+ }
+
+ render() {
+ return (
+ <div id="outer" ref={c => (this.outer = c)}>
+ <div id="inner" ref={c => (this.inner = c)} />
+ </div>
+ );
+ }
+ }
+
+ sinon.spy(TestUnmount.prototype, 'componentWillUnmount');
+
+ render(
+ <div>
+ <TestUnmount />
+ </div>,
+ scratch
+ );
+ outer = scratch.querySelector('#outer');
+ inner = scratch.querySelector('#inner');
+
+ expect(TestUnmount.prototype.componentWillUnmount).not.to.have.been.called;
+
+ render(<div />, scratch);
+ expect(TestUnmount.prototype.componentWillUnmount).to.have.been.calledOnce;
+ });
+
+ it('should null and re-invoke refs when swapping component root element type', () => {
+ let inst;
+
+ class App extends Component {
+ render() {
+ return (
+ <div>
+ <Child />
+ </div>
+ );
+ }
+ }
+
+ class Child extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = { show: false };
+ inst = this;
+ }
+ handleMount() {}
+ render(_, { show }) {
+ if (!show) return <div id="div" ref={this.handleMount} />;
+ return (
+ <span id="span" ref={this.handleMount}>
+ some test content
+ </span>
+ );
+ }
+ }
+ sinon.spy(Child.prototype, 'handleMount');
+
+ render(<App />, scratch);
+ expect(inst.handleMount).to.have.been.calledOnce.and.calledWith(
+ scratch.querySelector('#div')
+ );
+ inst.handleMount.resetHistory();
+
+ inst.setState({ show: true });
+ rerender();
+ expect(inst.handleMount).to.have.been.calledTwice;
+ expect(inst.handleMount.firstCall).to.have.been.calledWith(null);
+ expect(inst.handleMount.secondCall).to.have.been.calledWith(
+ scratch.querySelector('#span')
+ );
+ inst.handleMount.resetHistory();
+
+ inst.setState({ show: false });
+ rerender();
+ expect(inst.handleMount).to.have.been.calledTwice;
+ expect(inst.handleMount.firstCall).to.have.been.calledWith(null);
+ expect(inst.handleMount.secondCall).to.have.been.calledWith(
+ scratch.querySelector('#div')
+ );
+ });
+
+ it('should add refs to components representing DOM nodes with no attributes if they have been pre-rendered', () => {
+ // Simulate pre-render
+ let parent = document.createElement('div');
+ let child = document.createElement('div');
+ parent.appendChild(child);
+ scratch.appendChild(parent); // scratch contains: <div><div></div></div>
+
+ let ref = spy('ref');
+
+ class Wrapper extends Component {
+ render() {
+ return <div />;
+ }
+ }
+
+ render(
+ <div>
+ <Wrapper ref={c => ref(c.base)} />
+ </div>,
+ scratch
+ );
+ expect(ref).to.have.been.calledOnce.and.calledWith(
+ scratch.firstChild.firstChild
+ );
+ });
+
+ // Test for #1177
+ it('should call ref after children are rendered', done => {
+ let input;
+ function autoFocus(el) {
+ if (el) {
+ input = el;
+
+ // Chrome bug: It will somehow drop the focus event if it fires too soon.
+ // See https://stackoverflow.com/questions/17384464/
+ setTimeout(() => {
+ el.focus();
+ done();
+ }, 1);
+ }
+ }
+
+ render(<input type="text" ref={autoFocus} value="foo" />, scratch);
+ expect(input.value).to.equal('foo');
+ });
+
+ it('should correctly set nested child refs', () => {
+ const ref = createRef();
+ const App = ({ open }) =>
+ open ? (
+ <div class="open" key="open">
+ <div ref={ref} />
+ </div>
+ ) : (
+ <div class="closes" key="closed">
+ <div ref={ref} />
+ </div>
+ );
+
+ render(<App />, scratch);
+ expect(ref.current).to.not.be.null;
+
+ render(<App open />, scratch);
+ expect(ref.current).to.not.be.null;
+ });
+
+ it('should correctly call child refs for un-keyed children on re-render', () => {
+ let el = null;
+ let ref = e => {
+ el = e;
+ };
+
+ class App extends Component {
+ render({ headerVisible }) {
+ return (
+ <div>
+ {headerVisible && <div>foo</div>}
+ <div ref={ref}>bar</div>
+ </div>
+ );
+ }
+ }
+
+ render(<App headerVisible />, scratch);
+ expect(el).to.not.be.equal(null);
+
+ render(<App />, scratch);
+ expect(el).to.not.be.equal(null);
+ });
+});
diff --git a/preact/test/browser/render.test.js b/preact/test/browser/render.test.js
new file mode 100644
index 0000000..63fb0c4
--- /dev/null
+++ b/preact/test/browser/render.test.js
@@ -0,0 +1,1164 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component, options } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ getMixedArray,
+ mixedArrayHTML,
+ serializeHtml,
+ supportsDataList,
+ sortAttributes,
+ spyOnElementAttributes,
+ createEvent
+} from '../_util/helpers';
+import { clearLog, getLog, logCall } from '../_util/logCall';
+import { useState } from 'preact/hooks';
+
+/** @jsx createElement */
+
+function getAttributes(node) {
+ let attrs = {};
+ for (let i = node.attributes.length; i--; ) {
+ attrs[node.attributes[i].name] = node.attributes[i].value;
+ }
+ return attrs;
+}
+
+const isIE11 = /Trident\//.test(navigator.userAgent);
+
+describe('render()', () => {
+ let scratch, rerender;
+
+ let resetAppendChild;
+ let resetInsertBefore;
+ let resetRemoveChild;
+ let resetRemove;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ before(() => {
+ resetAppendChild = logCall(Element.prototype, 'appendChild');
+ resetInsertBefore = logCall(Element.prototype, 'insertBefore');
+ resetRemoveChild = logCall(Element.prototype, 'removeChild');
+ resetRemove = logCall(Element.prototype, 'remove');
+ });
+
+ after(() => {
+ resetAppendChild();
+ resetInsertBefore();
+ resetRemoveChild();
+ resetRemove();
+ });
+
+ it('should rerender when value from "" to 0', () => {
+ render('', scratch);
+ expect(scratch.innerHTML).to.equal('');
+
+ render(0, scratch);
+ expect(scratch.innerHTML).to.equal('0');
+ });
+
+ it('should render an empty text node given an empty string', () => {
+ render('', scratch);
+ let c = scratch.childNodes;
+ expect(c).to.have.length(1);
+ expect(c[0].data).to.equal('');
+ expect(c[0].nodeName).to.equal('#text');
+ });
+
+ it('should allow node type change with content', () => {
+ render(<span>Bad</span>, scratch);
+ render(<div>Good</div>, scratch);
+ expect(scratch.innerHTML).to.eql(`<div>Good</div>`);
+ });
+
+ it('should not render when detecting JSON-injection', () => {
+ const vnode = JSON.parse('{"type":"span","children":"Malicious"}');
+ render(vnode, scratch);
+ expect(scratch.firstChild).to.be.null;
+ });
+
+ it('should create empty nodes (<* />)', () => {
+ render(<div />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.childNodes[0].nodeName).to.equal('DIV');
+
+ scratch.parentNode.removeChild(scratch);
+ scratch = document.createElement('div');
+ (document.body || document.documentElement).appendChild(scratch);
+
+ render(<span />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.childNodes[0].nodeName).to.equal('SPAN');
+ });
+
+ it('should not throw error in IE11 with type date', () => {
+ expect(() => render(<input type="date" />, scratch)).to.not.throw();
+ });
+
+ it('should support custom tag names', () => {
+ render(<foo />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.firstChild).to.have.property('nodeName', 'FOO');
+
+ scratch.parentNode.removeChild(scratch);
+ scratch = document.createElement('div');
+ (document.body || document.documentElement).appendChild(scratch);
+
+ render(<x-bar />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.firstChild).to.have.property('nodeName', 'X-BAR');
+ });
+
+ it('should support the form attribute', () => {
+ render(
+ <div>
+ <form id="myform" />
+ <button form="myform">test</button>
+ <input form="myform" />
+ </div>,
+ scratch
+ );
+ const div = scratch.childNodes[0];
+ const form = div.childNodes[0];
+ const button = div.childNodes[1];
+ const input = div.childNodes[2];
+
+ // IE11 doesn't support the form attribute
+ if (!isIE11) {
+ expect(button).to.have.property('form', form);
+ expect(input).to.have.property('form', form);
+ }
+ });
+
+ it('should allow VNode reuse', () => {
+ let reused = <div class="reuse">Hello World!</div>;
+ render(
+ <div>
+ {reused}
+ <hr />
+ {reused}
+ </div>,
+ scratch
+ );
+ expect(serializeHtml(scratch)).to.eql(
+ `<div><div class="reuse">Hello World!</div><hr><div class="reuse">Hello World!</div></div>`
+ );
+
+ render(
+ <div>
+ <hr />
+ {reused}
+ </div>,
+ scratch
+ );
+ expect(serializeHtml(scratch)).to.eql(
+ `<div><hr><div class="reuse">Hello World!</div></div>`
+ );
+ });
+
+ it('should merge new elements when called multiple times', () => {
+ render(<div />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.firstChild).to.have.property('nodeName', 'DIV');
+ expect(scratch.innerHTML).to.equal('<div></div>');
+
+ render(<span />, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.firstChild).to.have.property('nodeName', 'SPAN');
+ expect(scratch.innerHTML).to.equal('<span></span>');
+
+ render(<span class="hello">Hello!</span>, scratch);
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.firstChild).to.have.property('nodeName', 'SPAN');
+ expect(scratch.innerHTML).to.equal('<span class="hello">Hello!</span>');
+ });
+
+ it('should nest empty nodes', () => {
+ render(
+ <div>
+ <span />
+ <foo />
+ <x-bar />
+ </div>,
+ scratch
+ );
+
+ expect(scratch.childNodes).to.have.length(1);
+ expect(scratch.childNodes[0].nodeName).to.equal('DIV');
+
+ let c = scratch.childNodes[0].childNodes;
+ expect(c).to.have.length(3);
+ expect(c[0].nodeName).to.equal('SPAN');
+ expect(c[1].nodeName).to.equal('FOO');
+ expect(c[2].nodeName).to.equal('X-BAR');
+ });
+
+ it('should not render falsy values', () => {
+ render(
+ <div>
+ {null},{undefined},{false},{0},{NaN}
+ </div>,
+ scratch
+ );
+
+ expect(scratch.firstChild).to.have.property('innerHTML', ',,,0,NaN');
+ });
+
+ it('should not render null', () => {
+ render(null, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ expect(scratch.childNodes).to.have.length(0);
+ });
+
+ it('should not render undefined', () => {
+ render(undefined, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ expect(scratch.childNodes).to.have.length(0);
+ });
+
+ it('should not render boolean true', () => {
+ render(true, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ expect(scratch.childNodes).to.have.length(0);
+ });
+
+ it('should not render boolean false', () => {
+ render(false, scratch);
+ expect(scratch.innerHTML).to.equal('');
+ expect(scratch.childNodes).to.have.length(0);
+ });
+
+ it('should not render children when using function children', () => {
+ render(<div>{() => {}}</div>, scratch);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should render NaN as text content', () => {
+ render(NaN, scratch);
+ expect(scratch.innerHTML).to.equal('NaN');
+ });
+
+ it('should render numbers (0) as text content', () => {
+ render(0, scratch);
+ expect(scratch.innerHTML).to.equal('0');
+ });
+
+ it('should render numbers (42) as text content', () => {
+ render(42, scratch);
+ expect(scratch.innerHTML).to.equal('42');
+ });
+
+ it('should render bigint as text content', () => {
+ // Skip in browsers not supporting big integers
+ if (typeof BigInt === 'undefined') {
+ return;
+ }
+
+ // eslint-disable-next-line no-undef, new-cap
+ render(BigInt(4), scratch);
+ expect(scratch.innerHTML).to.equal('4');
+ });
+
+ it('should render strings as text content', () => {
+ render('Testing, huh! How is it going?', scratch);
+ expect(scratch.innerHTML).to.equal('Testing, huh! How is it going?');
+ });
+
+ it('should render arrays of mixed elements', () => {
+ render(getMixedArray(), scratch);
+ expect(scratch.innerHTML).to.equal(mixedArrayHTML);
+ });
+
+ it('should clear falsy attributes', () => {
+ render(
+ <div
+ anull="anull"
+ aundefined="aundefined"
+ afalse="afalse"
+ anan="aNaN"
+ a0="a0"
+ />,
+ scratch
+ );
+
+ render(
+ <div
+ anull={null}
+ aundefined={undefined}
+ afalse={false}
+ anan={NaN}
+ a0={0}
+ />,
+ scratch
+ );
+
+ expect(
+ getAttributes(scratch.firstChild),
+ 'from previous truthy values'
+ ).to.eql({
+ a0: '0',
+ anan: 'NaN'
+ });
+ });
+
+ it('should not render falsy attributes on hydrate', () => {
+ render(
+ <div
+ anull={null}
+ aundefined={undefined}
+ afalse={false}
+ anan={NaN}
+ a0={0}
+ />,
+ scratch
+ );
+
+ expect(getAttributes(scratch.firstChild), 'initial render').to.eql({
+ a0: '0',
+ anan: 'NaN'
+ });
+ });
+
+ it('should clear falsy input values', () => {
+ // Note: this test just demonstrates the default browser behavior
+ render(
+ <div>
+ <input value={0} />
+ <input value={false} />
+ <input value={null} />
+ <input value={undefined} />
+ </div>,
+ scratch
+ );
+
+ let root = scratch.firstChild;
+ expect(root.children[0]).to.have.property('value', '0');
+ expect(root.children[1]).to.have.property('value', 'false');
+ expect(root.children[2]).to.have.property('value', '');
+ expect(root.children[3]).to.have.property('value', '');
+ });
+
+ it('should set value inside the specified range', () => {
+ render(
+ <input type="range" value={0.5} min="0" max="1" step="0.05" />,
+ scratch
+ );
+ expect(scratch.firstChild.value).to.equal('0.5');
+ });
+
+ // IE or IE Edge will throw when attribute values don't conform to the
+ // spec. That's the correct behaviour, but bad for this test...
+ if (!/(Edge|MSIE|Trident)/.test(navigator.userAgent)) {
+ it('should not clear falsy DOM properties', () => {
+ function test(val) {
+ render(
+ <div>
+ <input value={val} />
+ <table border={val} />
+ </div>,
+ scratch
+ );
+ }
+
+ test('2');
+ test(false);
+ expect(scratch.innerHTML).to.equal(
+ '<div><input><table border="false"></table></div>',
+ 'for false'
+ );
+
+ test('3');
+ test(null);
+ expect(scratch.innerHTML).to.equal(
+ '<div><input><table border=""></table></div>',
+ 'for null'
+ );
+
+ test('4');
+ test(undefined);
+ expect(scratch.innerHTML).to.equal(
+ '<div><input><table border=""></table></div>',
+ 'for undefined'
+ );
+ });
+ }
+
+ // Test for preactjs/preact#651
+ it('should set enumerable boolean attribute', () => {
+ render(<input spellcheck={false} />, scratch);
+ expect(scratch.firstChild.spellcheck).to.equal(false);
+ });
+
+ it('should render download attribute', () => {
+ render(<a download="" />, scratch);
+ expect(scratch.firstChild.getAttribute('download')).to.equal('');
+
+ render(<a download={null} />, scratch);
+ expect(scratch.firstChild.getAttribute('download')).to.equal(null);
+ });
+
+ it('should not set tagName', () => {
+ expect(() => render(<input tagName="div" />, scratch)).not.to.throw();
+ });
+
+ it('should apply string attributes', () => {
+ render(<div foo="bar" data-foo="databar" />, scratch);
+ expect(serializeHtml(scratch)).to.equal(
+ '<div data-foo="databar" foo="bar"></div>'
+ );
+ });
+
+ it('should not serialize function props as attributes', () => {
+ render(<div click={function a() {}} ONCLICK={function b() {}} />, scratch);
+
+ let div = scratch.childNodes[0];
+ expect(div.attributes.length).to.equal(0);
+ });
+
+ it('should serialize object props as attributes', () => {
+ render(
+ <div
+ foo={{ a: 'b' }}
+ bar={{
+ toString() {
+ return 'abc';
+ }
+ }}
+ />,
+ scratch
+ );
+
+ let div = scratch.childNodes[0];
+ expect(div.attributes.length).to.equal(2);
+
+ // Normalize attribute order because it's different in various browsers
+ let normalized = {};
+ for (let i = 0; i < div.attributes.length; i++) {
+ let attr = div.attributes[i];
+ normalized[attr.name] = attr.value;
+ }
+
+ expect(normalized).to.deep.equal({
+ bar: 'abc',
+ foo: '[object Object]'
+ });
+ });
+
+ it('should apply class as String', () => {
+ render(<div class="foo" />, scratch);
+ expect(scratch.childNodes[0]).to.have.property('className', 'foo');
+ });
+
+ it('should alias className to class', () => {
+ render(<div className="bar" />, scratch);
+ expect(scratch.childNodes[0]).to.have.property('className', 'bar');
+ });
+
+ it('should support false aria-* attributes', () => {
+ render(<div aria-checked="false" />, scratch);
+ expect(scratch.firstChild.getAttribute('aria-checked')).to.equal('false');
+ });
+
+ it('should set checked attribute on custom elements without checked property', () => {
+ render(<o-checkbox checked />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<o-checkbox checked="true"></o-checkbox>'
+ );
+ });
+
+ it('should set value attribute on custom elements without value property', () => {
+ render(<o-input value="test" />, scratch);
+ expect(scratch.innerHTML).to.equal('<o-input value="test"></o-input>');
+ });
+
+ it('should mask value on password input elements', () => {
+ render(<input value="xyz" type="password" />, scratch);
+ expect(scratch.innerHTML).to.equal('<input type="password">');
+ });
+
+ it('should unset href if null || undefined', () => {
+ render(
+ <pre>
+ <a href="#">href="#"</a>
+ <a href={undefined}>href="undefined"</a>
+ <a href={null}>href="null"</a>
+ <a href={''}>href="''"</a>
+ </pre>,
+ scratch
+ );
+
+ const links = scratch.querySelectorAll('a');
+ expect(links[0].hasAttribute('href')).to.equal(true);
+ expect(links[1].hasAttribute('href')).to.equal(false);
+ expect(links[2].hasAttribute('href')).to.equal(false);
+ expect(links[3].hasAttribute('href')).to.equal(true);
+ });
+
+ describe('dangerouslySetInnerHTML', () => {
+ it('should support dangerouslySetInnerHTML', () => {
+ let html = '<b>foo &amp; bar</b>';
+ // eslint-disable-next-line react/no-danger
+ render(<div dangerouslySetInnerHTML={{ __html: html }} />, scratch);
+
+ expect(scratch.firstChild, 'set').to.have.property('innerHTML', html);
+ expect(scratch.innerHTML).to.equal('<div>' + html + '</div>');
+
+ render(
+ <div>
+ a<strong>b</strong>
+ </div>,
+ scratch
+ );
+
+ expect(scratch, 'unset').to.have.property(
+ 'innerHTML',
+ `<div>a<strong>b</strong></div>`
+ );
+
+ // eslint-disable-next-line react/no-danger
+ render(<div dangerouslySetInnerHTML={{ __html: html }} />, scratch);
+ expect(scratch.innerHTML, 're-set').to.equal('<div>' + html + '</div>');
+ });
+
+ it('should apply proper mutation for VNodes with dangerouslySetInnerHTML attr', () => {
+ let thing;
+ class Thing extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = { html: this.props.html };
+ thing = this;
+ }
+ render(props, { html }) {
+ // eslint-disable-next-line react/no-danger
+ return html ? (
+ <div dangerouslySetInnerHTML={{ __html: html }} />
+ ) : (
+ <div />
+ );
+ }
+ }
+
+ render(<Thing html="<b><i>test</i></b>" />, scratch);
+ expect(scratch.innerHTML).to.equal('<div><b><i>test</i></b></div>');
+
+ thing.setState({ html: false });
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div></div>');
+
+ thing.setState({ html: '<foo><bar>test</bar></foo>' });
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ '<div><foo><bar>test</bar></foo></div>'
+ );
+ });
+
+ it('should not hydrate with dangerouslySetInnerHTML', () => {
+ let html = '<b>foo &amp; bar</b>';
+ scratch.innerHTML = `<div>${html}</div>`;
+ // eslint-disable-next-line react/no-danger
+ render(<div dangerouslySetInnerHTML={{ __html: html }} />, scratch);
+
+ expect(scratch.firstChild).to.have.property('innerHTML', html);
+ expect(scratch.innerHTML).to.equal(`<div>${html}</div>`);
+ });
+
+ it('should avoid reapplying innerHTML when __html property of dangerouslySetInnerHTML attr remains unchanged', () => {
+ class Thing extends Component {
+ render() {
+ // eslint-disable-next-line react/no-danger
+ return (
+ <div dangerouslySetInnerHTML={{ __html: '<span>same</span>' }} />
+ );
+ }
+ }
+
+ let thing;
+ render(<Thing ref={r => (thing = r)} />, scratch);
+
+ let firstInnerHTMLChild = scratch.firstChild.firstChild;
+
+ // Re-render
+ thing.forceUpdate();
+
+ expect(firstInnerHTMLChild).to.equalNode(scratch.firstChild.firstChild);
+ });
+
+ it('should unmount dangerouslySetInnerHTML', () => {
+ let set;
+
+ const TextDiv = () => (
+ <div dangerouslySetInnerHTML={{ __html: '' }}>some text</div>
+ );
+
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ set = this.setState.bind(this);
+ this.state = { show: true };
+ }
+
+ render() {
+ return this.state.show && <TextDiv />;
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+
+ set({ show: false });
+ rerender();
+ expect(scratch.innerHTML).to.equal('');
+ });
+ });
+
+ it('should reconcile mutated DOM attributes', () => {
+ let check = p => render(<input type="checkbox" checked={p} />, scratch),
+ value = () => scratch.lastChild.checked,
+ setValue = p => (scratch.lastChild.checked = p);
+ check(true);
+ expect(value()).to.equal(true);
+ check(false);
+ expect(value()).to.equal(false);
+ check(true);
+ expect(value()).to.equal(true);
+ setValue(true);
+ check(false);
+ expect(value()).to.equal(false);
+ setValue(false);
+ check(true);
+ expect(value()).to.equal(true);
+ });
+
+ it('should reorder child pairs', () => {
+ render(
+ <div>
+ <a>a</a>
+ <b>b</b>
+ </div>,
+ scratch
+ );
+
+ let a = scratch.firstChild.firstChild;
+ let b = scratch.firstChild.lastChild;
+
+ expect(a).to.have.property('nodeName', 'A');
+ expect(b).to.have.property('nodeName', 'B');
+
+ render(
+ <div>
+ <b>b</b>
+ <a>a</a>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.firstChild.firstChild).to.equalNode(b);
+ expect(scratch.firstChild.lastChild).to.equalNode(a);
+ });
+
+ // Discussion: https://github.com/preactjs/preact/issues/287
+ // <datalist> is not supported in Safari, even though the element
+ // constructor is present
+ if (supportsDataList()) {
+ it('should allow <input list /> to pass through as an attribute', () => {
+ render(
+ <div>
+ <input type="range" min="0" max="100" list="steplist" />
+ <datalist id="steplist">
+ <option>0</option>
+ <option>50</option>
+ <option>100</option>
+ </datalist>
+ </div>,
+ scratch
+ );
+
+ let html = scratch.firstElementChild.firstElementChild.outerHTML;
+ expect(sortAttributes(html)).to.equal(
+ sortAttributes('<input type="range" min="0" max="100" list="steplist">')
+ );
+ });
+ }
+
+ // Issue #2284
+ it('should not throw when setting size to an invalid value', () => {
+ // These values are usually used to reset the `size` attribute to its
+ // initial state.
+ expect(() => render(<input size={undefined} />, scratch)).to.not.throw();
+ expect(() => render(<input size={null} />, scratch)).to.not.throw();
+ expect(() => render(<input size={0} />, scratch)).to.not.throw();
+ });
+
+ it('should not execute append operation when child is at last', () => {
+ // See preactjs/preact#717 for discussion about the issue this addresses
+
+ let todoText = 'new todo that I should complete';
+ let input;
+ let setText;
+ let addTodo;
+
+ const ENTER = 13;
+
+ class TodoList extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { todos: [], text: '' };
+ setText = this.setText = this.setText.bind(this);
+ addTodo = this.addTodo = this.addTodo.bind(this);
+ }
+ setText(e) {
+ this.setState({ text: e.target.value });
+ }
+ addTodo(e) {
+ if (e.keyCode === ENTER) {
+ let { todos, text } = this.state;
+ todos = todos.concat({ text });
+ this.setState({ todos, text: '' });
+ }
+ }
+ render() {
+ const { todos, text } = this.state;
+ return (
+ <div onKeyDown={this.addTodo}>
+ {todos.map(todo => [
+ <span>{todo.text}</span>,
+ <span>
+ {' '}
+ [ <a href="javascript:;">Delete</a> ]
+ </span>,
+ <br />
+ ])}
+ <input value={text} onInput={this.setText} ref={i => (input = i)} />
+ </div>
+ );
+ }
+ }
+
+ render(<TodoList />, scratch);
+
+ // Simulate user typing
+ input.focus();
+ input.value = todoText;
+ setText({
+ target: input
+ });
+
+ // Commit the user typing setState call
+ rerender();
+
+ // Simulate user pressing enter
+ addTodo({
+ keyCode: ENTER
+ });
+
+ // Before Preact rerenders, focus should be on the input
+ expect(document.activeElement).to.equalNode(input);
+
+ rerender();
+
+ // After Preact rerenders, focus should remain on the input
+ expect(document.activeElement).to.equalNode(input);
+ expect(scratch.innerHTML).to.contain(`<span>${todoText}</span>`);
+ });
+
+ it('should keep value of uncontrolled inputs', () => {
+ render(<input value={undefined} />, scratch);
+ scratch.firstChild.value = 'foo';
+ render(<input value={undefined} />, scratch);
+ expect(scratch.firstChild.value).to.equal('foo');
+ });
+
+ it('should keep value of uncontrolled checkboxes', () => {
+ render(<input type="checkbox" checked={undefined} />, scratch);
+ scratch.firstChild.checked = true;
+ render(<input type="checkbox" checked={undefined} />, scratch);
+ expect(scratch.firstChild.checked).to.equal(true);
+ });
+
+ // #2756
+ it('should set progress value to 0', () => {
+ render(<progress value={0} max="100" />, scratch);
+ expect(scratch.firstChild.value).to.equal(0);
+ expect(scratch.firstChild.getAttribute('value')).to.equal('0');
+ });
+
+ it('should always diff `checked` and `value` properties against the DOM', () => {
+ // See https://github.com/preactjs/preact/issues/1324
+
+ let inputs;
+ let text;
+ let checkbox;
+
+ class Inputs extends Component {
+ render() {
+ return (
+ <div>
+ <input value={'Hello'} ref={el => (text = el)} />
+ <input type="checkbox" checked ref={el => (checkbox = el)} />
+ </div>
+ );
+ }
+ }
+
+ render(<Inputs ref={x => (inputs = x)} />, scratch);
+
+ expect(text.value).to.equal('Hello');
+ expect(checkbox.checked).to.equal(true);
+
+ text.value = 'World';
+ checkbox.checked = false;
+
+ inputs.forceUpdate();
+ rerender();
+
+ expect(text.value).to.equal('Hello');
+ expect(checkbox.checked).to.equal(true);
+ });
+
+ it('should always diff `contenteditable` `innerHTML` against the DOM', () => {
+ // This tests that we do not cause any cursor jumps in contenteditable fields
+ // See https://github.com/preactjs/preact/issues/2691
+
+ function Editable() {
+ const [value, setValue] = useState('Hello');
+
+ return (
+ <div
+ contentEditable
+ dangerouslySetInnerHTML={{ __html: value }}
+ onInput={e => setValue(e.currentTarget.innerHTML)}
+ />
+ );
+ }
+
+ render(<Editable />, scratch);
+
+ let editable = scratch.querySelector('[contenteditable]');
+
+ // modify the innerHTML and set the caret to character 2 to simulate a user typing
+ editable.innerHTML = 'World';
+
+ const range = document.createRange();
+ range.selectNodeContents(editable);
+ range.setStart(editable.childNodes[0], 2);
+ range.collapse(true);
+ const sel = window.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+
+ // ensure we didn't mess up setting the cursor to position 2
+ expect(window.getSelection().getRangeAt(0).startOffset).to.equal(2);
+
+ // dispatch the input event to tell preact to re-render
+ editable.dispatchEvent(createEvent('input'));
+ rerender();
+
+ // ensure innerHTML is still correct (was not an issue before) and
+ // more importantly the caret is still at character 2
+ editable = scratch.querySelector('[contenteditable]');
+ expect(editable.innerHTML).to.equal('World');
+ expect(window.getSelection().getRangeAt(0).startOffset).to.equal(2);
+ });
+
+ it('should not re-render when a component returns undefined', () => {
+ let Dialog = () => undefined;
+ let updateState;
+ class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { name: '' };
+ updateState = () => this.setState({ name: ', friend' });
+ }
+
+ render(props, { name }) {
+ return (
+ <div>
+ <Dialog />
+ <h1 class="fade-down">Hi{name}</h1>
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ clearLog();
+
+ updateState();
+ rerender();
+
+ // We don't log text updates
+ expect(getLog()).to.deep.equal([]);
+ });
+
+ it('should not lead to stale DOM nodes', () => {
+ let i = 0;
+ let updateApp;
+ class App extends Component {
+ render() {
+ updateApp = () => this.forceUpdate();
+ return <Parent />;
+ }
+ }
+
+ let updateParent;
+ function Parent() {
+ updateParent = () => this.forceUpdate();
+ i++;
+ return <Child i={i} />;
+ }
+
+ function Child({ i }) {
+ return i < 3 ? null : <div>foo</div>;
+ }
+
+ render(<App />, scratch);
+
+ updateApp();
+ rerender();
+ updateParent();
+ rerender();
+ updateApp();
+ rerender();
+
+ // Without a fix it would render: `<div>foo</div><div></div>`
+ expect(scratch.innerHTML).to.equal('<div>foo</div>');
+ });
+
+ // see preact/#1327
+ it('should not reuse unkeyed components', () => {
+ class X extends Component {
+ constructor() {
+ super();
+ this.state = { i: 0 };
+ }
+
+ update() {
+ this.setState(prev => ({ i: prev.i + 1 }));
+ }
+
+ componentWillUnmount() {
+ clearTimeout(this.id);
+ }
+
+ render() {
+ return <div>{this.state.i}</div>;
+ }
+ }
+
+ let ref;
+ let updateApp;
+ class App extends Component {
+ constructor() {
+ super();
+ this.state = { i: 0 };
+ updateApp = () => this.setState(prev => ({ i: prev.i ^ 1 }));
+ }
+
+ render() {
+ return (
+ <div>
+ {this.state.i === 0 && <X />}
+ <X ref={node => (ref = node)} />
+ </div>
+ );
+ }
+ }
+
+ render(<App />, scratch);
+ expect(scratch.textContent).to.equal('00');
+
+ ref.update();
+ updateApp();
+ rerender();
+ expect(scratch.textContent).to.equal('1');
+
+ updateApp();
+ rerender();
+
+ expect(scratch.textContent).to.equal('01');
+ });
+
+ it('should not cause infinite loop with referentially equal props', () => {
+ let i = 0;
+ let prevDiff = options._diff;
+ options._diff = () => {
+ if (++i > 10) {
+ options._diff = prevDiff;
+ throw new Error('Infinite loop');
+ }
+ };
+
+ function App({ children, ...rest }) {
+ return (
+ <div {...rest}>
+ <div {...rest}>{children}</div>
+ </div>
+ );
+ }
+
+ render(<App>10</App>, scratch);
+ expect(scratch.textContent).to.equal('10');
+ options._diff = prevDiff;
+ });
+
+ it('should not call options.debounceRendering unnecessarily', () => {
+ let comp;
+
+ class A extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { updates: 0 };
+ comp = this;
+ }
+
+ render() {
+ return <div>{this.state.updates}</div>;
+ }
+ }
+
+ render(<A />, scratch);
+ expect(scratch.innerHTML).to.equal('<div>0</div>');
+
+ const sandbox = sinon.createSandbox();
+ try {
+ sandbox.spy(options, 'debounceRendering');
+
+ comp.setState({ updates: 1 }, () => {
+ comp.setState({ updates: 2 });
+ });
+ rerender();
+ expect(scratch.innerHTML).to.equal('<div>2</div>');
+
+ expect(options.debounceRendering).to.have.been.calledOnce;
+ } finally {
+ sandbox.restore();
+ }
+ });
+
+ it('should remove attributes on pre-existing DOM', () => {
+ const div = document.createElement('div');
+ div.setAttribute('class', 'red');
+ const span = document.createElement('span');
+ const text = document.createTextNode('Hi');
+
+ span.appendChild(text);
+ div.appendChild(span);
+ scratch.appendChild(div);
+
+ const App = () => (
+ <div>
+ <span>Bye</span>
+ </div>
+ );
+
+ render(<App />, scratch);
+ expect(serializeHtml(scratch)).to.equal('<div><span>Bye</span></div>');
+ });
+
+ it('should remove class attributes', () => {
+ const App = props => (
+ <div className={props.class}>
+ <span>Bye</span>
+ </div>
+ );
+
+ render(<App class="hi" />, scratch);
+ expect(scratch.innerHTML).to.equal(
+ '<div class="hi"><span>Bye</span></div>'
+ );
+
+ render(<App />, scratch);
+ expect(serializeHtml(scratch)).to.equal('<div><span>Bye</span></div>');
+ });
+
+ it('should not read DOM attributes on render without existing DOM', () => {
+ const attributesSpy = spyOnElementAttributes();
+ render(
+ <div id="wrapper">
+ <div id="page1">Page 1</div>
+ </div>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div id="wrapper"><div id="page1">Page 1</div></div>'
+ );
+
+ // IE11 doesn't allow modifying Element.prototype functions properly.
+ // Custom spies will never be called.
+ if (!isIE11) {
+ expect(attributesSpy.get).to.not.have.been.called;
+ }
+
+ render(
+ <div id="wrapper">
+ <div id="page2">Page 2</div>
+ </div>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal(
+ '<div id="wrapper"><div id="page2">Page 2</div></div>'
+ );
+
+ // IE11 doesn't allow modifying Element.prototype functions properly.
+ // Custom spies will never be called.
+ if (!isIE11) {
+ expect(attributesSpy.get).to.not.have.been.called;
+ }
+ });
+
+ // #2926
+ it('should not throw when changing contentEditable to undefined or null', () => {
+ render(<p contentEditable>foo</p>, scratch);
+
+ expect(() =>
+ render(<p contentEditable={undefined}>foo</p>, scratch)
+ ).to.not.throw();
+ expect(scratch.firstChild.contentEditable).to.equal('inherit');
+
+ expect(() =>
+ render(<p contentEditable={null}>foo</p>, scratch)
+ ).to.not.throw();
+ expect(scratch.firstChild.contentEditable).to.equal('inherit');
+ });
+
+ // #2926 Part 2
+ it('should allow setting contentEditable to false', () => {
+ render(
+ <div contentEditable>
+ <span>editable</span>
+ <p contentEditable={false}>not editable</p>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.firstChild.contentEditable).to.equal('true');
+ expect(scratch.querySelector('p').contentEditable).to.equal('false');
+ });
+
+ // #3060
+ it('should reset tabindex on undefined/null', () => {
+ const defaultValue = isIE11 ? 0 : -1;
+
+ render(<div tabIndex={0} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(0);
+ render(<div tabIndex={undefined} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(defaultValue);
+ render(<div tabIndex={null} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(defaultValue);
+
+ render(<div tabindex={0} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(0);
+ render(<div tabindex={undefined} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(defaultValue);
+ render(<div tabindex={null} />, scratch);
+ expect(scratch.firstChild.tabIndex).to.equal(defaultValue);
+ });
+});
diff --git a/preact/test/browser/replaceNode.test.js b/preact/test/browser/replaceNode.test.js
new file mode 100644
index 0000000..63cdd2d
--- /dev/null
+++ b/preact/test/browser/replaceNode.test.js
@@ -0,0 +1,239 @@
+import { createElement, render, Component } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ serializeHtml,
+ sortAttributes
+} from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('replaceNode parameter in render()', () => {
+ let scratch;
+
+ /**
+ * @param {HTMLDivElement} container
+ * @returns {HTMLDivElement[]}
+ */
+ function setupABCDom(container) {
+ return ['a', 'b', 'c'].map(id => {
+ const child = document.createElement('div');
+ child.id = id;
+ container.appendChild(child);
+
+ return child;
+ });
+ }
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should use replaceNode as render root and not inject into it', () => {
+ setupABCDom(scratch);
+ const childA = scratch.querySelector('#a');
+
+ render(<div id="a">contents</div>, scratch, childA);
+ expect(scratch.querySelector('#a')).to.equalNode(childA);
+ expect(childA.innerHTML).to.equal('contents');
+ });
+
+ it('should not remove siblings of replaceNode', () => {
+ setupABCDom(scratch);
+ const childA = scratch.querySelector('#a');
+
+ render(<div id="a" />, scratch, childA);
+ expect(scratch.innerHTML).to.equal(
+ '<div id="a"></div><div id="b"></div><div id="c"></div>'
+ );
+ });
+
+ it('should notice prop changes on replaceNode', () => {
+ setupABCDom(scratch);
+ const childA = scratch.querySelector('#a');
+
+ render(<div id="a" className="b" />, scratch, childA);
+ expect(sortAttributes(String(scratch.innerHTML))).to.equal(
+ sortAttributes(
+ '<div id="a" class="b"></div><div id="b"></div><div id="c"></div>'
+ )
+ );
+ });
+
+ it('should unmount existing components', () => {
+ const unmount = sinon.spy();
+ const mount = sinon.spy();
+ class App extends Component {
+ componentDidMount() {
+ mount();
+ }
+
+ componentWillUnmount() {
+ unmount();
+ }
+
+ render() {
+ return <div>App</div>;
+ }
+ }
+
+ render(
+ <div id="a">
+ <App />
+ </div>,
+ scratch
+ );
+ expect(scratch.innerHTML).to.equal('<div id="a"><div>App</div></div>');
+ expect(mount).to.be.calledOnce;
+
+ render(<div id="a">new</div>, scratch, scratch.querySelector('#a'));
+ expect(scratch.innerHTML).to.equal('<div id="a">new</div>');
+ expect(unmount).to.be.calledOnce;
+ });
+
+ it('should unmount existing components in prerendered HTML', () => {
+ const unmount = sinon.spy();
+ const mount = sinon.spy();
+ class App extends Component {
+ componentDidMount() {
+ mount();
+ }
+
+ componentWillUnmount() {
+ unmount();
+ }
+
+ render() {
+ return <span>App</span>;
+ }
+ }
+
+ scratch.innerHTML = `<div id="child"></div>`;
+
+ const childContainer = scratch.querySelector('#child');
+
+ render(<App />, childContainer);
+ expect(serializeHtml(childContainer)).to.equal('<span>App</span>');
+ expect(mount).to.be.calledOnce;
+
+ render(<div />, scratch, scratch.firstElementChild);
+ expect(serializeHtml(scratch)).to.equal('<div id=""></div>');
+ expect(unmount).to.be.calledOnce;
+ });
+
+ it('should render multiple render roots in one parentDom', () => {
+ setupABCDom(scratch);
+ const childA = scratch.querySelector('#a');
+ const childB = scratch.querySelector('#b');
+ const childC = scratch.querySelector('#c');
+
+ const expectedA = '<div id="a">childA</div>';
+ const expectedB = '<div id="b">childB</div>';
+ const expectedC = '<div id="c">childC</div>';
+
+ render(<div id="a">childA</div>, scratch, childA);
+ render(<div id="b">childB</div>, scratch, childB);
+ render(<div id="c">childC</div>, scratch, childC);
+
+ expect(scratch.innerHTML).to.equal(`${expectedA}${expectedB}${expectedC}`);
+ });
+
+ it('should call unmount when working with replaceNode', () => {
+ const mountSpy = sinon.spy();
+ const unmountSpy = sinon.spy();
+ class MyComponent extends Component {
+ componentDidMount() {
+ mountSpy();
+ }
+ componentWillUnmount() {
+ unmountSpy();
+ }
+ render() {
+ return <div>My Component</div>;
+ }
+ }
+
+ const container = document.createElement('div');
+ scratch.appendChild(container);
+
+ render(<MyComponent />, scratch, container);
+ expect(mountSpy).to.be.calledOnce;
+
+ render(<div>Not my component</div>, document.body, container);
+ expect(unmountSpy).to.be.calledOnce;
+ });
+
+ it('should double replace', () => {
+ const container = document.createElement('div');
+ scratch.appendChild(container);
+
+ render(<div>Hello</div>, scratch, scratch.firstElementChild);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+
+ render(<div>Hello</div>, scratch, scratch.firstElementChild);
+ expect(scratch.innerHTML).to.equal('<div>Hello</div>');
+ });
+
+ it('should replaceNode after rendering', () => {
+ function App({ i }) {
+ return <p>{i}</p>;
+ }
+
+ render(<App i={2} />, scratch);
+ expect(scratch.innerHTML).to.equal('<p>2</p>');
+
+ render(<App i={3} />, scratch, scratch.firstChild);
+ expect(scratch.innerHTML).to.equal('<p>3</p>');
+ });
+
+ it("shouldn't remove elements on subsequent renders with replaceNode", () => {
+ const placeholder = document.createElement('div');
+ scratch.appendChild(placeholder);
+ const App = () => (
+ <div>
+ New content
+ <button>Update</button>
+ </div>
+ );
+
+ render(<App />, scratch, placeholder);
+ expect(scratch.innerHTML).to.equal(
+ '<div>New content<button>Update</button></div>'
+ );
+
+ render(<App />, scratch, placeholder);
+ expect(scratch.innerHTML).to.equal(
+ '<div>New content<button>Update</button></div>'
+ );
+ });
+
+ it('should remove redundant elements on subsequent renders with replaceNode', () => {
+ const placeholder = document.createElement('div');
+ scratch.appendChild(placeholder);
+ const App = () => (
+ <div>
+ New content
+ <button>Update</button>
+ </div>
+ );
+
+ render(<App />, scratch, placeholder);
+ expect(scratch.innerHTML).to.equal(
+ '<div>New content<button>Update</button></div>'
+ );
+
+ placeholder.appendChild(document.createElement('span'));
+ expect(scratch.innerHTML).to.equal(
+ '<div>New content<button>Update</button><span></span></div>'
+ );
+
+ render(<App />, scratch, placeholder);
+ expect(scratch.innerHTML).to.equal(
+ '<div>New content<button>Update</button></div>'
+ );
+ });
+});
diff --git a/preact/test/browser/select.test.js b/preact/test/browser/select.test.js
new file mode 100644
index 0000000..74b08ce
--- /dev/null
+++ b/preact/test/browser/select.test.js
@@ -0,0 +1,72 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Select', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should set <select> value', () => {
+ function App() {
+ return (
+ <select value="B">
+ <option value="A">A</option>
+ <option value="B">B</option>
+ <option value="C">C</option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(scratch.firstChild.value).to.equal('B');
+ });
+
+ it('should set value with selected', () => {
+ function App() {
+ return (
+ <select>
+ <option value="A">A</option>
+ <option selected value="B">
+ B
+ </option>
+ <option value="C">C</option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ expect(scratch.firstChild.value).to.equal('B');
+ });
+
+ it('should work with multiple selected', () => {
+ function App() {
+ return (
+ <select multiple>
+ <option value="A">A</option>
+ <option selected value="B">
+ B
+ </option>
+ <option selected value="C">
+ C
+ </option>
+ </select>
+ );
+ }
+
+ render(<App />, scratch);
+ Array.prototype.slice.call(scratch.firstChild.childNodes).forEach(node => {
+ if (node.value === 'B' || node.value === 'C') {
+ expect(node.selected).to.equal(true);
+ }
+ });
+ expect(scratch.firstChild.value).to.equal('B');
+ });
+});
diff --git a/preact/test/browser/spec.test.js b/preact/test/browser/spec.test.js
new file mode 100644
index 0000000..ee5f388
--- /dev/null
+++ b/preact/test/browser/spec.test.js
@@ -0,0 +1,151 @@
+import { setupRerender } from 'preact/test-utils';
+import { createElement, render, Component } from 'preact';
+import { setupScratch, teardown } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('Component spec', () => {
+ let scratch, rerender;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ rerender = setupRerender();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ describe('defaultProps', () => {
+ it('should apply default props on initial render', () => {
+ class WithDefaultProps extends Component {
+ constructor(props, context) {
+ super(props, context);
+ expect(props).to.be.deep.equal({
+ fieldA: 1,
+ fieldB: 2,
+ fieldC: 1,
+ fieldD: 2
+ });
+ }
+ render() {
+ return <div />;
+ }
+ }
+ WithDefaultProps.defaultProps = { fieldC: 1, fieldD: 1 };
+ render(<WithDefaultProps fieldA={1} fieldB={2} fieldD={2} />, scratch);
+ });
+
+ it('should apply default props on rerender', () => {
+ let doRender;
+ class Outer extends Component {
+ constructor() {
+ super();
+ this.state = { i: 1 };
+ }
+ componentDidMount() {
+ doRender = () => this.setState({ i: 2 });
+ }
+ render(props, { i }) {
+ return <WithDefaultProps fieldA={1} fieldB={i} fieldD={i} />;
+ }
+ }
+ class WithDefaultProps extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.ctor(props, context);
+ }
+ ctor() {}
+ componentWillReceiveProps() {}
+ render() {
+ return <div />;
+ }
+ }
+ WithDefaultProps.defaultProps = { fieldC: 1, fieldD: 1 };
+
+ let proto = WithDefaultProps.prototype;
+ sinon.spy(proto, 'ctor');
+ sinon.spy(proto, 'componentWillReceiveProps');
+ sinon.spy(proto, 'render');
+
+ render(<Outer />, scratch);
+ doRender();
+
+ const PROPS1 = {
+ fieldA: 1,
+ fieldB: 1,
+ fieldC: 1,
+ fieldD: 1
+ };
+
+ const PROPS2 = {
+ fieldA: 1,
+ fieldB: 2,
+ fieldC: 1,
+ fieldD: 2
+ };
+
+ expect(proto.ctor).to.have.been.calledWithMatch(PROPS1);
+ expect(proto.render).to.have.been.calledWithMatch(PROPS1);
+
+ rerender();
+
+ // expect(proto.ctor).to.have.been.calledWith(PROPS2);
+ expect(proto.componentWillReceiveProps).to.have.been.calledWithMatch(
+ PROPS2
+ );
+ expect(proto.render).to.have.been.calledWithMatch(PROPS2);
+ });
+ });
+
+ describe('forceUpdate', () => {
+ it('should force a rerender', () => {
+ let forceUpdate;
+ class ForceUpdateComponent extends Component {
+ componentWillUpdate() {}
+ componentDidMount() {
+ forceUpdate = () => this.forceUpdate();
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(ForceUpdateComponent.prototype, 'componentWillUpdate');
+ sinon.spy(ForceUpdateComponent.prototype, 'forceUpdate');
+ render(<ForceUpdateComponent />, scratch);
+ expect(ForceUpdateComponent.prototype.componentWillUpdate).not.to.have
+ .been.called;
+
+ forceUpdate();
+ rerender();
+
+ expect(ForceUpdateComponent.prototype.componentWillUpdate).to.have.been
+ .called;
+ expect(ForceUpdateComponent.prototype.forceUpdate).to.have.been.called;
+ });
+
+ it('should add callback to renderCallbacks', () => {
+ let forceUpdate;
+ let callback = sinon.spy();
+ class ForceUpdateComponent extends Component {
+ componentDidMount() {
+ forceUpdate = () => this.forceUpdate(callback);
+ }
+ render() {
+ return <div />;
+ }
+ }
+ sinon.spy(ForceUpdateComponent.prototype, 'forceUpdate');
+ render(<ForceUpdateComponent />, scratch);
+
+ forceUpdate();
+ rerender();
+
+ expect(ForceUpdateComponent.prototype.forceUpdate).to.have.been.called;
+ expect(
+ ForceUpdateComponent.prototype.forceUpdate
+ ).to.have.been.calledWith(callback);
+ expect(callback).to.have.been.called;
+ });
+ });
+});
diff --git a/preact/test/browser/style.test.js b/preact/test/browser/style.test.js
new file mode 100644
index 0000000..a2b6afc
--- /dev/null
+++ b/preact/test/browser/style.test.js
@@ -0,0 +1,225 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown, sortCss } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('style attribute', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should apply style as String', () => {
+ render(<div style="top: 5px; position: relative;" />, scratch);
+ expect(scratch.childNodes[0].style.cssText).to.equal(
+ 'top: 5px; position: relative;'
+ );
+ });
+
+ it('should not call CSSStyleDeclaration.setProperty for style strings', () => {
+ render(<div style="top: 5px; position: relative;" />, scratch);
+ sinon.stub(scratch.firstChild.style, 'setProperty');
+ render(<div style="top: 10px; position: absolute;" />, scratch);
+ expect(scratch.firstChild.style.setProperty).to.not.be.called;
+ });
+
+ it('should properly switch from string styles to object styles and back', () => {
+ render(<div style="display: inline;">test</div>, scratch);
+
+ let style = scratch.firstChild.style;
+ expect(style.cssText).to.equal('display: inline;');
+
+ render(<div style={{ color: 'red' }} />, scratch);
+ expect(style.cssText).to.equal('color: red;');
+
+ render(<div style="color: blue" />, scratch);
+ expect(style.cssText).to.equal('color: blue;');
+
+ render(<div style={{ color: 'yellow' }} />, scratch);
+ expect(style.cssText).to.equal('color: yellow;');
+
+ render(<div style="display: block" />, scratch);
+ expect(style.cssText).to.equal('display: block;');
+ });
+
+ it('should serialize style objects', () => {
+ const styleObj = {
+ color: 'rgb(255, 255, 255)',
+ background: 'rgb(255, 100, 0)',
+ backgroundPosition: '10px 10px',
+ 'background-size': 'cover',
+ gridRowStart: 1,
+ padding: 5,
+ top: 100,
+ left: '100%'
+ };
+
+ render(<div style={styleObj}>test</div>, scratch);
+
+ let style = scratch.firstChild.style;
+ expect(style.color).to.equal('rgb(255, 255, 255)');
+ expect(style.background).to.contain('rgb(255, 100, 0)');
+ expect(style.backgroundPosition).to.equal('10px 10px');
+ expect(style.backgroundSize).to.equal('cover');
+ expect(style.padding).to.equal('5px');
+ expect(style.top).to.equal('100px');
+ expect(style.left).to.equal('100%');
+
+ // Only check for this in browsers that support css grids
+ if (typeof scratch.style.grid == 'string') {
+ expect(style.gridRowStart).to.equal('1');
+ }
+ });
+
+ it('should support opacity 0', () => {
+ render(<div style={{ opacity: 1 }}>Test</div>, scratch);
+ let style = scratch.firstChild.style;
+ expect(style)
+ .to.have.property('opacity')
+ .that.equals('1');
+
+ render(<div style={{ opacity: 0 }}>Test</div>, scratch);
+ style = scratch.firstChild.style;
+ expect(style)
+ .to.have.property('opacity')
+ .that.equals('0');
+ });
+
+ it('should support animation-iteration-count as number', () => {
+ render(<div style={{ animationIterationCount: 1 }}>Test</div>, scratch);
+ let style = scratch.firstChild.style;
+ expect(style)
+ .to.have.property('animationIterationCount')
+ .that.equals('1');
+
+ render(<div style={{ animationIterationCount: 2.5 }}>Test</div>, scratch);
+ style = scratch.firstChild.style;
+ expect(style)
+ .to.have.property('animationIterationCount')
+ .that.equals('2.5');
+ });
+
+ it('should replace previous style objects', () => {
+ render(<div style={{ display: 'inline' }}>test</div>, scratch);
+
+ let style = scratch.firstChild.style;
+ expect(style.cssText).to.equal('display: inline;');
+ expect(style)
+ .to.have.property('display')
+ .that.equals('inline');
+ expect(style)
+ .to.have.property('color')
+ .that.equals('');
+ expect(style.zIndex.toString()).to.equal('');
+
+ render(
+ <div style={{ color: 'rgb(0, 255, 255)', zIndex: '3' }}>test</div>,
+ scratch
+ );
+
+ style = scratch.firstChild.style;
+ expect(style.cssText).to.equal('color: rgb(0, 255, 255); z-index: 3;');
+ expect(style)
+ .to.have.property('display')
+ .that.equals('');
+ expect(style)
+ .to.have.property('color')
+ .that.equals('rgb(0, 255, 255)');
+
+ // IE stores numeric z-index values as a number
+ expect(style.zIndex.toString()).to.equal('3');
+
+ render(
+ <div style={{ color: 'rgb(0, 255, 255)', display: 'inline' }}>test</div>,
+ scratch
+ );
+
+ style = scratch.firstChild.style;
+ expect(style.cssText).to.equal('color: rgb(0, 255, 255); display: inline;');
+ expect(style)
+ .to.have.property('display')
+ .that.equals('inline');
+ expect(style)
+ .to.have.property('color')
+ .that.equals('rgb(0, 255, 255)');
+ expect(style.zIndex.toString()).to.equal('');
+ });
+
+ it('should remove old styles', () => {
+ render(<div style={{ color: 'red' }} />, scratch);
+ render(<div style={{ backgroundColor: 'blue' }} />, scratch);
+ expect(scratch.firstChild.style.color).to.equal('');
+ expect(scratch.firstChild.style.backgroundColor).to.equal('blue');
+ });
+
+ // Issue #1850
+ it('should remove empty styles', () => {
+ render(<div style={{ visibility: 'hidden' }} />, scratch);
+ expect(scratch.firstChild.style.visibility).to.equal('hidden');
+ render(<div style={{ visibility: undefined }} />, scratch);
+ expect(scratch.firstChild.style.visibility).to.equal('');
+ });
+
+ // Skip test if the currently running browser doesn't support CSS Custom Properties
+ if (window.CSS && CSS.supports('color', 'var(--fake-var)')) {
+ it('should support css custom properties', () => {
+ render(
+ <div style={{ '--foo': 'red', color: 'var(--foo)' }}>test</div>,
+ scratch
+ );
+ expect(sortCss(scratch.firstChild.style.cssText)).to.equal(
+ '--foo: red; color: var(--foo);'
+ );
+ expect(window.getComputedStyle(scratch.firstChild).color).to.equal(
+ 'rgb(255, 0, 0)'
+ );
+ });
+
+ it('should not add "px" suffix for custom properties', () => {
+ render(
+ <div style={{ '--foo': '100px', width: 'var(--foo)' }}>test</div>,
+ scratch
+ );
+ expect(sortCss(scratch.firstChild.style.cssText)).to.equal(
+ '--foo: 100px; width: var(--foo);'
+ );
+ });
+
+ it('css vars should not be transformed into dash-separated', () => {
+ render(
+ <div
+ style={{
+ '--fooBar': 1,
+ '--foo-baz': 2,
+ opacity: 'var(--fooBar)',
+ zIndex: 'var(--foo-baz)'
+ }}
+ >
+ test
+ </div>,
+ scratch
+ );
+ expect(sortCss(scratch.firstChild.style.cssText)).to.equal(
+ '--foo-baz: 2; --fooBar: 1; opacity: var(--fooBar); z-index: var(--foo-baz);'
+ );
+ });
+
+ it('should call CSSStyleDeclaration.setProperty for css vars', () => {
+ render(<div style={{ padding: '10px' }} />, scratch);
+ sinon.stub(scratch.firstChild.style, 'setProperty');
+ render(
+ <div style={{ '--foo': '10px', padding: 'var(--foo)' }} />,
+ scratch
+ );
+ expect(scratch.firstChild.style.setProperty).to.be.calledWith(
+ '--foo',
+ '10px'
+ );
+ });
+ }
+});
diff --git a/preact/test/browser/svg.test.js b/preact/test/browser/svg.test.js
new file mode 100644
index 0000000..ef2e796
--- /dev/null
+++ b/preact/test/browser/svg.test.js
@@ -0,0 +1,226 @@
+import { createElement, render } from 'preact';
+import { setupScratch, teardown, sortAttributes } from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('svg', () => {
+ let scratch;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('should render SVG to string', () => {
+ render(
+ <svg viewBox="0 0 360 360">
+ <path
+ stroke="white"
+ fill="black"
+ d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"
+ />
+ </svg>,
+ scratch
+ );
+
+ let html = sortAttributes(
+ String(scratch.innerHTML).replace(
+ ' xmlns="http://www.w3.org/2000/svg"',
+ ''
+ )
+ );
+ expect(html).to.equal(
+ sortAttributes(
+ `
+ <svg viewBox="0 0 360 360">
+ <path d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" fill="black" stroke="white"></path>
+ </svg>
+ `.replace(/[\n\t]+/g, '')
+ )
+ );
+ });
+
+ it('should support svg attributes', () => {
+ const Demo = ({ url }) => (
+ <svg viewBox="0 0 360 360" xlinkHref={url}>
+ <path
+ d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"
+ fill="black"
+ stroke="white"
+ />
+ </svg>
+ );
+ render(<Demo url="www.preact.com" />, scratch);
+
+ let html = String(scratch.innerHTML).replace(
+ ' xmlns="http://www.w3.org/2000/svg"',
+ ''
+ );
+ html = sortAttributes(
+ html.replace(' xmlns:xlink="http://www.w3.org/1999/xlink"', '')
+ );
+ expect(html).to.equal(
+ sortAttributes(
+ `
+ <svg viewBox="0 0 360 360" href="www.preact.com">
+ <path d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" fill="black" stroke="white"></path>
+ </svg>
+ `.replace(/[\n\t]+/g, '')
+ )
+ );
+ render(<Demo />, scratch);
+
+ html = String(scratch.innerHTML).replace(
+ ' xmlns="http://www.w3.org/2000/svg"',
+ ''
+ );
+ html = sortAttributes(
+ html.replace(' xmlns:xlink="http://www.w3.org/1999/xlink"', '')
+ );
+ expect(html).to.equal(
+ sortAttributes(
+ `
+ <svg viewBox="0 0 360 360">
+ <path d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z" fill="black" stroke="white"></path>
+ </svg>
+ `.replace(/[\n\t]+/g, '')
+ )
+ );
+ });
+
+ it('should render SVG to DOM', () => {
+ const Demo = () => (
+ <svg viewBox="0 0 360 360">
+ <path
+ d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"
+ fill="black"
+ stroke="white"
+ />
+ </svg>
+ );
+ render(<Demo />, scratch);
+
+ let html = sortAttributes(
+ String(scratch.innerHTML).replace(
+ ' xmlns="http://www.w3.org/2000/svg"',
+ ''
+ )
+ );
+ expect(html).to.equal(
+ sortAttributes(
+ '<svg viewBox="0 0 360 360"><path stroke="white" fill="black" d="M 347.1 357.9 L 183.3 256.5 L 13 357.9 V 1.7 h 334.1 v 356.2 Z M 58.5 47.2 v 231.4 l 124.8 -74.1 l 118.3 72.8 V 47.2 H 58.5 Z"></path></svg>'
+ )
+ );
+ });
+
+ it('should render with the correct namespace URI', () => {
+ render(<svg />, scratch);
+
+ let namespace = scratch.querySelector('svg').namespaceURI;
+
+ expect(namespace).to.equal('http://www.w3.org/2000/svg');
+ });
+
+ it('should use attributes for className', () => {
+ const Demo = ({ c }) => (
+ <svg viewBox="0 0 360 360" {...(c ? { class: 'foo_' + c } : {})}>
+ <path
+ class={c && 'bar_' + c}
+ stroke="white"
+ fill="black"
+ d="M347.1 357.9L183.3 256.5 13 357.9V1.7h334.1v356.2zM58.5 47.2v231.4l124.8-74.1 118.3 72.8V47.2H58.5z"
+ />
+ </svg>
+ );
+ render(<Demo c="1" />, scratch);
+ let root = scratch.firstChild;
+ sinon.spy(root, 'removeAttribute');
+ render(<Demo />, scratch);
+ expect(root.removeAttribute).to.have.been.calledOnce.and.calledWith(
+ 'class'
+ );
+
+ root.removeAttribute.restore();
+
+ render(<div />, scratch);
+ render(<Demo />, scratch);
+ root = scratch.firstChild;
+ sinon.spy(root, 'setAttribute');
+ render(<Demo c="2" />, scratch);
+ expect(root.setAttribute).to.have.been.calledOnce.and.calledWith(
+ 'class',
+ 'foo_2'
+ );
+
+ root.setAttribute.restore();
+ });
+
+ it('should still support class attribute', () => {
+ render(<svg viewBox="0 0 1 1" class="foo bar" />, scratch);
+
+ expect(scratch.innerHTML).to.contain(` class="foo bar"`);
+ });
+
+ it('should still support className attribute', () => {
+ render(<svg viewBox="0 0 1 1" className="foo bar" />, scratch);
+
+ expect(scratch.innerHTML).to.contain(` class="foo bar"`);
+ });
+
+ it('should switch back to HTML for <foreignObject>', () => {
+ render(
+ <svg>
+ <g>
+ <foreignObject>
+ <a href="#foo">test</a>
+ </foreignObject>
+ </g>
+ </svg>,
+ scratch
+ );
+
+ expect(scratch.getElementsByTagName('a'))
+ .to.have.property('0')
+ .that.is.a('HTMLAnchorElement');
+ });
+
+ it('should render foreignObject as an svg element', () => {
+ render(
+ <svg>
+ <g>
+ <foreignObject>
+ <a href="#foo">test</a>
+ </foreignObject>
+ </g>
+ </svg>,
+ scratch
+ );
+
+ expect(scratch.querySelector('foreignObject').localName).to.equal(
+ 'foreignObject'
+ );
+ });
+
+ it('should transition from DOM to SVG and back', () => {
+ render(
+ <div>
+ <svg
+ id="svg1923"
+ width="700"
+ xmlns="http://www.w3.org/2000/svg"
+ height="700"
+ >
+ <circle cy="333" cx="333" r="333" />
+ <circle cy="333" cx="333" r="333" fill="#fede58" />
+ </svg>
+ </div>,
+ scratch
+ );
+
+ expect(scratch.firstChild).to.be.an('HTMLDivElement');
+ expect(scratch.firstChild.firstChild).to.be.an('SVGSVGElement');
+ });
+});
diff --git a/preact/test/browser/toChildArray.test.js b/preact/test/browser/toChildArray.test.js
new file mode 100644
index 0000000..d1cb950
--- /dev/null
+++ b/preact/test/browser/toChildArray.test.js
@@ -0,0 +1,207 @@
+import { createElement, render, toChildArray } from 'preact';
+import {
+ setupScratch,
+ teardown,
+ getMixedArray,
+ mixedArrayHTML
+} from '../_util/helpers';
+
+/** @jsx createElement */
+
+describe('toChildArray', () => {
+ /** @type {HTMLDivElement} */
+ let scratch;
+
+ let children;
+
+ let Foo = props => {
+ children = toChildArray(props.children);
+ return <div>{children}</div>;
+ };
+
+ let Bar = () => <span>Bar</span>;
+
+ beforeEach(() => {
+ scratch = setupScratch();
+ children = undefined;
+ });
+
+ afterEach(() => {
+ teardown(scratch);
+ });
+
+ it('returns an empty array with no child', () => {
+ render(<Foo />, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(0);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('returns an empty array with null as a child', () => {
+ render(<Foo>{null}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(0);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('returns an empty array with false as a child', () => {
+ render(<Foo>{false}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(0);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('returns an empty array with true as a child', () => {
+ render(<Foo>{true}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(0);
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('should skip a function child', () => {
+ const child = num => num.toFixed(2);
+ render(<Foo>{child}</Foo>, scratch);
+ expect(children).to.be.an('array');
+ expect(scratch.innerHTML).to.equal('<div></div>');
+ });
+
+ it('returns an array containing a VNode with a text child', () => {
+ render(<Foo>text</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(1);
+ expect(children[0]).to.equal('text');
+ expect(scratch.innerHTML).to.equal('<div>text</div>');
+ });
+
+ it('returns an array containing a VNode with a number child', () => {
+ render(<Foo>{1}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(1);
+ expect(children[0]).to.equal(1);
+ expect(scratch.innerHTML).to.equal('<div>1</div>');
+ });
+
+ it('returns an array containing a VNode with a DOM node child', () => {
+ render(
+ <Foo>
+ <span />
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(1);
+ expect(children[0].type).to.equal('span');
+ expect(scratch.innerHTML).to.equal('<div><span></span></div>');
+ });
+
+ it('returns an array containing a VNode with a Component child', () => {
+ render(
+ <Foo>
+ <Bar />
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(1);
+ expect(children[0].type).to.equal(Bar);
+ expect(scratch.innerHTML).to.equal('<div><span>Bar</span></div>');
+ });
+
+ it('returns an array with multiple children', () => {
+ render(
+ <Foo>
+ 0<span />
+ <input />
+ <div />1
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(children[0]).to.equal('0');
+ expect(children[1].type).to.equal('span');
+ expect(children[2].type).to.equal('input');
+ expect(children[3].type).to.equal('div');
+ expect(children[4]).to.equal('1');
+ expect(scratch.innerHTML).to.equal(
+ `<div>0<span></span><input><div></div>1</div>`
+ );
+ });
+
+ it('returns an array with non-renderables removed with a mixed array as children', () => {
+ const mixedArray = getMixedArray();
+ render(<Foo>{mixedArray}</Foo>, scratch);
+
+ expect(children).to.be.an('array');
+ expect(children).to.have.lengthOf(8); // Length of flattened mixedArray with non-renderables removed
+ expect(scratch.innerHTML).to.equal(`<div>${mixedArrayHTML}</div>`);
+
+ function filterAndReduceChildren(acc, child) {
+ if (Array.isArray(child)) {
+ return child.reduce(filterAndReduceChildren, acc);
+ }
+
+ if (
+ child != null &&
+ typeof child != 'boolean' &&
+ typeof child != 'function'
+ ) {
+ acc.push(child);
+ }
+
+ return acc;
+ }
+
+ let renderableArray = filterAndReduceChildren([], mixedArray);
+
+ expect(children).to.have.lengthOf(renderableArray.length);
+
+ for (let i = 0; i < renderableArray.length; i++) {
+ let originalChild = renderableArray[i];
+ let actualChild = children[i];
+
+ if (
+ typeof originalChild == 'string' ||
+ typeof originalChild == 'number'
+ ) {
+ expect(actualChild).to.equal(originalChild);
+ } else {
+ expect(actualChild.type).to.equal(originalChild.type);
+ }
+ }
+ });
+
+ it('flattens sibling and nested arrays', () => {
+ const list1 = [0, 1];
+ const list2 = [2, 3];
+ const list3 = [4, 5];
+ const list4 = [6, 7];
+ const list5 = [8, 9];
+
+ const flatList = [...list1, ...list2, ...list3, ...list4, ...list5];
+
+ render(
+ <Foo>
+ {[list1, list2]}
+ {[list3, list4]}
+ {list5}
+ </Foo>,
+ scratch
+ );
+
+ expect(children).to.be.an('array');
+ expect(scratch.innerHTML).to.equal('<div>0123456789</div>');
+
+ for (let i = 0; i < flatList.length; i++) {
+ expect(children[i]).to.equal(flatList[i]);
+ }
+ });
+});
diff --git a/preact/test/extensions.d.ts b/preact/test/extensions.d.ts
new file mode 100644
index 0000000..c810c3b
--- /dev/null
+++ b/preact/test/extensions.d.ts
@@ -0,0 +1,5 @@
+declare module Chai {
+ export interface Assertion {
+ equalNode(node: Node | null, message?: string): void;
+ }
+}
diff --git a/preact/test/fixtures/preact.js b/preact/test/fixtures/preact.js
new file mode 100644
index 0000000..c76e635
--- /dev/null
+++ b/preact/test/fixtures/preact.js
@@ -0,0 +1,626 @@
+!(function() {
+ 'use strict';
+ function h(nodeName, attributes) {
+ var lastSimple,
+ child,
+ simple,
+ i,
+ children = EMPTY_CHILDREN;
+ for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]);
+ if (attributes && null != attributes.children) {
+ if (!stack.length) stack.push(attributes.children);
+ delete attributes.children;
+ }
+ while (stack.length)
+ if ((child = stack.pop()) && void 0 !== child.pop)
+ for (i = child.length; i--; ) stack.push(child[i]);
+ else {
+ if ('boolean' == typeof child) child = null;
+ if ((simple = 'function' != typeof nodeName))
+ if (null == child) child = '';
+ else if ('number' == typeof child) child = String(child);
+ else if ('string' != typeof child) simple = !1;
+ if (simple && lastSimple) children[children.length - 1] += child;
+ else if (children === EMPTY_CHILDREN) children = [child];
+ else children.push(child);
+ lastSimple = simple;
+ }
+ var p = new VNode();
+ p.nodeName = nodeName;
+ p.children = children;
+ p.attributes = null == attributes ? void 0 : attributes;
+ p.key = null == attributes ? void 0 : attributes.key;
+ if (void 0 !== options.vnode) options.vnode(p);
+ return p;
+ }
+ function extend(obj, props) {
+ for (var i in props) obj[i] = props[i];
+ return obj;
+ }
+ function applyRef(ref, value) {
+ if ('function' == typeof ref) ref(value);
+ else if (null != ref) ref.current = value;
+ }
+ function cloneElement(vnode, props) {
+ return h(
+ vnode.nodeName,
+ extend(extend({}, vnode.attributes), props),
+ arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children
+ );
+ }
+ function enqueueRender(component) {
+ if (!component.__d && (component.__d = !0) && 1 == items.push(component))
+ (options.debounceRendering || defer)(rerender);
+ }
+ function rerender() {
+ var p;
+ while ((p = items.pop())) if (p.__d) renderComponent(p);
+ }
+ function isSameNodeType(node, vnode, hydrating) {
+ if ('string' == typeof vnode || 'number' == typeof vnode)
+ return void 0 !== node.splitText;
+ if ('string' == typeof vnode.nodeName)
+ return !node._componentConstructor && isNamedNode(node, vnode.nodeName);
+ else return hydrating || node._componentConstructor === vnode.nodeName;
+ }
+ function isNamedNode(node, nodeName) {
+ return (
+ node.__n === nodeName ||
+ node.nodeName.toLowerCase() === nodeName.toLowerCase()
+ );
+ }
+ function getNodeProps(vnode) {
+ var props = extend({}, vnode.attributes);
+ props.children = vnode.children;
+ var defaultProps = vnode.nodeName.defaultProps;
+ if (void 0 !== defaultProps)
+ for (var i in defaultProps)
+ if (void 0 === props[i]) props[i] = defaultProps[i];
+ return props;
+ }
+ function createNode(nodeName, isSvg) {
+ var node = isSvg
+ ? document.createElementNS('http://www.w3.org/2000/svg', nodeName)
+ : document.createElement(nodeName);
+ node.__n = nodeName;
+ return node;
+ }
+ function removeNode(node) {
+ var parentNode = node.parentNode;
+ if (parentNode) parentNode.removeChild(node);
+ }
+ function setAccessor(node, name, old, value, isSvg) {
+ if ('className' === name) name = 'class';
+ if ('key' === name);
+ else if ('ref' === name) {
+ applyRef(old, null);
+ applyRef(value, node);
+ } else if ('class' === name && !isSvg) node.className = value || '';
+ else if ('style' === name) {
+ if (!value || 'string' == typeof value || 'string' == typeof old)
+ node.style.cssText = value || '';
+ if (value && 'object' == typeof value) {
+ if ('string' != typeof old)
+ for (var i in old) if (!(i in value)) node.style[i] = '';
+ for (var i in value)
+ node.style[i] =
+ 'number' == typeof value[i] && !1 === IS_NON_DIMENSIONAL.test(i)
+ ? value[i] + 'px'
+ : value[i];
+ }
+ } else if ('dangerouslySetInnerHTML' === name) {
+ if (value) node.innerHTML = value.__html || '';
+ } else if ('o' == name[0] && 'n' == name[1]) {
+ var useCapture = name !== (name = name.replace(/Capture$/, ''));
+ name = name.toLowerCase().substring(2);
+ if (value) {
+ if (!old) node.addEventListener(name, eventProxy, useCapture);
+ } else node.removeEventListener(name, eventProxy, useCapture);
+ (node.__l || (node.__l = {}))[name] = value;
+ } else if ('list' !== name && 'type' !== name && !isSvg && name in node) {
+ try {
+ node[name] = null == value ? '' : value;
+ } catch (e) {}
+ if ((null == value || !1 === value) && 'spellcheck' != name)
+ node.removeAttribute(name);
+ } else {
+ var ns = isSvg && name !== (name = name.replace(/^xlink:?/, ''));
+ if (null == value || !1 === value)
+ if (ns)
+ node.removeAttributeNS(
+ 'http://www.w3.org/1999/xlink',
+ name.toLowerCase()
+ );
+ else node.removeAttribute(name);
+ else if ('function' != typeof value)
+ if (ns)
+ node.setAttributeNS(
+ 'http://www.w3.org/1999/xlink',
+ name.toLowerCase(),
+ value
+ );
+ else node.setAttribute(name, value);
+ }
+ }
+ function eventProxy(e) {
+ return this.__l[e.type]((options.event && options.event(e)) || e);
+ }
+ function flushMounts() {
+ var c;
+ while ((c = mounts.pop())) {
+ if (options.afterMount) options.afterMount(c);
+ if (c.componentDidMount) c.componentDidMount();
+ }
+ }
+ function diff(dom, vnode, context, mountAll, parent, componentRoot) {
+ if (!diffLevel++) {
+ isSvgMode = null != parent && void 0 !== parent.ownerSVGElement;
+ hydrating = null != dom && !('__preactattr_' in dom);
+ }
+ var ret = idiff(dom, vnode, context, mountAll, componentRoot);
+ if (parent && ret.parentNode !== parent) parent.appendChild(ret);
+ if (!--diffLevel) {
+ hydrating = !1;
+ if (!componentRoot) flushMounts();
+ }
+ return ret;
+ }
+ function idiff(dom, vnode, context, mountAll, componentRoot) {
+ var out = dom,
+ prevSvgMode = isSvgMode;
+ if (null == vnode || 'boolean' == typeof vnode) vnode = '';
+ if ('string' == typeof vnode || 'number' == typeof vnode) {
+ if (
+ dom &&
+ void 0 !== dom.splitText &&
+ dom.parentNode &&
+ (!dom._component || componentRoot)
+ ) {
+ if (dom.nodeValue != vnode) dom.nodeValue = vnode;
+ } else {
+ out = document.createTextNode(vnode);
+ if (dom) {
+ if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
+ recollectNodeTree(dom, !0);
+ }
+ }
+ out.__preactattr_ = !0;
+ return out;
+ }
+ var vnodeName = vnode.nodeName;
+ if ('function' == typeof vnodeName)
+ return buildComponentFromVNode(dom, vnode, context, mountAll);
+ isSvgMode =
+ 'svg' === vnodeName ? !0 : 'foreignObject' === vnodeName ? !1 : isSvgMode;
+ vnodeName = String(vnodeName);
+ if (!dom || !isNamedNode(dom, vnodeName)) {
+ out = createNode(vnodeName, isSvgMode);
+ if (dom) {
+ while (dom.firstChild) out.appendChild(dom.firstChild);
+ if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
+ recollectNodeTree(dom, !0);
+ }
+ }
+ var fc = out.firstChild,
+ props = out.__preactattr_,
+ vchildren = vnode.children;
+ if (null == props) {
+ props = out.__preactattr_ = {};
+ for (var a = out.attributes, i = a.length; i--; )
+ props[a[i].name] = a[i].value;
+ }
+ if (
+ !hydrating &&
+ vchildren &&
+ 1 === vchildren.length &&
+ 'string' == typeof vchildren[0] &&
+ null != fc &&
+ void 0 !== fc.splitText &&
+ null == fc.nextSibling
+ ) {
+ if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
+ } else if ((vchildren && vchildren.length) || null != fc)
+ innerDiffNode(
+ out,
+ vchildren,
+ context,
+ mountAll,
+ hydrating || null != props.dangerouslySetInnerHTML
+ );
+ diffAttributes(out, vnode.attributes, props);
+ isSvgMode = prevSvgMode;
+ return out;
+ }
+ function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
+ var j,
+ c,
+ f,
+ vchild,
+ child,
+ originalChildren = dom.childNodes,
+ children = [],
+ keyed = {},
+ keyedLen = 0,
+ min = 0,
+ len = originalChildren.length,
+ childrenLen = 0,
+ vlen = vchildren ? vchildren.length : 0;
+ if (0 !== len)
+ for (var i = 0; i < len; i++) {
+ var _child = originalChildren[i],
+ props = _child.__preactattr_,
+ key =
+ vlen && props
+ ? _child._component
+ ? _child._component.__k
+ : props.key
+ : null;
+ if (null != key) {
+ keyedLen++;
+ keyed[key] = _child;
+ } else if (
+ props ||
+ (void 0 !== _child.splitText
+ ? isHydrating
+ ? _child.nodeValue.trim()
+ : !0
+ : isHydrating)
+ )
+ children[childrenLen++] = _child;
+ }
+ if (0 !== vlen)
+ for (var i = 0; i < vlen; i++) {
+ vchild = vchildren[i];
+ child = null;
+ var key = vchild.key;
+ if (null != key) {
+ if (keyedLen && void 0 !== keyed[key]) {
+ child = keyed[key];
+ keyed[key] = void 0;
+ keyedLen--;
+ }
+ } else if (min < childrenLen)
+ for (j = min; j < childrenLen; j++)
+ if (
+ void 0 !== children[j] &&
+ isSameNodeType((c = children[j]), vchild, isHydrating)
+ ) {
+ child = c;
+ children[j] = void 0;
+ if (j === childrenLen - 1) childrenLen--;
+ if (j === min) min++;
+ break;
+ }
+ child = idiff(child, vchild, context, mountAll);
+ f = originalChildren[i];
+ if (child && child !== dom && child !== f)
+ if (null == f) dom.appendChild(child);
+ else if (child === f.nextSibling) removeNode(f);
+ else dom.insertBefore(child, f);
+ }
+ if (keyedLen)
+ for (var i in keyed)
+ if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1);
+ while (min <= childrenLen)
+ if (void 0 !== (child = children[childrenLen--]))
+ recollectNodeTree(child, !1);
+ }
+ function recollectNodeTree(node, unmountOnly) {
+ var component = node._component;
+ if (component) unmountComponent(component);
+ else {
+ if (null != node.__preactattr_) applyRef(node.__preactattr_.ref, null);
+ if (!1 === unmountOnly || null == node.__preactattr_) removeNode(node);
+ removeChildren(node);
+ }
+ }
+ function removeChildren(node) {
+ node = node.lastChild;
+ while (node) {
+ var next = node.previousSibling;
+ recollectNodeTree(node, !0);
+ node = next;
+ }
+ }
+ function diffAttributes(dom, attrs, old) {
+ var name;
+ for (name in old)
+ if ((!attrs || null == attrs[name]) && null != old[name])
+ setAccessor(dom, name, old[name], (old[name] = void 0), isSvgMode);
+ for (name in attrs)
+ if (
+ !(
+ 'children' === name ||
+ 'innerHTML' === name ||
+ (name in old &&
+ attrs[name] ===
+ ('value' === name || 'checked' === name ? dom[name] : old[name]))
+ )
+ )
+ setAccessor(dom, name, old[name], (old[name] = attrs[name]), isSvgMode);
+ }
+ function createComponent(Ctor, props, context) {
+ var inst,
+ i = recyclerComponents.length;
+ if (Ctor.prototype && Ctor.prototype.render) {
+ inst = new Ctor(props, context);
+ Component.call(inst, props, context);
+ } else {
+ inst = new Component(props, context);
+ inst.constructor = Ctor;
+ inst.render = doRender;
+ }
+ while (i--)
+ if (recyclerComponents[i].constructor === Ctor) {
+ inst.__b = recyclerComponents[i].__b;
+ recyclerComponents.splice(i, 1);
+ return inst;
+ }
+ return inst;
+ }
+ function doRender(props, state, context) {
+ return this.constructor(props, context);
+ }
+ function setComponentProps(component, props, renderMode, context, mountAll) {
+ if (!component.__x) {
+ component.__x = !0;
+ component.__r = props.ref;
+ component.__k = props.key;
+ delete props.ref;
+ delete props.key;
+ if (void 0 === component.constructor.getDerivedStateFromProps)
+ if (!component.base || mountAll) {
+ if (component.componentWillMount) component.componentWillMount();
+ } else if (component.componentWillReceiveProps)
+ component.componentWillReceiveProps(props, context);
+ if (context && context !== component.context) {
+ if (!component.__c) component.__c = component.context;
+ component.context = context;
+ }
+ if (!component.__p) component.__p = component.props;
+ component.props = props;
+ component.__x = !1;
+ if (0 !== renderMode)
+ if (
+ 1 === renderMode ||
+ !1 !== options.syncComponentUpdates ||
+ !component.base
+ )
+ renderComponent(component, 1, mountAll);
+ else enqueueRender(component);
+ applyRef(component.__r, component);
+ }
+ }
+ function renderComponent(component, renderMode, mountAll, isChild) {
+ if (!component.__x) {
+ var rendered,
+ inst,
+ cbase,
+ props = component.props,
+ state = component.state,
+ context = component.context,
+ previousProps = component.__p || props,
+ previousState = component.__s || state,
+ previousContext = component.__c || context,
+ isUpdate = component.base,
+ nextBase = component.__b,
+ initialBase = isUpdate || nextBase,
+ initialChildComponent = component._component,
+ skip = !1,
+ snapshot = previousContext;
+ if (component.constructor.getDerivedStateFromProps) {
+ state = extend(
+ extend({}, state),
+ component.constructor.getDerivedStateFromProps(props, state)
+ );
+ component.state = state;
+ }
+ if (isUpdate) {
+ component.props = previousProps;
+ component.state = previousState;
+ component.context = previousContext;
+ if (
+ 2 !== renderMode &&
+ component.shouldComponentUpdate &&
+ !1 === component.shouldComponentUpdate(props, state, context)
+ )
+ skip = !0;
+ else if (component.componentWillUpdate)
+ component.componentWillUpdate(props, state, context);
+ component.props = props;
+ component.state = state;
+ component.context = context;
+ }
+ component.__p = component.__s = component.__c = component.__b = null;
+ component.__d = !1;
+ if (!skip) {
+ rendered = component.render(props, state, context);
+ if (component.getChildContext)
+ context = extend(extend({}, context), component.getChildContext());
+ if (isUpdate && component.getSnapshotBeforeUpdate)
+ snapshot = component.getSnapshotBeforeUpdate(
+ previousProps,
+ previousState
+ );
+ var toUnmount,
+ base,
+ childComponent = rendered && rendered.nodeName;
+ if ('function' == typeof childComponent) {
+ var childProps = getNodeProps(rendered);
+ inst = initialChildComponent;
+ if (
+ inst &&
+ inst.constructor === childComponent &&
+ childProps.key == inst.__k
+ )
+ setComponentProps(inst, childProps, 1, context, !1);
+ else {
+ toUnmount = inst;
+ component._component = inst = createComponent(
+ childComponent,
+ childProps,
+ context
+ );
+ inst.__b = inst.__b || nextBase;
+ inst.__u = component;
+ setComponentProps(inst, childProps, 0, context, !1);
+ renderComponent(inst, 1, mountAll, !0);
+ }
+ base = inst.base;
+ } else {
+ cbase = initialBase;
+ toUnmount = initialChildComponent;
+ if (toUnmount) cbase = component._component = null;
+ if (initialBase || 1 === renderMode) {
+ if (cbase) cbase._component = null;
+ base = diff(
+ cbase,
+ rendered,
+ context,
+ mountAll || !isUpdate,
+ initialBase && initialBase.parentNode,
+ !0
+ );
+ }
+ }
+ if (
+ initialBase &&
+ base !== initialBase &&
+ inst !== initialChildComponent
+ ) {
+ var baseParent = initialBase.parentNode;
+ if (baseParent && base !== baseParent) {
+ baseParent.replaceChild(base, initialBase);
+ if (!toUnmount) {
+ initialBase._component = null;
+ recollectNodeTree(initialBase, !1);
+ }
+ }
+ }
+ if (toUnmount) unmountComponent(toUnmount);
+ component.base = base;
+ if (base && !isChild) {
+ var componentRef = component,
+ t = component;
+ while ((t = t.__u)) (componentRef = t).base = base;
+ base._component = componentRef;
+ base._componentConstructor = componentRef.constructor;
+ }
+ }
+ if (!isUpdate || mountAll) mounts.unshift(component);
+ else if (!skip) {
+ if (component.componentDidUpdate)
+ component.componentDidUpdate(previousProps, previousState, snapshot);
+ if (options.afterUpdate) options.afterUpdate(component);
+ }
+ while (component.__h.length) component.__h.pop().call(component);
+ if (!diffLevel && !isChild) flushMounts();
+ }
+ }
+ function buildComponentFromVNode(dom, vnode, context, mountAll) {
+ var c = dom && dom._component,
+ originalComponent = c,
+ oldDom = dom,
+ isDirectOwner = c && dom._componentConstructor === vnode.nodeName,
+ isOwner = isDirectOwner,
+ props = getNodeProps(vnode);
+ while (c && !isOwner && (c = c.__u))
+ isOwner = c.constructor === vnode.nodeName;
+ if (c && isOwner && (!mountAll || c._component)) {
+ setComponentProps(c, props, 3, context, mountAll);
+ dom = c.base;
+ } else {
+ if (originalComponent && !isDirectOwner) {
+ unmountComponent(originalComponent);
+ dom = oldDom = null;
+ }
+ c = createComponent(vnode.nodeName, props, context);
+ if (dom && !c.__b) {
+ c.__b = dom;
+ oldDom = null;
+ }
+ setComponentProps(c, props, 1, context, mountAll);
+ dom = c.base;
+ if (oldDom && dom !== oldDom) {
+ oldDom._component = null;
+ recollectNodeTree(oldDom, !1);
+ }
+ }
+ return dom;
+ }
+ function unmountComponent(component) {
+ if (options.beforeUnmount) options.beforeUnmount(component);
+ var base = component.base;
+ component.__x = !0;
+ if (component.componentWillUnmount) component.componentWillUnmount();
+ component.base = null;
+ var inner = component._component;
+ if (inner) unmountComponent(inner);
+ else if (base) {
+ if (base.__preactattr_ && base.__preactattr_.ref)
+ base.__preactattr_.ref(null);
+ component.__b = base;
+ removeNode(base);
+ recyclerComponents.push(component);
+ removeChildren(base);
+ }
+ applyRef(component.__r, null);
+ }
+ function Component(props, context) {
+ this.__d = !0;
+ this.context = context;
+ this.props = props;
+ this.state = this.state || {};
+ this.__h = [];
+ }
+ function render(vnode, parent, merge) {
+ return diff(merge, vnode, {}, !1, parent, !1);
+ }
+ function createRef() {
+ return {};
+ }
+ var VNode = function() {};
+ var options = {};
+ var stack = [];
+ var EMPTY_CHILDREN = [];
+ var defer =
+ 'function' == typeof Promise
+ ? Promise.resolve().then.bind(Promise.resolve())
+ : setTimeout;
+ var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;
+ var items = [];
+ var mounts = [];
+ var diffLevel = 0;
+ var isSvgMode = !1;
+ var hydrating = !1;
+ var recyclerComponents = [];
+ extend(Component.prototype, {
+ setState: function(state, callback) {
+ if (!this.__s) this.__s = this.state;
+ this.state = extend(
+ extend({}, this.state),
+ 'function' == typeof state ? state(this.state, this.props) : state
+ );
+ if (callback) this.__h.push(callback);
+ enqueueRender(this);
+ },
+ forceUpdate: function(callback) {
+ if (callback) this.__h.push(callback);
+ renderComponent(this, 2);
+ },
+ render: function() {}
+ });
+ var preact = {
+ h: h,
+ createElement: h,
+ cloneElement: cloneElement,
+ createRef: createRef,
+ Component: Component,
+ render: render,
+ rerender: rerender,
+ options: options
+ };
+ if ('undefined' != typeof module) module.exports = preact;
+ else self.preact = preact;
+})();
+//# sourceMappingURL=preact.js.map
diff --git a/preact/test/node/index.test.js b/preact/test/node/index.test.js
new file mode 100644
index 0000000..fef7547
--- /dev/null
+++ b/preact/test/node/index.test.js
@@ -0,0 +1,15 @@
+import { expect } from 'chai';
+import * as preact from '../../';
+
+describe('build artifact', () => {
+ // #1075 Check that the build artifact has the correct exports
+ it('should have exported properties', () => {
+ expect(preact).to.be.an('object');
+ expect(preact).to.have.property('createElement');
+ expect(preact).to.have.property('h');
+ expect(preact).to.have.property('Component');
+ expect(preact).to.have.property('render');
+ expect(preact).to.have.property('hydrate');
+ // expect(preact).to.have.property('options');
+ });
+});
diff --git a/preact/test/polyfills.js b/preact/test/polyfills.js
new file mode 100644
index 0000000..e2f542b
--- /dev/null
+++ b/preact/test/polyfills.js
@@ -0,0 +1,260 @@
+// ES2015 APIs used by developer tools integration
+import 'core-js/es6/map';
+import 'core-js/es6/promise';
+import 'core-js/fn/array/fill';
+import 'core-js/fn/array/from';
+import 'core-js/fn/array/find';
+import 'core-js/fn/array/includes';
+import 'core-js/fn/string/includes';
+import 'core-js/fn/object/assign';
+import 'core-js/fn/string/starts-with';
+import 'core-js/fn/string/code-point-at';
+import 'core-js/fn/string/from-code-point';
+import 'core-js/fn/string/repeat';
+import * as kl from 'kolorist';
+
+// Something that's loaded before this file polyfills Symbol object.
+// We need to verify that it works in IE without that.
+if (/Trident/.test(window.navigator.userAgent)) {
+ window.Symbol = undefined;
+}
+
+// Fix Function#name on browsers that do not support it (IE).
+// Taken from: https://stackoverflow.com/a/17056530/755391
+if (!function f() {}.name) {
+ Object.defineProperty(Function.prototype, 'name', {
+ get() {
+ let name = (this.toString().match(/^function\s*([^\s(]+)/) || [])[1];
+ // For better performance only parse once, and then cache the
+ // result through a new accessor for repeated access.
+ Object.defineProperty(this, 'name', { value: name });
+ return name;
+ }
+ });
+}
+
+/* global chai */
+chai.use((chai, util) => {
+ const Assertion = chai.Assertion;
+
+ Assertion.addMethod('equalNode', function(expectedNode, message) {
+ const obj = this._obj;
+ message = message || 'equalNode';
+
+ if (expectedNode == null) {
+ this.assert(
+ obj == null,
+ `${message}: expected node to "== null" but got #{act} instead.`,
+ `${message}: expected node to not "!= null".`,
+ expectedNode,
+ obj
+ );
+ } else {
+ new Assertion(obj).to.be.instanceof(Node, message);
+ this.assert(
+ obj.tagName === expectedNode.tagName,
+ `${message}: expected node to have tagName #{exp} but got #{act} instead.`,
+ `${message}: expected node to not have tagName #{act}.`,
+ expectedNode.tagName,
+ obj.tagName
+ );
+ this.assert(
+ obj === expectedNode,
+ `${message}: expected #{this} to be #{exp} but got #{act}`,
+ `${message}: expected # {this} not to be #{exp}`,
+ expectedNode,
+ obj
+ );
+ }
+ });
+});
+
+//
+// The following code overwrites karma's internal logging feature to
+// support a much prettier and humand readable represantation of
+// console logs in our terminal. This includes indentation, coloring
+// and support for Map and Set objects.
+//
+function patchConsole(method) {
+ const original = window.console[method];
+ window.console[method] = (...args) => {
+ // @ts-ignore
+ // eslint-disable-next-line no-undef
+ __karma__.log(method, ['__LOG_CUSTOM:' + serializeConsoleArgs(args)]);
+ original.apply(window.console, args);
+ };
+}
+
+patchConsole('log');
+patchConsole('warn');
+patchConsole('error');
+patchConsole('info');
+
+/**
+ * @param {any[]} args
+ * @returns {[string]}
+ */
+function serializeConsoleArgs(args) {
+ const flat = args.map(arg => serialize(arg, 'flat', 0, new Set()));
+ // We don't have access to the users terminal width, so we'll try to
+ // format everything into one line if possible and assume a terminal
+ // width of 80 chars
+ if (kl.stripColors(flat.join(', ')).length <= 80) {
+ return [flat.join(', ')];
+ }
+
+ const serialized = args.map(arg => serialize(arg, 'default', 0, new Set()));
+ return ['\n' + serialized.join(',\n') + '\n'];
+}
+
+/**
+ * @param {number} n
+ * @returns {string}
+ */
+function applyIndent(n) {
+ if (n <= 0) return '';
+ return ' '.repeat(n);
+}
+
+/**
+ * @param {any} value
+ * @param {"flat" | "default"} mode
+ * @param {number} indent
+ * @param {Set<any>} seen
+ * @returns {string}
+ */
+function serialize(value, mode, indent, seen) {
+ if (seen.has(value)) {
+ return kl.cyan('[Circular]');
+ }
+
+ if (value === null) {
+ return kl.bold('null');
+ } else if (Array.isArray(value)) {
+ seen.add(value);
+ const values = value.map(v => serialize(v, mode, indent + 1, seen));
+ if (mode === 'flat') {
+ return `[ ${values.join(', ')} ]`;
+ }
+
+ const space = applyIndent(indent);
+ const pretty = values.map(v => applyIndent(indent + 1) + v).join(',\n');
+ return `[\n${pretty}\n${space}]`;
+ } else if (value instanceof Set) {
+ const values = [];
+ value.forEach(v => {
+ values.push(serialize(v, mode, indent, seen));
+ });
+
+ if (mode === 'flat') {
+ return `Set(${value.size}) { ${values.join(', ')} }`;
+ }
+
+ const pretty = values.map(v => applyIndent(indent + 1) + v).join(',\n');
+ return `Set(${value.size}) {\n${pretty}\n${applyIndent(indent)}}`;
+ } else if (value instanceof Map) {
+ const values = [];
+ value.forEach((v, k) => {
+ values.push([
+ serialize(v, 'flat', indent, seen),
+ serialize(k, 'flat', indent, seen)
+ ]);
+ });
+
+ if (mode === 'flat') {
+ const pretty = values.map(v => `${v[0]} => ${v[1]}`).join(', ');
+ return `Map(${value.size}) { ${pretty} }`;
+ }
+
+ const pretty = values
+ .map(v => {
+ return applyIndent(indent + 1) + `${v[0]} => ${v[1]}`;
+ })
+ .join(', ');
+ return `Map(${value.size}) {\n${pretty}\n${applyIndent(indent)}}`;
+ }
+
+ switch (typeof value) {
+ case 'undefined':
+ return kl.dim('undefined');
+
+ case 'bigint':
+ case 'number':
+ case 'boolean':
+ return kl.yellow(String(value));
+ case 'string': {
+ // By default node's built in logging doesn't wrap top level
+ // strings with quotes
+ if (indent === 0) {
+ return String(value);
+ }
+ const quote = /[^\\]"/.test(value) ? '"' : "'";
+ return kl.green(String(quote + value + quote));
+ }
+ case 'symbol':
+ return kl.green(value.toString());
+ case 'function':
+ return kl.cyan(`[Function: ${value.name || 'anonymous'}]`);
+ }
+
+ if (value instanceof Element) {
+ return value.outerHTML;
+ }
+
+ seen.add(value);
+
+ const props = Object.keys(value).map(key => {
+ const v = serialize(value[key], mode, indent + 1, seen);
+ return `${key}: ${v}`;
+ });
+
+ if (props.length === 0) {
+ return '{}';
+ } else if (mode === 'flat') {
+ const pretty = props.join(', ');
+ return `{ ${pretty} }`;
+ }
+
+ const pretty = props.map(p => applyIndent(indent + 1) + p).join(',\n');
+ return `{\n${pretty}\n${applyIndent(indent)}}`;
+}
+
+// Use these lines to test pretty formatting:
+//
+// const obj = { foo: 123 };
+// obj.obj = obj;
+// console.log(obj);
+// console.log([1, 2]);
+// console.log(new Set([1, 2]));
+// console.log(new Map([[1, 2]]));
+// console.log({
+// foo: { bar: 123, bob: { a: 1 } }
+// });
+// console.log(
+// 'hey',
+// null,
+// undefined,
+// [1, 2, ['a']],
+// () => {},
+// {
+// type: 'div',
+// props: {},
+// key: undefined,
+// ref: undefined,
+// __k: null,
+// __: null,
+// __b: 0,
+// __e: null,
+// __d: undefined,
+// __c: null,
+// __h: null,
+// constructor: undefined,
+// __v: 1
+// },
+// {
+// foo: { bar: 123, bob: { a: 1, b: new Set([1, 2]), c: new Map([[1, 2]]) } }
+// },
+// new Set([1, 2]),
+// new Map([[1, 2]])
+// );
+// console.log(document.createElement('div'));
diff --git a/preact/test/shared/createContext.test.js b/preact/test/shared/createContext.test.js
new file mode 100644
index 0000000..1c64c3c
--- /dev/null
+++ b/preact/test/shared/createContext.test.js
@@ -0,0 +1,24 @@
+import { createElement, createContext } from '../../';
+import { expect } from 'chai';
+
+/** @jsx createElement */
+/* eslint-env browser, mocha */
+
+describe('createContext', () => {
+ it('should return a Provider and a Consumer', () => {
+ const context = createContext();
+ expect(context).to.have.property('Provider');
+ expect(context).to.have.property('Consumer');
+ });
+
+ it('should return a valid Provider Component', () => {
+ const { Provider } = createContext();
+ const contextValue = { value: 'test' };
+ const children = [<div>child1</div>, <div>child2</div>];
+
+ const providerComponent = <Provider {...contextValue}>{children}</Provider>;
+ //expect(providerComponent).to.have.property('tag', 'Provider');
+ expect(providerComponent.props.value).to.equal(contextValue.value);
+ expect(providerComponent.props.children).to.equal(children);
+ });
+});
diff --git a/preact/test/shared/createElement.test.js b/preact/test/shared/createElement.test.js
new file mode 100644
index 0000000..a7231b6
--- /dev/null
+++ b/preact/test/shared/createElement.test.js
@@ -0,0 +1,299 @@
+import { createElement } from '../../';
+import { expect } from 'chai';
+
+const h = createElement;
+/** @jsx createElement */
+/*eslint-env browser, mocha */
+
+// const buildVNode = (nodeName, attributes, children=[]) => ({
+// nodeName,
+// children,
+// attributes,
+// key: attributes && attributes.key
+// });
+
+describe('createElement(jsx)', () => {
+ it('should return a VNode', () => {
+ let r;
+ expect(() => (r = h('foo'))).not.to.throw();
+ expect(r).to.be.an('object');
+ // expect(r).to.be.an.instanceof(VNode);
+ expect(r).to.have.property('type', 'foo');
+ expect(r)
+ .to.have.property('props')
+ .that.eql({});
+ // expect(r).to.have.deep.property('props.children').that.eql(null);
+ });
+
+ it('should set VNode#type property', () => {
+ expect(<div />).to.have.property('type', 'div');
+ function Test() {
+ return <div />;
+ }
+ expect(<Test />).to.have.property('type', Test);
+ });
+
+ it('should set VNode.constructor property to prevent json injection', () => {
+ const vnode = <span />;
+ expect(vnode.constructor).to.equal(undefined);
+ });
+
+ it('should set VNode#props property', () => {
+ const props = {};
+ expect(h('div', props).props).to.deep.equal(props);
+ });
+
+ it('should set VNode#key property', () => {
+ expect(<div />).to.have.property('key').that.does.not.exist;
+ expect(<div a="a" />).to.have.property('key').that.does.not.exist;
+ expect(<div key="1" />).to.have.property('key', '1');
+ });
+
+ it('should not set VNode#props.key property', () => {
+ expect(<div />).to.not.have.nested.property('props.key');
+ expect(<div key="1" />).to.not.have.nested.property('props.key');
+ expect(<div key={0} />).to.not.have.nested.property('props.key');
+ expect(<div key={''} />).to.not.have.nested.property('props.key');
+ });
+
+ it('should set VNode#ref property', () => {
+ expect(<div />).to.have.property('ref').that.does.not.exist;
+ expect(<div a="a" />).to.have.property('ref').that.does.not.exist;
+ const emptyFunction = () => {};
+ expect(<div ref={emptyFunction} />).to.have.property('ref', emptyFunction);
+ });
+
+ it('should not set VNode#props.ref property', () => {
+ expect(<div />).to.not.have.nested.property('props.ref');
+ expect(<div ref={() => {}} />).to.not.have.nested.property('props.ref');
+ });
+
+ it('should have ordered VNode properties', () => {
+ expect(Object.keys(<div />).filter(key => !/^_/.test(key))).to.deep.equal([
+ 'type',
+ 'props',
+ 'key',
+ 'ref',
+ 'constructor'
+ ]);
+ });
+
+ it('should preserve raw props', () => {
+ let props = { foo: 'bar', baz: 10, func: () => {} },
+ r = h('foo', props);
+ expect(r)
+ .to.be.an('object')
+ .with.property('props')
+ .that.deep.equals(props);
+ });
+
+ it('should support element children', () => {
+ let kid1 = h('bar');
+ let kid2 = h('baz');
+ let r = h('foo', null, kid1, kid2);
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.deep.property('props.children', [kid1, kid2]);
+ });
+
+ it('should support multiple element children, given as arg list', () => {
+ let kid1 = h('bar');
+ let kid3 = h('test');
+ let kid2 = h('baz', null, kid3);
+
+ let r = h('foo', null, kid1, kid2);
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.deep.property('props.children', [kid1, kid2]);
+ });
+
+ it('should handle multiple element children, given as an array', () => {
+ let kid1 = h('bar');
+ let kid3 = h('test');
+ let kid2 = h('baz', null, kid3);
+
+ let r = h('foo', null, [kid1, kid2]);
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.deep.property('props.children', [kid1, kid2]);
+ });
+
+ it('should support nested children', () => {
+ const m = x => {
+ const result = h(x);
+ delete result._original;
+ return result;
+ };
+ expect(h('foo', null, m('a'), [m('b'), m('c')], m('d')))
+ .to.have.nested.property('props.children')
+ .that.eql([m('a'), [m('b'), m('c')], m('d')]);
+
+ expect(h('foo', null, [m('a'), [m('b'), m('c')], m('d')]))
+ .to.have.nested.property('props.children')
+ .that.eql([m('a'), [m('b'), m('c')], m('d')]);
+
+ expect(h('foo', { children: [m('a'), [m('b'), m('c')], m('d')] }))
+ .to.have.nested.property('props.children')
+ .that.eql([m('a'), [m('b'), m('c')], m('d')]);
+
+ expect(h('foo', { children: [[m('a'), [m('b'), m('c')], m('d')]] }))
+ .to.have.nested.property('props.children')
+ .that.eql([[m('a'), [m('b'), m('c')], m('d')]]);
+
+ expect(h('foo', { children: m('a') }))
+ .to.have.nested.property('props.children')
+ .that.eql(m('a'));
+
+ expect(h('foo', { children: 'a' }))
+ .to.have.nested.property('props.children')
+ .that.eql('a');
+ });
+
+ it('should support text children', () => {
+ let r = h('foo', null, 'textstuff');
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.property('props.children')
+ .that.equals('textstuff');
+ });
+
+ it('should override children if null is provided as an argument', () => {
+ let r = h('foo', { foo: 'bar', children: 'baz' }, null);
+
+ expect(r)
+ .to.be.an('object')
+ .to.deep.nested.include({
+ 'props.foo': 'bar',
+ 'props.children': null
+ });
+ });
+
+ it('should NOT set children prop when unspecified', () => {
+ let r = h('foo', { foo: 'bar' });
+
+ expect(r)
+ .to.be.an('object')
+ .to.have.nested.property('props.foo')
+ .not.to.have.nested.property('props.children');
+ });
+
+ it('should NOT merge adjacent text children', () => {
+ const bar = h('bar');
+ const barClone = h('bar');
+ const baz = h('baz');
+ const bazClone = h('baz');
+ const baz2 = h('baz');
+ const baz2Clone = h('baz');
+
+ delete bar._original;
+ delete barClone._original;
+ delete baz._original;
+ delete bazClone._original;
+ delete baz2._original;
+ delete baz2Clone._original;
+
+ let r = h(
+ 'foo',
+ null,
+ 'one',
+ 'two',
+ bar,
+ 'three',
+ baz,
+ baz2,
+ 'four',
+ null,
+ 'five',
+ 'six'
+ );
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.property('props.children')
+ .that.deep.equals([
+ 'one',
+ 'two',
+ barClone,
+ 'three',
+ bazClone,
+ baz2Clone,
+ 'four',
+ null,
+ 'five',
+ 'six'
+ ]);
+ });
+
+ it('should not merge nested adjacent text children', () => {
+ let r = h(
+ 'foo',
+ null,
+ 'one',
+ ['two', null, 'three'],
+ null,
+ ['four', null, 'five', null],
+ 'six',
+ null
+ );
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.property('props.children')
+ .that.deep.equals([
+ 'one',
+ ['two', null, 'three'],
+ null,
+ ['four', null, 'five', null],
+ 'six',
+ null
+ ]);
+ });
+
+ it('should not merge children that are boolean values', () => {
+ let r = h('foo', null, 'one', true, 'two', false, 'three');
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.property('props.children')
+ .that.deep.equals(['one', true, 'two', false, 'three']);
+ });
+
+ it('should not merge children of components', () => {
+ let Component = ({ children }) => children;
+ let r = h(Component, null, 'x', 'y');
+
+ expect(r)
+ .to.be.an('object')
+ .with.nested.property('props.children')
+ .that.deep.equals(['x', 'y']);
+ });
+
+ it('should respect defaultProps', () => {
+ const Component = ({ children }) => children;
+ Component.defaultProps = { foo: 'bar' };
+ expect(h(Component).props).to.deep.equal({ foo: 'bar' });
+ });
+
+ it('should override defaultProps', () => {
+ const Component = ({ children }) => children;
+ Component.defaultProps = { foo: 'default' };
+ expect(h(Component, { foo: 'bar' }).props).to.deep.equal({ foo: 'bar' });
+ });
+
+ it('should ignore props.children if children are manually specified', () => {
+ const element = (
+ <div a children={['a', 'b']}>
+ c
+ </div>
+ );
+ const childrenless = <div a>c</div>;
+ delete element._original;
+ delete childrenless._original;
+
+ expect(element).to.eql(childrenless);
+ });
+});
diff --git a/preact/test/shared/exports.test.js b/preact/test/shared/exports.test.js
new file mode 100644
index 0000000..b075af5
--- /dev/null
+++ b/preact/test/shared/exports.test.js
@@ -0,0 +1,32 @@
+import {
+ createElement,
+ h,
+ createContext,
+ Component,
+ Fragment,
+ render,
+ hydrate,
+ cloneElement,
+ options,
+ createRef,
+ toChildArray,
+ isValidElement
+} from '../../';
+import { expect } from 'chai';
+
+describe('preact', () => {
+ it('should be available as named exports', () => {
+ expect(h).to.be.a('function');
+ expect(createElement).to.be.a('function');
+ expect(Component).to.be.a('function');
+ expect(Fragment).to.exist;
+ expect(render).to.be.a('function');
+ expect(hydrate).to.be.a('function');
+ expect(cloneElement).to.be.a('function');
+ expect(createContext).to.be.a('function');
+ expect(options).to.exist.and.be.an('object');
+ expect(createRef).to.be.a('function');
+ expect(isValidElement).to.be.a('function');
+ expect(toChildArray).to.be.a('function');
+ });
+});
diff --git a/preact/test/shared/isValidElement.test.js b/preact/test/shared/isValidElement.test.js
new file mode 100644
index 0000000..66c49b6
--- /dev/null
+++ b/preact/test/shared/isValidElement.test.js
@@ -0,0 +1,5 @@
+import { createElement, isValidElement, Component } from '../../';
+import { expect } from 'chai';
+import { isValidElementTests } from './isValidElementTests';
+
+isValidElementTests(expect, isValidElement, createElement, Component);
diff --git a/preact/test/shared/isValidElementTests.js b/preact/test/shared/isValidElementTests.js
new file mode 100644
index 0000000..d0e86b5
--- /dev/null
+++ b/preact/test/shared/isValidElementTests.js
@@ -0,0 +1,37 @@
+/** @jsx createElement */
+
+export function isValidElementTests(
+ expect,
+ isValidElement,
+ createElement,
+ Component
+) {
+ describe('isValidElement', () => {
+ it('should check if the argument is a valid vnode', () => {
+ // Failure cases
+ expect(isValidElement(123)).to.equal(false);
+ expect(isValidElement(0)).to.equal(false);
+ expect(isValidElement('')).to.equal(false);
+ expect(isValidElement('abc')).to.equal(false);
+ expect(isValidElement(null)).to.equal(false);
+ expect(isValidElement(undefined)).to.equal(false);
+ expect(isValidElement(true)).to.equal(false);
+ expect(isValidElement(false)).to.equal(false);
+ expect(isValidElement([])).to.equal(false);
+ expect(isValidElement([123])).to.equal(false);
+ expect(isValidElement([null])).to.equal(false);
+
+ // Success cases
+ expect(isValidElement(<div />)).to.equal(true);
+
+ const Foo = () => 123;
+ expect(isValidElement(<Foo />)).to.equal(true);
+ class Bar extends Component {
+ render() {
+ return <div />;
+ }
+ }
+ expect(isValidElement(<Bar />)).to.equal(true);
+ });
+ });
+}
diff --git a/preact/test/ts/Component-test.tsx b/preact/test/ts/Component-test.tsx
new file mode 100644
index 0000000..b037219
--- /dev/null
+++ b/preact/test/ts/Component-test.tsx
@@ -0,0 +1,183 @@
+import 'mocha';
+import { expect } from 'chai';
+import { createElement, Component, RenderableProps, Fragment } from '../../';
+
+// Test `this` binding on event handlers
+function onHandler(this: HTMLInputElement, event: any) {
+ return this.value;
+}
+const foo = <input onChange={onHandler} />;
+
+export class ContextComponent extends Component<{ foo: string }> {
+ getChildContext() {
+ return { something: 2 };
+ }
+
+ render() {
+ return null;
+ }
+}
+
+export interface SimpleComponentProps {
+ initialName: string | null;
+}
+
+export interface SimpleState {
+ name: string | null;
+}
+
+export class SimpleComponent extends Component<
+ SimpleComponentProps,
+ SimpleState
+> {
+ constructor(props: SimpleComponentProps) {
+ super(props);
+ this.state = {
+ name: props.initialName
+ };
+ }
+
+ render() {
+ if (!this.state.name) {
+ return null;
+ }
+ const { initialName, children } = this.props;
+ return (
+ <div>
+ <span>
+ {initialName} / {this.state.name}
+ </span>
+ {children}
+ </div>
+ );
+ }
+}
+
+class DestructuringRenderPropsComponent extends Component<
+ SimpleComponentProps,
+ SimpleState
+> {
+ constructor(props: SimpleComponentProps) {
+ super(props);
+ this.state = {
+ name: props.initialName
+ };
+ }
+
+ render({ initialName, children }: RenderableProps<SimpleComponentProps>) {
+ if (!this.state.name) {
+ return null;
+ }
+ return (
+ <span>
+ {this.props.initialName} / {this.state.name}
+ </span>
+ );
+ }
+}
+
+interface RandomChildrenComponentProps {
+ num?: number;
+ val?: string;
+ span?: boolean;
+}
+
+class RandomChildrenComponent extends Component<RandomChildrenComponentProps> {
+ render() {
+ const { num, val, span } = this.props;
+ if (num) {
+ return num;
+ }
+ if (val) {
+ return val;
+ }
+ if (span) {
+ return <span>hi</span>;
+ }
+ return null;
+ }
+}
+
+class StaticComponent extends Component<SimpleComponentProps, SimpleState> {
+ static getDerivedStateFromProps(
+ props: SimpleComponentProps,
+ state: SimpleState
+ ): Partial<SimpleState> {
+ return {
+ ...props,
+ ...state
+ };
+ }
+
+ static getDerivedStateFromError(err: Error) {
+ return {
+ name: err.message
+ };
+ }
+
+ render() {
+ return null;
+ }
+}
+
+function MapperItem(props: { foo: number }) {
+ return <div />;
+}
+
+function Mapper() {
+ return [1, 2, 3].map(x => <MapperItem foo={x} key={x} />);
+}
+
+describe('Component', () => {
+ const component = new SimpleComponent({ initialName: 'da name' });
+
+ it('has state', () => {
+ expect(component.state.name).to.eq('da name');
+ });
+
+ it('has props', () => {
+ expect(component.props.initialName).to.eq('da name');
+ });
+
+ it('has no base when not mounted', () => {
+ expect(component.base).to.not.exist;
+ });
+
+ describe('setState', () => {
+ // No need to execute these tests. because we only need to check if
+ // the types are working. Executing them would require the DOM.
+ // TODO: Run TS tests in our standard karma setup
+ it.skip('can be used with an object', () => {
+ component.setState({ name: 'another name' });
+ });
+
+ it.skip('can be used with a function', () => {
+ const updater = (state: any, props: any) => ({
+ name: `${state.name} - ${props.initialName}`
+ });
+ component.setState(updater);
+ });
+ });
+
+ describe('render', () => {
+ it('can return null', () => {
+ const comp = new SimpleComponent({ initialName: null });
+ const actual = comp.render();
+
+ expect(actual).to.eq(null);
+ });
+ });
+
+ describe('Fragment', () => {
+ it('should render nested Fragments', () => {
+ var vnode = (
+ <Fragment>
+ <Fragment>foo</Fragment>
+ bar
+ </Fragment>
+ );
+
+ expect(vnode.type).to.be.equal(Fragment);
+ });
+ });
+});
diff --git a/preact/test/ts/VNode-test.tsx b/preact/test/ts/VNode-test.tsx
new file mode 100644
index 0000000..7225901
--- /dev/null
+++ b/preact/test/ts/VNode-test.tsx
@@ -0,0 +1,197 @@
+import 'mocha';
+import { expect } from 'chai';
+import {
+ createElement,
+ Component,
+ toChildArray,
+ FunctionalComponent,
+ ComponentConstructor,
+ ComponentFactory,
+ VNode,
+ ComponentChildren,
+ cloneElement
+} from '../../';
+
+function getDisplayType(vnode: VNode | string | number) {
+ if (typeof vnode === 'string' || typeof vnode == 'number') {
+ return vnode.toString();
+ } else if (typeof vnode.type == 'string') {
+ return vnode.type;
+ } else {
+ return vnode.type.displayName;
+ }
+}
+
+class SimpleComponent extends Component<{}, {}> {
+ render() {
+ return <div>{this.props.children}</div>;
+ }
+}
+
+const SimpleFunctionalComponent = () => <div />;
+
+const a: ComponentFactory = SimpleComponent;
+const b: ComponentFactory = SimpleFunctionalComponent;
+
+describe('VNode TS types', () => {
+ it('is returned by h', () => {
+ const actual = <div className="wow" />;
+ expect(actual).to.include.all.keys('type', 'props', 'key');
+ });
+
+ it('has a nodeName of string when html element', () => {
+ const div = <div>Hi!</div>;
+ expect(div.type).to.equal('div');
+ });
+
+ it('has a nodeName equal to the construction function when SFC', () => {
+ const sfc = <SimpleFunctionalComponent />;
+ expect(sfc.type).to.be.instanceOf(Function);
+ const constructor = sfc.type as FunctionalComponent<any>;
+ expect(constructor.name).to.eq('SimpleFunctionalComponent');
+ });
+
+ it('has a nodeName equal to the constructor of a component', () => {
+ const sfc = <SimpleComponent />;
+ expect(sfc.type).to.be.instanceOf(Function);
+ const constructor = sfc.type as ComponentConstructor<any>;
+ expect(constructor.name).to.eq('SimpleComponent');
+ });
+
+ it('has children which is an array of string or other vnodes', () => {
+ const comp = (
+ <SimpleComponent>
+ <SimpleComponent>child1</SimpleComponent>
+ child2
+ </SimpleComponent>
+ );
+
+ expect(comp.props.children).to.be.instanceOf(Array);
+ expect(comp.props.children[1]).to.be.a('string');
+ });
+
+ it('children type should work with toChildArray', () => {
+ const comp: VNode = <SimpleComponent>child1 {1}</SimpleComponent>;
+
+ const children = toChildArray(comp.props.children);
+ expect(children).to.have.lengthOf(2);
+ });
+
+ it('toChildArray should filter out some types', () => {
+ const compChild = <SimpleComponent />;
+ const comp: VNode = (
+ <SimpleComponent>
+ a{null}
+ {true}
+ {false}
+ {2}
+ {undefined}
+ {['b', 'c']}
+ {compChild}
+ </SimpleComponent>
+ );
+
+ const children = toChildArray(comp.props.children);
+ expect(children).to.deep.equal(['a', 2, 'b', 'c', compChild]);
+ });
+
+ it('functions like getDisplayType should work', () => {
+ function TestComp(props: { children?: ComponentChildren }) {
+ return <div>{props.children}</div>;
+ }
+ TestComp.displayName = 'TestComp';
+
+ const compChild = <TestComp />;
+ const comp: VNode = (
+ <SimpleComponent>
+ a{null}
+ {true}
+ {false}
+ {2}
+ {undefined}
+ {['b', 'c']}
+ {compChild}
+ </SimpleComponent>
+ );
+
+ const types = toChildArray(comp.props.children).map(getDisplayType);
+ expect(types).to.deep.equal(['a', '2', 'b', 'c', 'TestComp']);
+ });
+
+ it('component should work with cloneElement', () => {
+ const comp: VNode = (
+ <SimpleComponent>
+ <div>child 1</div>
+ </SimpleComponent>
+ );
+ const clone: VNode = cloneElement(comp);
+
+ expect(comp.type).to.equal(clone.type);
+ expect(comp.props).not.to.equal(clone.props);
+ expect(comp.props).to.deep.equal(clone.props);
+ });
+
+ it('component should work with cloneElement using generics', () => {
+ const comp: VNode<string> = <SimpleComponent></SimpleComponent>;
+ const clone: VNode<string> = cloneElement<string>(comp);
+
+ expect(comp.type).to.equal(clone.type);
+ expect(comp.props).not.to.equal(clone.props);
+ expect(comp.props).to.deep.equal(clone.props);
+ });
+});
+
+class ComponentWithFunctionChild extends Component<{
+ children: (num: number) => string;
+}> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithFunctionChild>
+ {num => num.toFixed(2)}
+</ComponentWithFunctionChild>;
+
+class ComponentWithStringChild extends Component<{ children: string }> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithStringChild>child</ComponentWithStringChild>;
+
+class ComponentWithNumberChild extends Component<{ children: number }> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithNumberChild>{1}</ComponentWithNumberChild>;
+
+class ComponentWithBooleanChild extends Component<{ children: boolean }> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithBooleanChild>{false}</ComponentWithBooleanChild>;
+
+class ComponentWithNullChild extends Component<{ children: null }> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithNullChild>{null}</ComponentWithNullChild>;
+
+class ComponentWithNumberChildren extends Component<{ children: number[] }> {
+ render() {
+ return null;
+ }
+}
+
+<ComponentWithNumberChildren>
+ {1}
+ {2}
+</ComponentWithNumberChildren>;
diff --git a/preact/test/ts/custom-elements.tsx b/preact/test/ts/custom-elements.tsx
new file mode 100644
index 0000000..0f8d29e
--- /dev/null
+++ b/preact/test/ts/custom-elements.tsx
@@ -0,0 +1,85 @@
+import { createElement, Component, createContext } from '../../';
+
+declare module '../../' {
+ namespace createElement.JSX {
+ interface IntrinsicElements {
+ // Custom element can use JSX EventHandler definitions
+ 'clickable-ce': {
+ optionalAttr?: string;
+ onClick?: MouseEventHandler<HTMLElement>;
+ };
+
+ // Custom Element that extends HTML attributes
+ 'color-picker': HTMLAttributes & {
+ // Required attribute
+ space: 'rgb' | 'hsl' | 'hsv';
+ // Optional attribute
+ alpha?: boolean;
+ };
+
+ // Custom Element with custom interface definition
+ 'custom-whatever': WhateveElAttributes;
+ }
+ }
+}
+
+// Whatever Element definition
+
+interface WhateverElement {
+ instanceProp: string;
+}
+
+interface WhateverElementEvent {
+ eventProp: number;
+}
+
+// preact.JSX.HTMLAttributes also appears to work here but for consistency,
+// let's use createElement.JSX
+interface WhateveElAttributes extends createElement.JSX.HTMLAttributes {
+ someattribute?: string;
+ onsomeevent?: (this: WhateverElement, ev: WhateverElementEvent) => void;
+}
+
+// Ensure context still works
+const { Provider, Consumer } = createContext({ contextValue: '' });
+
+// Sample component that uses custom elements
+
+class SimpleComponent extends Component {
+ componentProp = 'componentProp';
+ render() {
+ // Render inside div to ensure standard JSX elements still work
+ return (
+ <Provider value={{ contextValue: 'value' }}>
+ <div>
+ <clickable-ce
+ onClick={e => {
+ // `this` should be instance of SimpleComponent since this is an
+ // arrow function
+ console.log(this.componentProp);
+
+ // Validate `currentTarget` is HTMLElement
+ console.log('clicked ', e.currentTarget.style.display);
+ }}
+ ></clickable-ce>
+ <color-picker space="rgb" dir="rtl"></color-picker>
+ <custom-whatever
+ dir="auto" // Inherited prop from HTMLAttributes
+ someattribute="string"
+ onsomeevent={function(e) {
+ // Validate `this` and `e` are the right type
+ console.log('clicked', this.instanceProp, e.eventProp);
+ }}
+ ></custom-whatever>
+
+ {/* Ensure context still works */}
+ <Consumer>
+ {({ contextValue }) => contextValue.toLowerCase()}
+ </Consumer>
+ </div>
+ </Provider>
+ );
+ }
+}
+
+const component = <SimpleComponent />;
diff --git a/preact/test/ts/hoc-test.tsx b/preact/test/ts/hoc-test.tsx
new file mode 100644
index 0000000..455d9e0
--- /dev/null
+++ b/preact/test/ts/hoc-test.tsx
@@ -0,0 +1,50 @@
+import { expect } from 'chai';
+import {
+ createElement,
+ ComponentFactory,
+ ComponentConstructor,
+ Component
+} from '../../';
+import { SimpleComponent, SimpleComponentProps } from './Component-test';
+
+export interface highlightedProps {
+ isHighlighted: boolean;
+}
+
+export function highlighted<T>(
+ Wrappable: ComponentFactory<T>
+): ComponentConstructor<T & highlightedProps> {
+ return class extends Component<T & highlightedProps> {
+ constructor(props: T & highlightedProps) {
+ super(props);
+ }
+
+ render() {
+ let className = this.props.isHighlighted ? 'highlighted' : '';
+ return (
+ <div className={className}>
+ <Wrappable {...this.props} />
+ </div>
+ );
+ }
+
+ toString() {
+ return `Highlighted ${Wrappable.name}`;
+ }
+ };
+}
+
+const HighlightedSimpleComponent = highlighted<SimpleComponentProps>(
+ SimpleComponent
+);
+
+describe('hoc', () => {
+ it('wraps the given component', () => {
+ const highlight = new HighlightedSimpleComponent({
+ initialName: 'initial name',
+ isHighlighted: true
+ });
+
+ expect(highlight.toString()).to.eq('Highlighted SimpleComponent');
+ });
+});
diff --git a/preact/test/ts/jsx-namespacce-test.tsx b/preact/test/ts/jsx-namespacce-test.tsx
new file mode 100644
index 0000000..d6e10bd
--- /dev/null
+++ b/preact/test/ts/jsx-namespacce-test.tsx
@@ -0,0 +1,16 @@
+import { createElement, Component } from '../../';
+
+// declare global JSX types that should not be mixed with preact's internal types
+declare global {
+ namespace JSX {
+ interface Element {
+ unknownProperty: string;
+ }
+ }
+}
+
+class SimpleComponent extends Component {
+ render() {
+ return <div>It works</div>;
+ }
+}
diff --git a/preact/test/ts/preact-global-test.tsx b/preact/test/ts/preact-global-test.tsx
new file mode 100644
index 0000000..e6c3286
--- /dev/null
+++ b/preact/test/ts/preact-global-test.tsx
@@ -0,0 +1,6 @@
+import { createElement } from '../../src';
+
+// Test that preact types are available via the global `preact` namespace.
+
+let component: preact.ComponentChild;
+component = <div>Hello World</div>;
diff --git a/preact/test/ts/preact.tsx b/preact/test/ts/preact.tsx
new file mode 100644
index 0000000..9779d41
--- /dev/null
+++ b/preact/test/ts/preact.tsx
@@ -0,0 +1,297 @@
+import {
+ createElement,
+ render,
+ Component,
+ ComponentProps,
+ FunctionalComponent,
+ AnyComponent,
+ h
+} from '../../';
+
+interface DummyProps {
+ initialInput: string;
+}
+
+interface DummyState {
+ input: string;
+}
+
+class DummyComponent extends Component<DummyProps, DummyState> {
+ constructor(props: DummyProps) {
+ super(props);
+ this.state = {
+ input: `x${this.props}x`
+ };
+ }
+
+ private setRef = (el: AnyComponent<any>) => {
+ console.log(el);
+ };
+
+ render({ initialInput }: DummyProps, { input }: DummyState) {
+ return (
+ <div>
+ <DummerComponent initialInput={initialInput} input={input} />
+ {/* Can specify all Preact attributes on a typed FunctionalComponent */}
+ <ComponentWithChildren
+ initialInput={initialInput}
+ input={input}
+ key="1"
+ ref={this.setRef}
+ />
+ </div>
+ );
+ }
+}
+
+interface DummerComponentProps extends DummyProps, DummyState {}
+
+function DummerComponent({ input, initialInput }: DummerComponentProps) {
+ return (
+ <div>
+ Input: {input}, initial: {initialInput}
+ </div>
+ );
+}
+
+render(createElement('div', { title: 'test', key: '1' }), document);
+render(
+ createElement(DummyComponent, { initialInput: 'The input', key: '1' }),
+ document
+);
+render(
+ createElement(DummerComponent, {
+ initialInput: 'The input',
+ input: 'New input',
+ key: '1'
+ }),
+ document
+);
+render(h('div', { title: 'test', key: '1' }), document);
+render(h(DummyComponent, { initialInput: 'The input', key: '1' }), document);
+render(
+ h(DummerComponent, {
+ initialInput: 'The input',
+ input: 'New input',
+ key: '1'
+ }),
+ document
+);
+
+// Accessing children
+const ComponentWithChildren: FunctionalComponent<DummerComponentProps> = ({
+ input,
+ initialInput,
+ children
+}) => {
+ return (
+ <div>
+ <span>{initialInput}</span>
+ <span>{input}</span>
+ <span>{children}</span>
+ </div>
+ );
+};
+
+const UseOfComponentWithChildren = () => {
+ return (
+ <ComponentWithChildren initialInput="initial" input="input">
+ <span>child 1</span>
+ <span>child 2</span>
+ </ComponentWithChildren>
+ );
+};
+
+// using ref and or jsx
+class ComponentUsingRef extends Component<any, any> {
+ private array: string[];
+ private refs: (Element | null)[] = [];
+
+ constructor() {
+ super();
+ this.array = ['1', '2'];
+ }
+
+ render() {
+ this.refs = [];
+ return (
+ <div jsx>
+ {this.array.map(el => (
+ <span ref={this.setRef}>{el}</span>
+ ))}
+
+ {/* Can specify Preact attributes on a component */}
+ <DummyComponent initialInput="1" key="1" ref={this.setRef} />
+ </div>
+ );
+ }
+
+ private setRef = (el: Element | null) => {
+ this.refs.push(el);
+ };
+}
+
+// using lifecycles
+class ComponentWithLifecycle extends Component<DummyProps, DummyState> {
+ render() {
+ return <div>Hi</div>;
+ }
+
+ componentWillMount() {
+ console.log('componentWillMount');
+ }
+
+ componentDidMount() {
+ console.log('componentDidMount');
+ }
+
+ componentWillUnmount() {
+ console.log('componentWillUnmount');
+ }
+
+ componentWillReceiveProps(nextProps: DummyProps, nextCtx: any) {
+ const { initialInput } = nextProps;
+ console.log('componentWillReceiveProps', initialInput, nextCtx);
+ }
+
+ shouldComponentUpdate(
+ nextProps: DummyProps,
+ nextState: DummyState,
+ nextContext: any
+ ) {
+ return false;
+ }
+
+ componentWillUpdate(
+ nextProps: DummyProps,
+ nextState: DummyState,
+ nextContext: any
+ ) {
+ console.log('componentWillUpdate', nextProps, nextState, nextContext);
+ }
+
+ componentDidUpdate(
+ previousProps: DummyProps,
+ previousState: DummyState,
+ previousContext: any
+ ) {
+ console.log(
+ 'componentDidUpdate',
+ previousProps,
+ previousState,
+ previousContext
+ );
+ }
+}
+
+// Default props: JSX.LibraryManagedAttributes
+
+class DefaultProps extends Component<{ text: string; bool: boolean }> {
+ static defaultProps = {
+ text: 'hello'
+ };
+
+ render() {
+ return <div>{this.props.text}</div>;
+ }
+}
+
+const d1 = <DefaultProps bool={false} text="foo" />;
+const d2 = <DefaultProps bool={false} />;
+
+class DefaultPropsWithUnion extends Component<
+ { default: boolean } & (
+ | {
+ type: 'string';
+ str: string;
+ }
+ | {
+ type: 'number';
+ num: number;
+ }
+ )
+> {
+ static defaultProps = {
+ default: true
+ };
+
+ render() {
+ return <div />;
+ }
+}
+
+const d3 = <DefaultPropsWithUnion type="string" str={'foo'} />;
+const d4 = <DefaultPropsWithUnion type="number" num={0xf00} />;
+const d5 = <DefaultPropsWithUnion type="string" str={'foo'} default={false} />;
+const d6 = <DefaultPropsWithUnion type="number" num={0xf00} default={false} />;
+
+class DefaultUnion extends Component<
+ | {
+ type: 'number';
+ num: number;
+ }
+ | {
+ type: 'string';
+ str: string;
+ }
+> {
+ static defaultProps = {
+ type: 'number',
+ num: 1
+ };
+
+ render() {
+ return <div />;
+ }
+}
+
+const d7 = <DefaultUnion />;
+const d8 = <DefaultUnion num={1} />;
+const d9 = <DefaultUnion type="number" />;
+const d10 = <DefaultUnion type="string" str="foo" />;
+
+class ComponentWithDefaultProps extends Component<{ value: string }> {
+ static defaultProps = { value: '' };
+ render() {
+ return <div>{this.props.value}</div>;
+ }
+}
+
+const withDefaultProps = <ComponentWithDefaultProps />;
+
+interface PartialState {
+ foo: string;
+ bar: number;
+}
+
+class ComponentWithPartialSetState extends Component<{}, PartialState> {
+ render({}, { foo, bar }: PartialState) {
+ return (
+ <button onClick={() => this.handleClick('foo')}>
+ {foo}-{bar}
+ </button>
+ );
+ }
+ handleClick = (value: keyof PartialState) => {
+ this.setState({ [value]: 'updated' });
+ };
+}
+
+const withPartialSetState = <ComponentWithPartialSetState />;
+
+let functionalProps: ComponentProps<typeof DummerComponent> = {
+ initialInput: '',
+ input: ''
+};
+
+let classProps: ComponentProps<typeof DummyComponent> = {
+ initialInput: ''
+};
+
+let elementProps: ComponentProps<'button'> = {
+ type: 'button'
+};
+
+// Typing of style property
+const acceptsNumberAsLength = <div style={{ marginTop: 20 }} />;
+const acceptsStringAsLength = <div style={{ marginTop: '20px' }} />;
diff --git a/preact/test/ts/refs.tsx b/preact/test/ts/refs.tsx
new file mode 100644
index 0000000..9edb730
--- /dev/null
+++ b/preact/test/ts/refs.tsx
@@ -0,0 +1,76 @@
+import {
+ createElement,
+ Component,
+ createRef,
+ FunctionalComponent,
+ Fragment,
+ RefObject,
+ RefCallback
+} from '../../';
+
+// Test Fixtures
+const Foo: FunctionalComponent = () => <span>Foo</span>;
+class Bar extends Component {
+ render() {
+ return <span>Bar</span>;
+ }
+}
+
+// Using Refs
+class CallbackRef extends Component {
+ divRef: RefCallback<HTMLDivElement> = div => {
+ if (div !== null) {
+ console.log(div.tagName);
+ }
+ };
+ fooRef: RefCallback<Component> = foo => {
+ if (foo !== null) {
+ console.log(foo.base);
+ }
+ };
+ barRef: RefCallback<Bar> = bar => {
+ if (bar !== null) {
+ console.log(bar.base);
+ }
+ };
+
+ render() {
+ return (
+ <Fragment>
+ <div ref={this.divRef} />
+ <Foo ref={this.fooRef} />
+ <Bar ref={this.barRef} />
+ </Fragment>
+ );
+ }
+}
+
+class CreateRefComponent extends Component {
+ private divRef: RefObject<HTMLDivElement> = createRef();
+ private fooRef: RefObject<Component> = createRef();
+ private barRef: RefObject<Bar> = createRef();
+
+ componentDidMount() {
+ if (this.divRef.current != null) {
+ console.log(this.divRef.current.tagName);
+ }
+
+ if (this.fooRef.current != null) {
+ console.log(this.fooRef.current.base);
+ }
+
+ if (this.barRef.current != null) {
+ console.log(this.barRef.current.base);
+ }
+ }
+
+ render() {
+ return (
+ <Fragment>
+ <div ref={this.divRef} />
+ <Foo ref={this.fooRef} />
+ <Bar ref={this.barRef} />
+ </Fragment>
+ );
+ }
+}
diff --git a/preact/test/ts/tsconfig.json b/preact/test/ts/tsconfig.json
new file mode 100644
index 0000000..36621f3
--- /dev/null
+++ b/preact/test/ts/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "es6",
+ "moduleResolution": "node",
+ "lib": ["es6", "dom"],
+ "strict": true,
+ "typeRoots": ["../../"],
+ "types": [],
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "jsxFactory": "createElement"
+ },
+ "include": ["./**/*.ts", "./**/*.tsx"]
+}