diff --git a/.eslintrc b/.eslintrc index 9f03e693..50b266f3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,14 @@ { - "extends": "eslint:recommended", + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2015, + "sourceType": "module" + }, + "extends": [ + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended" + ], "env": { "es6": true, "node": true, @@ -7,20 +16,19 @@ }, "rules": { "no-var": "error", - "space-before-function-paren": ["error", "never"], "standard/no-callback-literal": "off", "arrow-spacing": "error", "arrow-parens": ["error", "always"], "arrow-body-style": ["error", "as-needed"], "prefer-template": "error", - "max-len": ["warn", { "code": 80 }], + "max-len": ["warn", { "code": 120 }], "no-unused-vars": ["warn", { "argsIgnorePattern": "^_$|^e$|^reject$|^resolve$" }], "no-console": ["error", { "allow": ["warn", "error"] }], - "valid-jsdoc": "error", + "valid-jsdoc": "warn", "semi": ["error", "always"], "quotes": ["error", "double", { "allowTemplateLiterals": true }] } diff --git a/.github/workflows/api-docs.yaml b/.github/workflows/api-docs.yaml new file mode 100644 index 00000000..e0b2d769 --- /dev/null +++ b/.github/workflows/api-docs.yaml @@ -0,0 +1,27 @@ +name: API Docs + +on: release + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Generate API documentation + run: npm install && npm run generate-docs + - + name: Deploy to GitHub Pages + if: success() + uses: crazy-max/ghaction-github-pages@v2 + with: + target_branch: gh-pages + build_dir: docs + commit_message: | + Deploy to GitHub Pages + Signed-off-by: Lance Ball + allow_empty_commit: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/nodejs-ci-action.yml b/.github/workflows/nodejs-ci-action.yml new file mode 100644 index 00000000..c1de8925 --- /dev/null +++ b/.github/workflows/nodejs-ci-action.yml @@ -0,0 +1,65 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + name: Build and test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [10.x, 12.x] + + steps: + - uses: actions/checkout@v2 + - name: Test on Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test + + coverage: + name: Code coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Generate coverage report + uses: actions/setup-node@v1 + with: + node-version: 12.x + - run: npm ci + - run: npm run build --if-present + - run: npm run coverage + - name: Upload coverage report to storage + uses: actions/upload-artifact@v1 + with: + name: coverage + path: coverage/lcov.info + + publish: + name: Publish code coverage report + needs: coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Download coverage report from storage + uses: actions/download-artifact@v1 + with: + name: coverage + - name: Upload coverage report to codacy + uses: actions/setup-node@v1 + with: + node-version: 12.x + - run: | + ( [[ "${CODACY_PROJECT_TOKEN}" != "" ]] && npm run coverage-publish ) || echo "Coverage report not published" + env: + CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..da7f445b --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: Issue Triage + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + triage_issues: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity.' + days-before-stale: 30 + days-before-close: -1 + stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity.' + stale-issue-label: 'status/no-issue-activity' + stale-pr-label: 'status/no-pr-activity' diff --git a/.gitignore b/.gitignore index d08c926e..8fa1cf23 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,14 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +# Generated files +*.d.ts +index.js +/lib +/browser +/bundles +/dist + # Runtime data pids *.pid diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000..64ba7d49 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: true, + trailingComma: "all", + doubleQuote: true, + printWidth: 120, + tabWidth: 2 +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 37d1a085..00000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: node_js -node_js: -- lts/* -- 10 -cache: npm -jobs: - include: - - stage: github release - node_js: lts/* - deploy: - provider: releases - api_key: - secure: ls/IjZdRpFZlEQsZrsmXn7h7QTZuM8x4gZq3r75sOyTWcmKgZLN27hYCtk8SPcuNbt+ZA3otQEQJvDuGTCAwtbU4lxQjfXswP9M/om01hf3J7uTcjtol4XOsmBFqMCktW94pVH4U7Q18IHeP5JBnlfLzAY/YifRKKNWNrsI6bbnfcGgsFJYvICwKL5LEj7bxtJk156lBBJm9TscMX48BFsUBvnCNTDEBYNaaGkoCz6DPM0Da7QPF5exHcNiiF9SoR60WeGI1q+MdZyE+1AG0VpUp7sMxJafXSBbgYquPEZmG9ScZbkVyWP7ps3sgkqDkxtH4kNe9zF4PySRYfxYKJ03ECwbSmj9gxsIc8o2zhrLFinmHydLxoOEh5EygB2euekgMhoEKL0kA8bteaaqmD+3sna8MbXG4HhvIrEAspNtOFZyUm/SmgvXXxaKiDtwTw/5CvPCc7VH51NuC5QZi0UehLzatDpDNsj/ffMwDp5F4SBIZgUUmmIWfnAODNGwSwBKxdPVS3etkTeiBxerw2uzC6qjNW1QJyb9s+iU3rC59IEAuq6u4ymv3caDIHLnJbCMHRHQoIbq86oErqb8DhH6KrTlBnwlGBpUVhdpYMt0QX2Uncu9uHMBZ2CQNZ819PJa4QWvc1Ixoj3auKqvoMfPNQFOskMWnrnxkOokyPZg= - skip_cleanup: true - on: - tags: true - - - stage: npm release - node_js: lts/* - deploy: - provider: npm - email: fabiojose@gmail.com - api_key: - secure: o5aF53FTPUSiJBbCZ/anBWQCgEJCctpxuTgGJbO1NpiheOM/xENiSmv+n2a5sGrhhqT0h7k15mE/ZgtL8TnM+45AHOg3EGez5JoR1XMIXnSeCno1GFK4waHDcEn3eLW9P35r1S5/RMTqbEUvqpyK/fzVZ4ecyh9t7dVvJV8MyQGo+r+oO3SLYEIt7YC6vZRh+dV3cK8jr7MHkHmQfZ6tZrALMKsj6QNTUtmk+IU52WHi4oe1iPuypS5dlaVdmanX7ZRtC7gR0Dko2/wja+DPOAKgG/S0aS794cxal7P5k/K34mvqT8iaCl4vN5uIcRsipgsprIahk2G2NgnIVCetBda9LhpMNUdn3j+v4T0lx3jiqP1eq01nk8YFpTV4Xz9VlYHK/E6NYQhUmd7N6WO9vXmOEDGBvWrDfQ1QMx+/TM9r3vzK9ps3sjkDFaAtJ2ZQ0pvFMEQTaLKak24ntWltSWZKvxdjYnS+bcfyIQQGagvqgZsnkKzeudO9N9Atp4OGcst9CAvvykDsfmLlARAiyvpuDVyUivuaOlCB9J7VBt1sbBfsiHpnJcSsMVz1OMRX5EGewbla530guoePhjTUDVit3NyUMz3ZQQTN9VSK3tA+NLyR0Ex8Oel+byHJDYyf+36GCDvoXagaPUVk5M5BINiCw2IWhxDgRGrcEp9JIUI= - skip_cleanup: true - on: - tags: true - -env: - global: - secure: t0A5/Fk1Qj8WkAk0ZuQqpFjrpINV6gfL+d1fXgq03EOAG/7FEyyz+AKkYaLT6avp26VWBzLgEoWC3RNmWD0v1/Ruckb95YpQcb5e4JotAce1ZsHgGTgx0UO146tkyGvXBw6MmO2nX2O/sHzkmyR6rlKkBi9LEKokJ9OFd6fi9nNtksgUDxkqNlNTu100fIQAV2RcN47C6iUx+gJIa+H/8QX/Cz02MyheXLe8a763wMQapz5GHrk2KuVY6FpylcAlSi2so+PjEGfKq3MWaQnTPkevkRDLtGcecVtFAq/0VbvoKc97PHoVT0x+nf48k1gj2VnQtYj6EVB74yRvqM9KkNOsfAQ0z9zF5wXMRs11SZywSViLQsnD9Ue6eYbYmodOKn4DFlLtoRyLBUspzLuoL76lERGe2cHU+Ebz2Nb9jL88o+SjfGrSJQEJU7SLZLbzJ7T/3SspWcAlo+Fo9UTCOB4/yL22Yge/SWQkdd1orBhohpjpyrU9Z1+IRvVoU1EICr04zSFUwEwn6Yxbt0ArgTZBEf11bf+YpCo+rBXNAd+XbZ79PGOEppFb+Hxrt9i1S1RnesDJnwC0k7cswU55Rv5gcNCo9lC+N4ZwS5y+5r6DsBfB+12YdsFORFyNbClECro1ODv4STf3rBBnjL8+ziPFjP4d4OwiGY+vG8bvLXY= -script: - - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then npm run coverage-publish; else npm test; fi - -branches: - only: - - master diff --git a/CHANGELOG.md b/CHANGELOG.md index e62f365a..4da4e176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,116 @@ # Changelog -All notable changes to this project will be documented in this file. +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +### [2.0.2](https://github.com/cloudevents/sdk-javascript/compare/v2.0.1...v2.0.2) (2020-06-08) -## [Unreleased] -### Fixed +### Bug Fixes -- Support for mTLS in v1.0 Binary and Structured Emitters: issue [#48](https://github.com/cloudevents/sdk-javascript/issues/48). Note that this fix is only valid for v1.0 and does not address the problem in v0.3 and below. +* add correct types to improve TypeScript behavior ([#202](https://github.com/cloudevents/sdk-javascript/issues/202)) ([da365e0](https://github.com/cloudevents/sdk-javascript/commit/da365e09ebcb493f63e6962800230899f1b978ad)) +* fix references to constants - remove .js extension ([#200](https://github.com/cloudevents/sdk-javascript/issues/200)) ([c757a2b](https://github.com/cloudevents/sdk-javascript/commit/c757a2bce1e5432c420db7a4ae4755058964cff7)) +* use /lib in gitignore so src/lib is not ignored ([#199](https://github.com/cloudevents/sdk-javascript/issues/199)) ([fba3294](https://github.com/cloudevents/sdk-javascript/commit/fba3294ce04a30be0e5ab551a1fa01727dc8d1f8)) -### Removed -- Removed support for Node.js 6, 7 and 8 - all of which are EOL at this point. Travis CI modified to test on Node.js 10 and 12. +### Documentation -### Added +* **README:** fix example typo ([#208](https://github.com/cloudevents/sdk-javascript/issues/208)) ([9857eda](https://github.com/cloudevents/sdk-javascript/commit/9857eda5ef85e64898f7c742e1ffabb714236d6a)), closes [#173](https://github.com/cloudevents/sdk-javascript/issues/173) + + +### Miscellaneous + +* ts formatter ([#210](https://github.com/cloudevents/sdk-javascript/issues/210)) ([90782a9](https://github.com/cloudevents/sdk-javascript/commit/90782a9e17dbd293d379f0ec134cf7fb06d0f36f)) + +### [2.0.1](https://github.com/cloudevents/sdk-javascript/compare/v2.0.0...v2.0.1) (2020-06-01) + + +### Bug Fixes + +* initialize CloudEvent's extensions property ([#192](https://github.com/cloudevents/sdk-javascript/issues/192)) ([0710166](https://github.com/cloudevents/sdk-javascript/commit/0710166ce9397f402b835fae745923d11357d15e)) +* introduce CloudEventV1 and CloudEventV03 interfaces ([#194](https://github.com/cloudevents/sdk-javascript/issues/194)) ([a5befbe](https://github.com/cloudevents/sdk-javascript/commit/a5befbe0cf11a53e39f3ea33990b037e2f165611)) + + +### Miscellaneous + +* CI workflow to only upload report if CODACY_PROJECT_TOKEN is set ([#193](https://github.com/cloudevents/sdk-javascript/issues/193)) ([aa320e7](https://github.com/cloudevents/sdk-javascript/commit/aa320e7fe4ce59284378cdd9420c0191d6a54b39)) +* minor typos in guidance docs ([#196](https://github.com/cloudevents/sdk-javascript/issues/196)) ([15cd763](https://github.com/cloudevents/sdk-javascript/commit/15cd7638da2906c7be7b550cc07ce551c2f7d1f8)) + +## [2.0.0](https://github.com/cloudevents/sdk-javascript/compare/v1.0.0...v2.0.0) (2020-05-27) + + +### ⚠ BREAKING CHANGES + +* change CloudEvent to use direct object notation and get/set properties (#172) +* refactor HTTP bindings and specifications (#165) +* expose a version agnostic event emitter (#141) +* **unmarshaller:** remove asynchronous 0.3 unmarshaller API (#126) + +### Features + +* add ValidationError type extending TypeError ([#151](https://github.com/cloudevents/sdk-javascript/issues/151)) ([09b0c76](https://github.com/cloudevents/sdk-javascript/commit/09b0c76826657222f6dc93fa377349a62e9b628f)) +* expose a mode and version agnostic event receiver ([#120](https://github.com/cloudevents/sdk-javascript/issues/120)) ([54f242b](https://github.com/cloudevents/sdk-javascript/commit/54f242b79e03dbba382f5016a1279ddf392c354f)) +* expose a version agnostic event emitter ([#141](https://github.com/cloudevents/sdk-javascript/issues/141)) ([250a0a1](https://github.com/cloudevents/sdk-javascript/commit/250a0a144c5fbeac237e04dcd3f54e05dc30fc70)) +* **unmarshaller:** remove asynchronous 0.3 unmarshaller API ([#126](https://github.com/cloudevents/sdk-javascript/issues/126)) ([63ae1ad](https://github.com/cloudevents/sdk-javascript/commit/63ae1ad527f0b9652222cbc7e51f7a895410a4b4)) +* formatter.js es6 ([#87](https://github.com/cloudevents/sdk-javascript/issues/87)) ([c36f194](https://github.com/cloudevents/sdk-javascript/commit/c36f1949d0176574ace24fee87ce850f01f1e2f5)) +* use CloudEvents not cloudevents everywhere ([#101](https://github.com/cloudevents/sdk-javascript/issues/101)) ([05ecbde](https://github.com/cloudevents/sdk-javascript/commit/05ecbdea4f594a6012ba7717f3311d0c20c2985f)) + + +### Bug Fixes + +* ensure binary events can handle no content-type header ([#134](https://github.com/cloudevents/sdk-javascript/issues/134)) ([72a87df](https://github.com/cloudevents/sdk-javascript/commit/72a87dfb2d05411f9f58b417bbc7db4233dcbbbf)) +* Fix Express example installation ([#77](https://github.com/cloudevents/sdk-javascript/issues/77)) ([bb8e0f9](https://github.com/cloudevents/sdk-javascript/commit/bb8e0f9e0ca7aef00103d03f6071a648a9fab76d)) +* make application/json the default content type in binary mode ([#118](https://github.com/cloudevents/sdk-javascript/issues/118)) ([d9e9ae6](https://github.com/cloudevents/sdk-javascript/commit/d9e9ae6bdcbaf80dc35d486765c9189a176be650)) +* misspelled word ([#113](https://github.com/cloudevents/sdk-javascript/issues/113)) ([cd6a3ee](https://github.com/cloudevents/sdk-javascript/commit/cd6a3eec7dca4bac1e2ba9fbba9949799e6c97d8)) +* misspelled word ([#115](https://github.com/cloudevents/sdk-javascript/issues/115)) ([53524ac](https://github.com/cloudevents/sdk-javascript/commit/53524acb0e18598b1376fa4485cdd2a117e892fd)) +* protects the consts from being changed in other parts of the code. ([fbcbcec](https://github.com/cloudevents/sdk-javascript/commit/fbcbcec4e885618367c5cb25a8e030549dd829df)) +* remove d.ts types. Fixes [#83](https://github.com/cloudevents/sdk-javascript/issues/83) ([#84](https://github.com/cloudevents/sdk-javascript/issues/84)) ([6c223e2](https://github.com/cloudevents/sdk-javascript/commit/6c223e2c34769fc0b2f2dbc58a398eb85442af92)) +* support mTLS in 1.0 Binary and Structured emitters ([3a063d7](https://github.com/cloudevents/sdk-javascript/commit/3a063d72451d1156df8fe9c3499ef1e81e905060)) +* throw "no cloud event detected" if one can't be read ([#139](https://github.com/cloudevents/sdk-javascript/issues/139)) ([ef7550d](https://github.com/cloudevents/sdk-javascript/commit/ef7550d60d248e1720172c0a18ae5dc21e8da5a1)) + + +### Tests + +* remove uuid require in spec_03_tests.js ([#145](https://github.com/cloudevents/sdk-javascript/issues/145)) ([c56c203](https://github.com/cloudevents/sdk-javascript/commit/c56c203d6af7b9bc1be09a82d33fdbe7aea7f331)) +* use constants in spec_03_tests.js ([#144](https://github.com/cloudevents/sdk-javascript/issues/144)) ([2882aff](https://github.com/cloudevents/sdk-javascript/commit/2882affb382366654b3c7749ed274b9b74f84723)) +* use header constants in receiver tests ([#131](https://github.com/cloudevents/sdk-javascript/issues/131)) ([60bf05c](https://github.com/cloudevents/sdk-javascript/commit/60bf05c8f2d4275b5432ce544982077d22b4b8ff)) +* use header constants in unmarshaller tests ([#60](https://github.com/cloudevents/sdk-javascript/issues/60)) ([e087805](https://github.com/cloudevents/sdk-javascript/commit/e0878055a207154eaf040d00f778ad3854a5d7d2)) + + +### lib + +* change CloudEvent to use direct object notation and get/set properties ([#172](https://github.com/cloudevents/sdk-javascript/issues/172)) ([abc114b](https://github.com/cloudevents/sdk-javascript/commit/abc114b24e448a33d2a4f583cdc7ae191940bdca)) +* refactor HTTP bindings and specifications ([#165](https://github.com/cloudevents/sdk-javascript/issues/165)) ([6f0b5ea](https://github.com/cloudevents/sdk-javascript/commit/6f0b5ea5f11ae8a451df2c46208bbd1e08ff7227)) + + +### Documentation + +* add instructions and details to contributors guide ([#105](https://github.com/cloudevents/sdk-javascript/issues/105)) ([fd99cb1](https://github.com/cloudevents/sdk-javascript/commit/fd99cb1e598bc27f0ec41755745942b0487f6905)) +* add JSDocs for top level API objects ([#140](https://github.com/cloudevents/sdk-javascript/issues/140)) ([b283583](https://github.com/cloudevents/sdk-javascript/commit/b283583c0c07e6da40fac26a2b8c7dac894468dc)) +* add maintainer guidelines for landing PRs ([#177](https://github.com/cloudevents/sdk-javascript/issues/177)) ([fdc79ae](https://github.com/cloudevents/sdk-javascript/commit/fdc79ae12083f989f80ec548669fc2070c69bb83)) +* organize README badges and remove TS example ([#112](https://github.com/cloudevents/sdk-javascript/issues/112)) ([07323e0](https://github.com/cloudevents/sdk-javascript/commit/07323e078fdd60814ed61a65d6756e23cf523400)) +* remove 0.1, 0.2 spec support from README ([56036b0](https://github.com/cloudevents/sdk-javascript/commit/56036b09ddfeb00d19678e118ea5f742b88cdfc7)) +* remove repo structure docs ([#111](https://github.com/cloudevents/sdk-javascript/issues/111)) ([223a7c6](https://github.com/cloudevents/sdk-javascript/commit/223a7c6f03732fa4dc91c0af78adfcc4c026e7c8)) +* update README and examples with new API ([#138](https://github.com/cloudevents/sdk-javascript/issues/138)) ([b866edd](https://github.com/cloudevents/sdk-javascript/commit/b866edddd9593b5456981f1f5613225b8335ec05)) + + +### Miscellaneous -- Added support for standard-version and conventional-changelog +* add action to detect and close stale issues ([5a6cde5](https://github.com/cloudevents/sdk-javascript/commit/5a6cde5695049403c7f614c42067511908b54ffc)) +* add coverage GitHub action ([#185](https://github.com/cloudevents/sdk-javascript/issues/185)) ([349fe8e](https://github.com/cloudevents/sdk-javascript/commit/349fe8e9bd3da711ab5c8221932d1bc5f551a1da)) +* add eslint configuration and npm script ([3f238a0](https://github.com/cloudevents/sdk-javascript/commit/3f238a01248aba54b0208aaaa54b66cf2f54a749)) +* add GitHub action for CI on master and prs ([#181](https://github.com/cloudevents/sdk-javascript/issues/181)) ([0fe57d1](https://github.com/cloudevents/sdk-javascript/commit/0fe57d123ac01458a6fa50752caf0071ed2571f6)) +* add npm fix command ([#74](https://github.com/cloudevents/sdk-javascript/issues/74)) ([005d532](https://github.com/cloudevents/sdk-javascript/commit/005d5327e49cd271fe84382d18df7019dc3f73ad)) +* add standard-version and release script ([f47bca4](https://github.com/cloudevents/sdk-javascript/commit/f47bca4ff0ca93dc83a927bb9ee4818e317a5e75)) +* adds files section in package.json ([#147](https://github.com/cloudevents/sdk-javascript/issues/147)) ([f8a62b2](https://github.com/cloudevents/sdk-javascript/commit/f8a62b2843b12fe894201670770a00c034ab701d)) +* es6 base64 parser ([#75](https://github.com/cloudevents/sdk-javascript/issues/75)) ([d042ef1](https://github.com/cloudevents/sdk-javascript/commit/d042ef1dbb555e2500036716d4170661dc48fe3e)) +* es6 parser ([#98](https://github.com/cloudevents/sdk-javascript/issues/98)) ([cd6decd](https://github.com/cloudevents/sdk-javascript/commit/cd6decd74904888557bfc53045c87efe630fb88c)) +* es6 unmarshaller ([#108](https://github.com/cloudevents/sdk-javascript/issues/108)) ([79ec3ef](https://github.com/cloudevents/sdk-javascript/commit/79ec3ef126a46afbd3217dfdb969b00f20e38f56)) +* fix CI code coverage publishing ([#78](https://github.com/cloudevents/sdk-javascript/issues/78)) ([8fb0ddf](https://github.com/cloudevents/sdk-javascript/commit/8fb0ddf6eb0dd05b0728444f404e1014a9348599)) +* Modify CI to also build backport branch(es) ([#122](https://github.com/cloudevents/sdk-javascript/issues/122)) ([c1fda94](https://github.com/cloudevents/sdk-javascript/commit/c1fda94d25f84db097e75177b166c3f18f707dda)) +* remove note with bad link and non SDK docs ([#109](https://github.com/cloudevents/sdk-javascript/issues/109)) ([f30c814](https://github.com/cloudevents/sdk-javascript/commit/f30c814a09896d31f821ebe5eb5ba95cd264d699)) +* update eslint rules to disallow var usage ([e83db29](https://github.com/cloudevents/sdk-javascript/commit/e83db297ae5761248d0c34a9d440e6a4285a645d)) +* Update uuid dependency ([42246ce](https://github.com/cloudevents/sdk-javascript/commit/42246ce36b9898eea1d5daa5f43ddb13ee6b12d0)) +* use es6 for cloudevents.js ([#73](https://github.com/cloudevents/sdk-javascript/issues/73)) ([12ac181](https://github.com/cloudevents/sdk-javascript/commit/12ac1813005d1c88e86c6fc9de675516dd3e290c)) ## [1.0.0] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 105a919f..4e2a4d45 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,61 +2,40 @@ :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: -Following you will see some guidelines about how to contribute with -JavaScript SDK. - -## Branch Management - -We use Gitflow to manage our branches and that's ok when `develop` branch is -ahead of `master`. - -- [Gitflow](https://nvie.com/posts/a-successful-git-branching-model/) by @nvie - -## Changelog - -The [CHANGELOG.md](./CHANGELOG.md) will be updated with your commits if you format -your commit messages following the -[Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary). -If you are unsure what prefix to use for a commit, you can consult the -[package.json](https://github.com/cloudevents/sdk-javascript/blob/master/package.json) file -in this repository. In the `standard-version.types` section, you can see all of the commit -types that will be committed to the changelog based on the prefix in the first line of -your commit message. For example, the commit message: - -```log -fix: removed a bug that was causing the rotation of the earth to change -``` - -will show up in the "Bug Fixes" section of the changelog for a given release. +We welcome contributions from the community! Please take some time to become +acquainted with the process before submitting a pull request. There are just +a few things to keep in mind. ## Pull Requests -Guidelines about how to perform pull requests. +Typically a pull request should relate to an existing issue. If you have +found a bug, want to add an improvement, or suggest an API change, please +create an issue before proceeding with a pull request. For very minor changes +such as typos in the documentation this isn't really necessary. -- before submit the PR, open an issue and link them +For step by step help with managing your pull request, have a look at our +[PR Guidelines](pr_guidelines.md) document. ### Commit Messages -Please follow the Conventional Commits specification noted above. the first line of -your commit should be prefixed with a type, be a single sentence with no period, and -succinctly indicate what this commit changes. - -All commit message lines should be kept to fewer than 80 characters if possible. - -### PR to `develop` - -- fixes in the documentation (readme, contributors) -- propose new files for the documentation -- implementation of new features +Please follow the +[Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary). -### PR to `master` +### Sign your work -- hot fixes +Each PR must be signed. Be sure your `git` `user.name` and `user.email` are configured +then use the `--signoff` flag for your commits. -## Style Guide +```console +git commit --signoff +``` -_TODO_ +### Style Guide -### JavaScript Style Guide +Code style for this module is maintained using [`eslint`](https://www.npmjs.com/package/eslint). +When you run tests with `npm test` linting is performed first. If you want to +check your code style for linting errors without running tests, you can just +run `npm run lint`. If there are errors, you can usually fix them automatically +by running `npm run fix`. -_TODO_ +Linting rules are declared in [.eslintrc](https://github.com/cloudevents/sdk-javascript/blob/master/.eslintrc). diff --git a/LICENSE b/LICENSE index 261eeb9e..6ac31b90 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018-2020 CloudEvents Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 9e6e51f2..82734645 100644 --- a/README.md +++ b/README.md @@ -2,282 +2,140 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/bd66e7c52002481993cd6d610534b0f7)](https://www.codacy.com/app/fabiojose/sdk-javascript?utm_source=github.com&utm_medium=referral&utm_content=cloudevents/sdk-javascript&utm_campaign=Badge_Grade) [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/bd66e7c52002481993cd6d610534b0f7)](https://www.codacy.com/app/fabiojose/sdk-javascript?utm_source=github.com&utm_medium=referral&utm_content=cloudevents/sdk-javascript&utm_campaign=Badge_Coverage) -[![Build Status](https://travis-ci.org/cloudevents/sdk-javascript.svg?branch=master)](https://travis-ci.org/cloudevents/sdk-javascript) -[![downloads](https://img.shields.io/npm/dy/cloudevents-sdk.svg)](https://www.npmjs.com/package/cloudevents-sdk) +![Node.js CI](https://github.com/cloudevents/sdk-javascript/workflows/Node.js%20CI/badge.svg) [![npm version](https://img.shields.io/npm/v/cloudevents-sdk.svg)](https://www.npmjs.com/package/cloudevents-sdk) [![vulnerabilities](https://snyk.io/test/github/cloudevents/sdk-javascript/badge.svg)](https://snyk.io/test/github/cloudevents/sdk-javascript) -[![licence](https://img.shields.io/github/license/cloudevents/sdk-javascript)](http://www.apache.org/licenses/LICENSE-2.0) - The CloudEvents SDK for JavaScript. -## Status - -This SDK is still considered a work in progress. +## Features -This SDK current supports the following versions of CloudEvents: +* Represent CloudEvents in memory +* Serialize and deserialize CloudEvents in different [event formats](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format). +* Send and recieve CloudEvents with via different [protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding). -- v1.0 - -**Checkout the [changelog](CHANGELOG.md) to see what's going on!** +_Note:_ Supports CloudEvent versions 0.3, 1.0 ## Installation -This CloudEvents SDK requires nodejs 6.11+ - -### Nodejs +The CloudEvents SDK requires a current LTS version of Node.js. At the moment +those are Node.js 10.x and Node.js 12.x. To install in your Node.js project: -```sh +```console npm install cloudevents-sdk ``` -## Specification Support - -These are the supported specifications by this version. - -| **Specifications** | v0.3 | **v1.0** | -|---------------------------------------|------|----------| -| CloudEvents | yes | yes | -| HTTP Transport Binding - Structured | yes | yes | -| HTTP Transport Binding - Binary | yes | yes | -| JSON Event Format | yes | yes | - -### What we can do - -| **What** | v0.3 | **v1.0** | -|-------------------------------------|------|----------| -| Create events | yes | yes | -| Emit Structured events over HTTP | yes | yes | -| Emit Binary events over HTTP | yes | yes | -| JSON Event Format | yes | yes | -| Receive Structured events over HTTP | yes | yes | -| Receive Binary events over HTTP | yes | yes | - -## How to use - -### Usage - -```js -const v1 = require("cloudevents-sdk/v1"); - -/* - * Creating an event - */ -let myevent = v1.event() - .type("com.github.pull.create") - .source("urn:event:from:myapi/resource/123"); -``` -#### Formatting - -```js -const v1 = require("cloudevents-sdk/v1"); - -/* - * Creating an event - */ -let myevent = v1.event() - .type("com.github.pull.create") - .source("urn:event:from:myapi/resource/123"); - -/* - * Format the payload and return it - */ -let formatted = myevent.format(); -``` - -#### Emitting - -```js -const v1 = require("cloudevents-sdk/v1"); - -/* - * Creating an event - */ -let myevent = v1.event() - .type("com.github.pull.create") - .source("urn:event:from:myapi/resource/123"); - -// The binding configuration using POST -let config = { - method: "POST", - url : "https://myserver.com" -}; - -// The binding instance -let binding = new v1.StructuredHTTPEmitter(config); - -// Emit the event using Promise -binding.emit(myevent) - .then(response => { - // Treat the response - console.log(response.data); - - }).catch(err => { - // Deal with errors - console.error(err); - }); -``` +### Receiving and Emitting Events #### Receiving Events -You can choose any framework for port binding. But, use the -StructuredHTTPReceiver or BinaryHTTPReceiver to process the HTTP Payload and -HTTP Headers, extracting the CloudEvents. - -:smiley: **Checkout the full working example: [here](./examples/express-ex).** +You can choose almost any popular web framework for port binding. Use an +`HTTPReceiver` to process the incoming HTTP request. The receiver accepts +binary and structured events in either the 1.0 or 0.3 protocol formats. ```js -// some parts were removed // - -const v1 = require("cloudevents-sdk/v1"); - -const receiver = new v1.StructuredHTTPReceiver(); - -// some parts were removed // - -app.post("/", (req, res) => { - try { - let myevent = receiver.parse(req.body, req.headers); +const { + CloudEvent, + Receiver +} = require("cloudevents-sdk"); - // TODO use the event +// Create a receiver to accept events over HTTP +const receiver = new Receiver(); - res.status(201).send("Event Accepted"); - - } catch(err) { - // TODO deal with errors - console.error(err); - res.status(415) - .header("Content-Type", "application/json") - .send(JSON.stringify(err)); - } -}); +// body and headers come from an incoming HTTP request, e.g. express.js +const receivedEvent = receiver.accept(req.headers, req.body); +console.log(receivedEvent); ``` -## Unit Testing - -The unit test checks the result of formatted payload and the constraints. +#### Emitting Events -```bash -npm test -``` - -## The API +You can send events over HTTP in either binary or structured format. -### `CloudEvent` class +By default, the `Emitter` will emit events over HTTP POST using the +binary transport protocol. The `Emitter` will examine the `specversion` +of the event being sent, and use the appropriate protocol version. To send +structured events, add `Protocol.HTTPStructured` as a parameter to +`emitter.send()`. ```js -/* - * Format the payload and return an Object. - */ -Object CloudEvent.format() - -/* - * Format the payload as String. - */ -String CloudEvent.toString() -``` +const { CloudEvent, Emitter, Protocol, Version } = require("cloudevents-sdk"); -### `Formatter` classes - -Every formatter class must implement these methods to work properly. +// With only an endpoint URL, this creates a v1 emitter +const emitter = new Emitter({ + url: "https://cloudevents.io/example" +}); +const event = new CloudEvent({ + type, source, data +}); -```js -/* - * Format the CloudEvent payload argument and return an Object. - */ -Object Formatter.format(Object) - -/* - * Format the CloudEvent payload as String. - */ -String Formatter.toString(Object) +// By default, the emitter will send binary events +emitter.send(event).then((response) => { + // handle the response + }).catch(console.error); + +// To send a structured event, just add that as an option +emitter.send(event, { protocol: Protocol.HTTPStructured }) + .then((response) => { + // handle the response + }).catch(console.error); + +// To send an event to an alternate URL, add that as an option +emitter.send(event, { url: "https://alternate.com/api" }) + .then((response) => { + // handle the response + }).catch(console.error); + +// Sending a v0.3 event works the same, If your event has a +// specversion property of Version.V03, then it will be sent +// using the 0.3 transport protocol +emitter.send(new CloudEvent({ specversion: Version.V03, source, type })) + .then((response) => { + // handle the response + }).catch(console.error); ``` -### `Parser` classes +## CloudEvent Objects -Every Parser class must implement these methods to work properly. +All created `CloudEvent` objects are read-only. If you need to update a property or add a new extension to an existing cloud event object, you can use the `cloneWith` method. This will return a new `CloudEvent` with any update or new properties. For example: ```js -/* - * The default constructor with Parser as decorator - */ -Parser(Parser) - -/* - * Try to parse the payload to some event format - */ -Object Parser.parse(payload) -``` - -### `Spec` classes +const { + CloudEvent, +} = require("cloudevents-sdk"); -Every Spec class must implement these methods to work properly. +// Create a new CloudEvent +const ce = new CloudEvent({...}); -```js -/* - * The constructor must receives the CloudEvent type. - */ -Spec(CloudEvent) - -/* - * Checks the spec constraints, throwing an error if do not pass. - * @throws Error when it is an invalid event - */ -Spec.check() - -/* - * Checks if the argument pass through the spec constraints - * @throws Error when it is an invalid event - */ -Spec.check(Object) +// Add a new extension to an existing CloudEvent +const ce2 = ce.cloneWith({extension: "Value"}); ``` -### `Binding` classes - -Every Binding class must implement these methods to work properly. - -#### Emitter Binding - -Following we have the signature for the binding to emit CloudEvents. - -```js -/* - * The constructor must receives the map of configurations. - */ -Binding(config) - -/* - * Emits the event using an instance of CloudEvent. - */ -Binding.emit(cloudEvent) -``` +### Example Applications -#### Receiver Binding +There are a few trivial example applications in +[the examples folder](https://github.com/cloudevents/sdk-javascript/tree/master/examples). +There you will find Express.js, TypeScript and Websocket examples. -Following we have the signature for the binding to receive CloudEvents. +## Supported specification features -```js -/* - * The constructor must receives the map of configurations. - */ -Receiver(config) - -/* - * Checks if some Object and a Map of headers - * follows the binding definition, throwing an error if did not follow - */ -Receiver.check(Object, Map) - -/* - * Checks and parse as CloudEvent - */ -CloudEvent Receiver.parse(Object, Map) -``` +| Core Specification | [v0.3](v03spec) | [v1.0](v1spec) | +| ----------------------------- | --- | --- | +| CloudEvents Core | :heavy_check_mark: | :heavy_check_mark: | +--- -## Versioning +| Event Formats | [v0.3](v03spec) | [v1.0](v1spec) | +| ----------------------------- | --- | --- | +| AVRO Event Format | :x: | :x: | +| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: | +--- -- `x.M.p`: where `x` relates to spec version, `M` relates to minor and `p` relates -to fixes. See [semver](https://semver.org/) +| Transport Protocols | [v0.3](v03spec) | [v1.0](v1spec) | +| ----------------------------- | --- | --- | +| AMQP Protocol Binding | :x: | :x: | +| HTTP Protocol Binding | :heavy_check_mark: | :heavy_check_mark: | +| Kafka Protocol Binding | :x: | :x: | +| MQTT Protocol Binding | :x: | :x: | +| NATS Protocol Binding | :x: | :x: | ## Community @@ -291,3 +149,12 @@ to fixes. See [semver](https://semver.org/) [CNCF's Slack workspace](https://slack.cncf.io/). - Email: https://lists.cncf.io/g/cncf-cloudevents-sdk - Contact for additional information: Fabio José (`@fabiojose` on slack). + +## Contributing + +We love contributions from the community! Please check the +[Contributor's Guide](https://github.com/cloudevents/sdk-javascript/blob/master/CONTRIBUTING.md) +for information on how to get involved. + +[v1spec]: https://github.com/cloudevents/spec/tree/v1.0 +[v103pec]: https://github.com/cloudevents/spec/tree/v0.3 \ No newline at end of file diff --git a/cucumber.js b/cucumber.js new file mode 100644 index 00000000..abde5e23 --- /dev/null +++ b/cucumber.js @@ -0,0 +1,11 @@ +// cucumber.js +let common = [ + "--require-module ts-node/register", // Load TypeScript module + "--require test/conformance/steps.ts", // Load step definitions + "--format progress-bar", // Load custom formatter + "--format node_modules/cucumber-pretty", // Load custom formatter +].join(" "); + +module.exports = { + default: common, +}; diff --git a/examples/express-ex/README.md b/examples/express-ex/README.md index 5ab53b1c..5a41f8fa 100644 --- a/examples/express-ex/README.md +++ b/examples/express-ex/README.md @@ -6,7 +6,7 @@ npm start ``` -## Spec v1.0 +## Latest Supported Spec (v1.0) __A Structured One__ @@ -17,7 +17,7 @@ __A Structured One__ curl -X POST \ -d'@../payload/v1/structured-event-0.json' \ -H'Content-Type:application/cloudevents+json' \ - http://localhost:3000/v1 + http://localhost:3000/ ``` __A Structured One with Extension__ @@ -28,7 +28,7 @@ __A Structured One with Extension__ curl -X POST \ -d'@../payload/v1/structured-event-1.json' \ -H'Content-Type:application/cloudevents+json' \ - http://localhost:3000/v1 + http://localhost:3000/ ``` __A Structured One with Base64 Event Data__ @@ -39,7 +39,7 @@ __A Structured One with Base64 Event Data__ curl -X POST \ -d'@../payload/v1/structured-event-2.json' \ -H'Content-Type:application/cloudevents+json' \ - http://localhost:3000/v1 + http://localhost:3000/ ``` __A Binary One__ @@ -53,7 +53,7 @@ curl -X POST \ -H'ce-source:https://github.com/cloudevents/spec/pull/123' \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-11-06T11:17:00Z' \ - http://localhost:3000/v1/binary + http://localhost:3000/ ``` __A Binary One with Extension__ @@ -68,7 +68,7 @@ curl -X POST \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-11-06T11:17:00Z' \ -H'ce-my-extension:extension value' \ - http://localhost:3000/v1/binary + http://localhost:3000/ ``` __A Binary One with Base 64 Encoding__ @@ -82,12 +82,9 @@ curl -X POST \ -H'ce-source:https://github.com/cloudevents/spec/pull/123' \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-11-06T11:17:00Z' \ - http://localhost:3000/v1/binary + http://localhost:3000/ ``` -__A Batch One__ - -TODO ## Spec v0.3 @@ -99,7 +96,7 @@ __A Structured One__ curl -X POST \ -d'@../payload/v03/structured-event-0.json' \ -H'Content-Type:application/cloudevents+json' \ - http://localhost:3000/v03 + http://localhost:3000/ ``` __A Structured One with Extension__ @@ -110,7 +107,7 @@ __A Structured One with Extension__ curl -X POST \ -d'@../payload/v03/structured-event-1.json' \ -H'Content-Type:application/cloudevents+json' \ - http://localhost:3000/v03 + http://localhost:3000/ ``` __A Binary One__ @@ -124,7 +121,7 @@ curl -X POST \ -H'ce-source:https://github.com/cloudevents/spec/pull/123' \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-06-21T17:31:00Z' \ - http://localhost:3000/v03 + http://localhost:3000/ ``` __A Binary One with Extension__ @@ -139,7 +136,7 @@ curl -X POST \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-06-21T17:31:00Z' \ -H'ce-my-extension:extension value' \ - http://localhost:3000/v03 + http://localhost:3000/ ``` __A Binary One with Base 64 Encoding__ @@ -154,10 +151,6 @@ curl -X POST \ -H'ce-id:45c83279-c8a1-4db6-a703-b3768db93887' \ -H'ce-time:2019-06-21T17:31:00Z' \ -H'ce-datacontentencoding:base64' \ - http://localhost:3000/v03 + http://localhost:3000/ ``` -__A Batch One__ - -TODO - diff --git a/examples/express-ex/index.js b/examples/express-ex/index.js index ba6fa5e2..da72cf89 100644 --- a/examples/express-ex/index.js +++ b/examples/express-ex/index.js @@ -1,90 +1,39 @@ /* eslint-disable no-console */ const express = require("express"); -const app = express(); - -const v03 = require("cloudevents-sdk/v03"); -const unmarshaller03 = new v03.HTTPUnmarshaller(); +const { Receiver } = require("cloudevents-sdk"); -const v1 = require("cloudevents-sdk/v1"); -const structured1 = new v1.StructuredHTTPReceiver(); -const binary1 = new v1.BinaryHTTPReceiver(); +const app = express(); +const receiver = new Receiver(); app.use((req, res, next) => { let data = ""; req.setEncoding("utf8"); - req.on("data", function(chunk) { + req.on("data", function (chunk) { data += chunk; }); - req.on("end", function() { + req.on("end", function () { req.body = data; next(); }); }); -app.post("/v1", function(req, res) { - console.log(req.headers); - console.log(req.body); - - try { - const myevent = structured1.parse(req.body, req.headers); - // pretty print - console.log("Accepted event:"); - console.log(JSON.stringify(myevent.format(), null, 2)); - - res.status(201) - .json(myevent.format()); - } catch (err) { - console.error(err); - res.status(415) - .header("Content-Type", "application/json") - .send(JSON.stringify(err)); - } -}); - -app.post("/v1/binary", function(req, res) { - console.log(req.headers); - console.log(req.body); +app.post("/", function (req, res) { + console.log("HEADERS", req.headers); + console.log("BODY", req.body); try { - const myevent = binary1.parse(req.body, req.headers); - // pretty print - console.log("Accepted event:"); - console.log(JSON.stringify(myevent.format(), null, 2)); - - res.status(201) - .json(myevent.format()); + const event = receiver.accept(req.headers, req.body); + console.log(`Accepted event: ${event}`); + res.status(201).json(event); } catch (err) { console.error(err); - res.status(415) - .header("Content-Type", "application/json") - .send(JSON.stringify(err)); + res.status(415).header("Content-Type", "application/json").send(JSON.stringify(err)); } }); -app.post("/v03", function(req, res) { - console.log(req.headers); - console.log(req.body); - - unmarshaller03.unmarshall(req.body, req.headers) - .then((cloudevent) => { - // pretty print - console.log("Accepted event:"); - console.log(JSON.stringify(cloudevent.format(), null, 2)); - - res.status(201) - .json(cloudevent.format()); - }) - .catch((err) => { - console.error(err); - res.status(415) - .header("Content-Type", "application/json") - .send(JSON.stringify(err)); - }); -}); - -app.listen(3000, function() { +app.listen(3000, function () { console.log("Example app listening on port 3000!"); }); diff --git a/examples/express-ex/package.json b/examples/express-ex/package.json index 9819abf7..ae7e226f 100644 --- a/examples/express-ex/package.json +++ b/examples/express-ex/package.json @@ -14,7 +14,7 @@ "author": "fabiojose@gmail.com", "license": "Apache-2.0", "dependencies": { - "cloudevents-sdk": "~1.0.0", + "cloudevents-sdk": "~2.0.2", "express": "^4.17.1" } } diff --git a/examples/typescript-ex/README.md b/examples/typescript-ex/README.md index d55e2b5b..f8107f72 100644 --- a/examples/typescript-ex/README.md +++ b/examples/typescript-ex/README.md @@ -15,5 +15,3 @@ Then, start ```bash npm start ``` - -See your event payload [here, at requestbin](https://requestbin.com/r/enu90y24i64jp) diff --git a/examples/typescript-ex/package.json b/examples/typescript-ex/package.json index 31e87b8d..c577e5fb 100644 --- a/examples/typescript-ex/package.json +++ b/examples/typescript-ex/package.json @@ -11,20 +11,21 @@ "license": "Apache-2.0", "keywords": [], "scripts": { - "start": "node build/src/index.js", + "start": "node build/index.js", "test": "echo \"Error: no test specified\" && exit 1", "check": "gts check", "clean": "gts clean", "compile": "tsc -p .", + "watch": "tsc -p . --watch", "fix": "gts fix", "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check" }, "devDependencies": { - "gts": "^1.1.0", - "typescript": "~3.5.0", "@types/node": "^8.9.0", - "cloudevents-sdk": "1.0.0" + "cloudevents-sdk": "~2.0.2", + "gts": "^1.1.0", + "typescript": "~3.9.5" } } diff --git a/examples/typescript-ex/prettier.config.js b/examples/typescript-ex/prettier.config.js deleted file mode 100644 index d305ebd0..00000000 --- a/examples/typescript-ex/prettier.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - singleQuote: true, - trailingComma: "es5" -}; diff --git a/examples/typescript-ex/src/index.ts b/examples/typescript-ex/src/index.ts index f12eee45..0a871ad3 100644 --- a/examples/typescript-ex/src/index.ts +++ b/examples/typescript-ex/src/index.ts @@ -1,79 +1,49 @@ -import CloudEvent, { - event, - StructuredHTTPEmitter, - BinaryHTTPEmitter, - StructuredHTTPReceiver, - BinaryHTTPReceiver -} from 'cloudevents-sdk/v1'; +import { CloudEvent, CloudEventV1, Receiver } from "cloudevents-sdk"; export function doSomeStuff() { - - const myevent: CloudEvent = event() - .source('/source') - .type('type') - .dataContentType('text/plain') - .dataschema('http://d.schema.com/my.json') - .subject('cha.json') - .data('my-data') - .addExtension("my-ext", "0x600"); - - console.log(myevent.toString()); - console.log(myevent.getExtensions()); - - const config = { - method: "POST", - url : "https://enu90y24i64jp.x.pipedream.net/" - }; - - // ------ emitter structured - const structured = new StructuredHTTPEmitter(config); - structured.emit(myevent).then(res => { - // success - console.log("Structured Mode: Success!") - }) - .catch(err => { - // error - console.error(err); + const receiver = new Receiver(); + + const myevent: CloudEventV1 = new CloudEvent({ + source: "/source", + type: "type", + datacontenttype: "text/plain", + dataschema: "https://d.schema.com/my.json", + subject: "cha.json", + data: "my-data", }); + myevent.extension1 = "some extension data"; - // ------ emitter binary - const binary = new BinaryHTTPEmitter(config); - binary.emit(myevent).then(res => { - console.log("Binary Mode: Success!"); - }) - .catch(err => { - console.error(err); - }); + console.log("My structured event:", myevent); // ------ receiver structured - const payload = myevent.toString(); + // The header names should be standarized to use lowercase const headers = { - "Content-Type":"application/cloudevents+json" + "content-type": "application/cloudevents+json", }; - const receiverStructured = new StructuredHTTPReceiver(); - console.log(receiverStructured.parse(payload, headers).toString()); + // Typically used with an incoming HTTP request where myevent.format() is the actual + // body of the HTTP + console.log("Received structured event:", receiver.accept(headers, myevent)); // ------ receiver binary - const extension1 = "mycuston-ext1"; const data = { - "data" : "dataString" + data: "dataString", }; const attributes = { - "ce-type" : "type", - "ce-specversion" : "1.0", - "ce-source" : "source", - "ce-id" : "id", - "ce-time" : "2019-06-16T11:42:00Z", - "ce-dataschema" : "http://schema.registry/v1", - "Content-Type" : "application/json", - "ce-extension1" : extension1 + "ce-type": "type", + "ce-specversion": "1.0", + "ce-source": "source", + "ce-id": "id", + "ce-time": "2019-06-16T11:42:00Z", + "ce-dataschema": "http://schema.registry/v1", + "Content-Type": "application/json", + "ce-extension1": "extension1", }; - const receiverBinary = new BinaryHTTPReceiver(); - console.log(receiverBinary.parse(data, attributes).toString()); + console.log("My binary event:", receiver.accept(attributes, data)); + console.log("My binary event extensions:", receiver.accept(attributes, data)); -return true; + return true; } doSomeStuff(); diff --git a/examples/typescript-ex/tsconfig.json b/examples/typescript-ex/tsconfig.json index 85710e86..c4f3c0e3 100644 --- a/examples/typescript-ex/tsconfig.json +++ b/examples/typescript-ex/tsconfig.json @@ -1,8 +1,8 @@ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { - "rootDir": ".", - "outDir": "build", + "rootDir": "./src", + "outDir": "./build/", "lib": [ "es6", "dom" diff --git a/examples/websocket/README.md b/examples/websocket/README.md new file mode 100644 index 00000000..8c5b7d2d --- /dev/null +++ b/examples/websocket/README.md @@ -0,0 +1,45 @@ +# WebSocket Example + +This example shows how simple it is to use CloudEvents over a websocket +connection. The code here shows backend communication from two server +side processes, and also between a browser and a server process. + +## Running the Example + +This simple project consists of a server and a client. The server receives +`CloudEvents` from the client over a local websocket connection. + + +To get started, first install dependencies. + +```sh +npm install +``` + +### Server +The server opens a websocket and waits for incoming connections. It expects that any +messages it receives will be a CloudEvent. When received, it reads the data field, +expecting a zip code. It then fetches the current weather for that zip code and +responds with a CloudEvent containing the body of the Weather API response as the +event data. + +You will need to change one line in the `server.js` file and provide your Open +Weather API key. + +To start the server, run `node server.js`. + +### Client +Upon start, the client prompts a user for a zip code, then sends a CloudEvent over +a websocket to the server with the provided zip code as the event data. The server +fetches the current weather for that zip code and returns it as a CloudEvent. The +client extracts the data and prints the current weather to the console. + +To start the client, run `node client.js` + +### Browser +Open the [`index.html`]('./index.html') file in your browser and provide a zip +code in the provided form field. The browser will send the zip code in the data +field of a CloudEvent over a websocket. When it receives a response from the server +it prints the weather, or an error message, to the screen. + +To terminate the client or server, type CTL-C. diff --git a/examples/websocket/client.js b/examples/websocket/client.js new file mode 100644 index 00000000..eb949c8f --- /dev/null +++ b/examples/websocket/client.js @@ -0,0 +1,46 @@ +/* eslint-disable no-console */ +const readline = require("readline"); +const WebSocket = require("ws"); +const ws = new WebSocket("ws://localhost:8080"); + +const { CloudEvent } = require("cloudevents-sdk"); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +rl.on("close", (_) => console.log("\n\nConnection closed! Press CTL-C to exit.")); + +ws.on("message", function incoming(message) { + const event = new CloudEvent(JSON.parse(message)); + if (event.type === "weather.error") { + console.error(`Error: ${event.data}`); + } else { + print(event.data); + } + ask(); +}); + +function ask() { + rl.question("Would you like to see the current weather? Provide a zip code: ", function (zip) { + console.log("Fetching weather data from server..."); + const event = new CloudEvent({ + type: "weather.query", + source: "/weather.client", + data: { zip }, + }); + ws.send(event.toString()); + }); +} + +function print(data) { + console.log(` +Current weather for ${data.name}: ${data.weather[0].main} +------------------------------------------ +With ${data.weather[0].description}, the temperature is ${Math.round(data.main.temp)}F +and the wind is blowing at ${Math.round(data.wind.speed)}mph. +`); +} + +ask(); diff --git a/examples/websocket/index.html b/examples/websocket/index.html new file mode 100644 index 00000000..da6ba43d --- /dev/null +++ b/examples/websocket/index.html @@ -0,0 +1,62 @@ + + + + CloudEvent Example + + + + +

Weather By Zip Code

+

Please provide a zip code + +

+

+

+ + \ No newline at end of file diff --git a/examples/websocket/package.json b/examples/websocket/package.json new file mode 100644 index 00000000..155f77a1 --- /dev/null +++ b/examples/websocket/package.json @@ -0,0 +1,22 @@ +{ + "name": "websocket-cloudevents", + "version": "0.0.1", + "description": "An example application that sends and receives CloudEvents over a websocket", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "keywords": [ + "cloudevents", + "example", + "websocket" + ], + "author": "", + "license": "ISC", + "dependencies": { + "cloudevents-sdk": "^2.0.2", + "got": "^11.3.0", + "ws": "^7.3.0" + } +} diff --git a/examples/websocket/server.js b/examples/websocket/server.js new file mode 100644 index 00000000..ccca33c0 --- /dev/null +++ b/examples/websocket/server.js @@ -0,0 +1,50 @@ +/* eslint-disable no-console */ +const got = require("got"); + +const { CloudEvent } = require("cloudevents-sdk"); +const WebSocket = require("ws"); +const wss = new WebSocket.Server({ port: 8080 }); + +const api = "https://api.openweathermap.org/data/2.5/weather"; +const key = "REPLACE WITH API KEY"; + +console.log("WebSocket server started. Waiting for events."); + +wss.on("connection", function connection(ws) { + console.log("Connection received"); + ws.on("message", function incoming(message) { + console.log(`Message received: ${message}`); + const event = new CloudEvent(JSON.parse(message)); + fetch(event.data.zip) + .then((weather) => { + const response = new CloudEvent({ + dataContentType: "application/json", + type: "current.weather", + source: "/weather.server", + data: weather, + }); + ws.send(JSON.stringify(response)); + }) + .catch((err) => { + console.error(err); + ws.send( + JSON.stringify( + new CloudEvent({ + type: "weather.error", + source: "/weather.server", + data: err.toString(), + }), + ), + ); + }); + }); +}); + +function fetch(zip) { + const query = `${api}?zip=${zip}&appid=${key}&units=imperial`; + return new Promise((resolve, reject) => { + got(query) + .then((response) => resolve(JSON.parse(response.body))) + .catch((err) => reject(err.message)); + }); +} diff --git a/index.js b/index.js deleted file mode 100644 index 22e87aab..00000000 --- a/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const CloudEvent = require("./lib/cloudevent.js"); -const HTTPReceiver = require("./lib/bindings/http/http_receiver.js"); - -module.exports = { - CloudEvent, - HTTPReceiver -}; diff --git a/lib/bindings/http/commons.js b/lib/bindings/http/commons.js deleted file mode 100644 index f0c646d5..00000000 --- a/lib/bindings/http/commons.js +++ /dev/null @@ -1,33 +0,0 @@ -const Constants = require("./constants.js"); - -// Specific sanity for content-type header -function sanityContentType(contentType) { - if (contentType) { - return Array.of(contentType) - .map((c) => c.split(";")) - .map((c) => c.shift()) - .shift(); - } - - return contentType; -} - -function sanityAndClone(headers) { - const sanityHeaders = {}; - - Array.from(Object.keys(headers)) - .filter((header) => Object.hasOwnProperty.call(headers, header)) - .forEach((header) => { - sanityHeaders[header.toLowerCase()] = headers[header]; - }); - - sanityHeaders[Constants.HEADER_CONTENT_TYPE] = - sanityContentType(sanityHeaders[Constants.HEADER_CONTENT_TYPE]); - - return sanityHeaders; -} - -module.exports = { - sanityAndClone, - sanityContentType -}; diff --git a/lib/bindings/http/emitter_binary.js b/lib/bindings/http/emitter_binary.js deleted file mode 100644 index 8c60e05a..00000000 --- a/lib/bindings/http/emitter_binary.js +++ /dev/null @@ -1,49 +0,0 @@ -const axios = require("axios"); - -const Constants = require("./constants.js"); -const defaults = {}; -defaults[Constants.HEADERS] = {}; -defaults[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] = - Constants.DEFAULT_CONTENT_TYPE; - -function BinaryHTTPEmitter(config, headerByGetter, extensionPrefix) { - this.config = Object.assign({}, defaults, config); - this.headerByGetter = headerByGetter; - this.extensionPrefix = extensionPrefix; -} - -BinaryHTTPEmitter.prototype.emit = function(cloudevent) { - const config = Object.assign({}, this.config); - const headers = Object.assign({}, this.config[Constants.HEADERS]); - - Object.keys(this.headerByGetter) - .filter((getter) => cloudevent[getter]()) - .forEach((getter) => { - const header = this.headerByGetter[getter]; - headers[header.name] = - header.parser( - cloudevent[getter]() - ); - }); - - // Set the cloudevent payload - const formatted = cloudevent.format(); - let data = formatted.data; - data = (formatted.data_base64 ? formatted.data_base64 : data); - - // Have extensions? - const exts = cloudevent.getExtensions(); - Object.keys(exts) - .filter((ext) => Object.hasOwnProperty.call(exts, ext)) - .forEach((ext) => { - headers[this.extensionPrefix + ext] = exts[ext]; - }); - - config[Constants.DATA_ATTRIBUTE] = data; - config.headers = headers; - - // Return the Promise - return axios.request(config); -}; - -module.exports = BinaryHTTPEmitter; diff --git a/lib/bindings/http/emitter_binary_0_3.js b/lib/bindings/http/emitter_binary_0_3.js deleted file mode 100644 index 5aa6c022..00000000 --- a/lib/bindings/http/emitter_binary_0_3.js +++ /dev/null @@ -1,64 +0,0 @@ -const BinaryHTTPEmitter = require("./emitter_binary.js"); - -const Constants = require("./constants.js"); - -const headerByGetter = {}; - -headerByGetter.getDataContentType = { - name: Constants.HEADER_CONTENT_TYPE, - parser: (v) => v -}; - -headerByGetter.getDataContentEncoding = { - name: Constants.BINARY_HEADERS_03.CONTENT_ENCONDING, - parser: (v) => v -}; - -headerByGetter.getSubject = { - name: Constants.BINARY_HEADERS_03.SUBJECT, - parser: (v) => v -}; - -headerByGetter.getType = { - name: Constants.BINARY_HEADERS_03.TYPE, - parser: (v) => v -}; - -headerByGetter.getSpecversion = { - name: Constants.BINARY_HEADERS_03.SPEC_VERSION, - parser: (v) => v -}; - -headerByGetter.getSource = { - name: Constants.BINARY_HEADERS_03.SOURCE, - parser: (v) => v -}; - -headerByGetter.getId = { - name: Constants.BINARY_HEADERS_03.ID, - parser: (v) => v -}; - -headerByGetter.getTime = { - name: Constants.BINARY_HEADERS_03.TIME, - parser: (v) => v -}; - -headerByGetter.getSchemaurl = { - name: Constants.BINARY_HEADERS_03.SCHEMA_URL, - parser: (v) => v -}; - -function HTTPBinary(configuration) { - this.emitter = new BinaryHTTPEmitter( - configuration, - headerByGetter, - Constants.BINARY_HEADERS_03.EXTENSIONS_PREFIX - ); -} - -HTTPBinary.prototype.emit = function(cloudevent) { - return this.emitter.emit(cloudevent); -}; - -module.exports = HTTPBinary; diff --git a/lib/bindings/http/emitter_binary_1.js b/lib/bindings/http/emitter_binary_1.js deleted file mode 100644 index 402b85ea..00000000 --- a/lib/bindings/http/emitter_binary_1.js +++ /dev/null @@ -1,59 +0,0 @@ -const BinaryHTTPEmitter = require("./emitter_binary.js"); - -const Constants = require("./constants.js"); - -const headerByGetter = {}; - -headerByGetter.getDataContentType = { - name: Constants.HEADER_CONTENT_TYPE, - parser: (v) => v -}; - -headerByGetter.getSubject = { - name: Constants.BINARY_HEADERS_1.SUBJECT, - parser: (v) => v -}; - -headerByGetter.getType = { - name: Constants.BINARY_HEADERS_1.TYPE, - parser: (v) => v -}; - -headerByGetter.getSpecversion = { - name: Constants.BINARY_HEADERS_1.SPEC_VERSION, - parser: (v) => v -}; - -headerByGetter.getSource = { - name: Constants.BINARY_HEADERS_1.SOURCE, - parser: (v) => v -}; - -headerByGetter.getId = { - name: Constants.BINARY_HEADERS_1.ID, - parser: (v) => v -}; - -headerByGetter.getTime = { - name: Constants.BINARY_HEADERS_1.TIME, - parser: (v) => v -}; - -headerByGetter.getDataschema = { - name: Constants.BINARY_HEADERS_1.DATA_SCHEMA, - parser: (v) => v -}; - -function HTTPBinary(configuration) { - this.emitter = new BinaryHTTPEmitter( - configuration, - headerByGetter, - Constants.BINARY_HEADERS_1.EXTENSIONS_PREFIX - ); -} - -HTTPBinary.prototype.emit = function(cloudevent) { - return this.emitter.emit(cloudevent); -}; - -module.exports = HTTPBinary; diff --git a/lib/bindings/http/emitter_structured.js b/lib/bindings/http/emitter_structured.js deleted file mode 100644 index 21b83479..00000000 --- a/lib/bindings/http/emitter_structured.js +++ /dev/null @@ -1,24 +0,0 @@ -const axios = require("axios"); - -const Constants = require("./constants.js"); -const defaults = {}; -defaults[Constants.HEADERS] = {}; -defaults[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] = - Constants.DEFAULT_CE_CONTENT_TYPE; - -function StructuredHTTPEmitter(configuration) { - this.config = Object.assign({}, defaults, configuration); -} - -StructuredHTTPEmitter.prototype.emit = function(cloudevent) { - // Set the cloudevent payload - this.config[Constants.DATA_ATTRIBUTE] = cloudevent.format(); - - // Return the Promise - return axios.request(this.config).then((response) => { - delete this.config[Constants.DATA_ATTRIBUTE]; - return response; - }); -}; - -module.exports = StructuredHTTPEmitter; diff --git a/lib/bindings/http/http_receiver.js b/lib/bindings/http/http_receiver.js deleted file mode 100644 index 09128642..00000000 --- a/lib/bindings/http/http_receiver.js +++ /dev/null @@ -1,61 +0,0 @@ -const V03Binary = require("./receiver_binary_0_3"); -const V03Structured = require("./receiver_structured_0_3.js"); -const V1Binary = require("./receiver_binary_1.js"); -const V1Structured = require("./receiver_structured_1.js"); -const constants = require("./constants"); - -class HTTPReceiver { - constructor() { - this.receivers = { - v1: { - structured: new V1Structured(), - binary: new V1Binary() - }, - v03: { - structured: new V03Structured(), - binary: new V03Binary() - } - }; - } - - accept(headers, body) { - const mode = getMode(headers); - const version = getVersion(mode, headers, body); - switch (version) { - case constants.SPEC_V1: - return this.receivers.v1[mode].parse(body, headers); - case constants.SPEC_V03: - return this.receivers.v03[mode].parse(body, headers); - default: - console.error( - `Unknown spec version ${version}. Default to ${constants.SPEC_V1}`); - return this.receivers.v1[mode].parse(body, headers); - } - } -} - -function getMode(headers) { - let mode = "binary"; - const contentType = headers[constants.HEADER_CONTENT_TYPE]; - if (contentType && contentType.startsWith(constants.MIME_CE)) { - mode = "structured"; - } - return mode; -} - -function getVersion(mode, headers, body) { - let version = constants.SPEC_V1; // default to 1.0 - - if (mode === "binary") { - // Check the headers for the version - const versionHeader = headers[constants.DEFAULT_SPEC_VERSION_HEADER]; - if (versionHeader) { version = versionHeader; } - } else { - // structured mode - the version is in the body - version = body instanceof String - ? JSON.parse(body).specversion : body.specversion; - } - return version; -} - -module.exports = HTTPReceiver; diff --git a/lib/bindings/http/receiver_binary.js b/lib/bindings/http/receiver_binary.js deleted file mode 100644 index 71a0c80c..00000000 --- a/lib/bindings/http/receiver_binary.js +++ /dev/null @@ -1,139 +0,0 @@ -const Constants = require("./constants.js"); -const Commons = require("./commons.js"); -const CloudEvent = require("../../cloudevent.js"); - -const { - isDefinedOrThrow, - isStringOrObjectOrThrow -} = require("../../utils/fun.js"); - -function validateArgs(payload, attributes) { - Array.of(payload) - .filter((p) => isDefinedOrThrow(p, - { message: "payload is null or undefined" })) - .filter((p) => isStringOrObjectOrThrow(p, - { message: "payload must be an object or a string" })) - .shift(); - - Array.of(attributes) - .filter((a) => isDefinedOrThrow(a, - { message: "attributes is null or undefined" })) - .shift(); -} - -function BinaryHTTPReceiver( - parsersByEncoding, - setterByHeader, - allowedContentTypes, - requiredHeaders, - Spec, - specversion, - extensionsPrefix, - checkDecorator) { - this.parsersByEncoding = parsersByEncoding; - this.setterByHeader = setterByHeader; - this.allowedContentTypes = allowedContentTypes; - this.requiredHeaders = requiredHeaders; - this.Spec = Spec; - this.spec = new Spec(); - this.specversion = specversion; - this.extensionsPrefix = extensionsPrefix; - this.checkDecorator = checkDecorator; -} - -BinaryHTTPReceiver.prototype.check = function(payload, headers) { - // Validation Level 0 - validateArgs(payload, headers); - - if (this.checkDecorator) { - this.checkDecorator(payload, headers); - } - - // Clone and low case all headers names - const sanityHeaders = Commons.sanityAndClone(headers); - - // If no content type is provided, default to application/json - if (!sanityHeaders[Constants.HEADER_CONTENT_TYPE]) { - sanityHeaders[Constants.HEADER_CONTENT_TYPE] = Constants.MIME_JSON; - } - - // Validation Level 1 - if (!this.allowedContentTypes - .includes(sanityHeaders[Constants.HEADER_CONTENT_TYPE])) { - const err = new TypeError("invalid content type"); - err.errors = [sanityHeaders[Constants.HEADER_CONTENT_TYPE]]; - throw err; - } - - this.requiredHeaders - .filter((required) => !sanityHeaders[required]) - .forEach((required) => { - throw new TypeError(`header '${required}' not found`); - }); - - if (sanityHeaders[Constants.DEFAULT_SPEC_VERSION_HEADER] !== - this.specversion) { - const err = new TypeError("invalid spec version"); - err.errors = [sanityHeaders[Constants.DEFAULT_SPEC_VERSION_HEADER]]; - throw err; - } - - // No erros! Its contains the minimum required attributes -}; - -function parserFor(parsersByEncoding, cloudevent, headers) { - const encoding = cloudevent.spec.payload.datacontentencoding; - return parsersByEncoding[encoding][headers[Constants.HEADER_CONTENT_TYPE]]; -} - -BinaryHTTPReceiver.prototype.parse = function(payload, headers) { - this.check(payload, headers); - - // Clone and low case all headers names - const sanityHeaders = Commons.sanityAndClone(headers); - - const processedHeaders = []; - const cloudevent = new CloudEvent(this.Spec); - - // dont worry, check() have seen what was required or not - Array.from(Object.keys(this.setterByHeader)) - .filter((header) => sanityHeaders[header]) - .forEach((header) => { - const setterName = this.setterByHeader[header].name; - const parserFun = this.setterByHeader[header].parser; - - // invoke the setter function - cloudevent[setterName](parserFun(sanityHeaders[header])); - - // to use ahead, for extensions processing - processedHeaders.push(header); - }); - - // Parses the payload - const parsedPayload = - parserFor(this.parsersByEncoding, cloudevent, sanityHeaders) - .parse(payload); - - // Every unprocessed header can be an extension - Array.from(Object.keys(sanityHeaders)) - .filter((value) => !processedHeaders.includes(value)) - .filter((value) => - value.startsWith(this.extensionsPrefix)) - .map((extension) => - extension.substring(this.extensionsPrefix.length) - ).forEach((extension) => - cloudevent.addExtension(extension, - sanityHeaders[this.extensionsPrefix + extension]) - ); - - // Sets the data - cloudevent.data(parsedPayload); - - // Checks the event spec - cloudevent.format(); - - // return the result - return cloudevent; -}; - -module.exports = BinaryHTTPReceiver; diff --git a/lib/bindings/http/receiver_binary_0_3.js b/lib/bindings/http/receiver_binary_0_3.js deleted file mode 100644 index 3f763298..00000000 --- a/lib/bindings/http/receiver_binary_0_3.js +++ /dev/null @@ -1,120 +0,0 @@ -const Constants = require("./constants.js"); -const Spec = require("../../specs/spec_0_3.js"); - -const JSONParser = require("../../formats/json/parser.js"); -const Base64Parser = require("../../formats/base64.js"); - -const BinaryHTTPReceiver = require("./receiver_binary.js"); - -const parserByType = {}; -parserByType[Constants.MIME_JSON] = new JSONParser(); -parserByType[Constants.MIME_OCTET_STREAM] = { - parse(payload) { return payload; } -}; - -const parsersByEncoding = {}; -parsersByEncoding.null = parserByType; -parsersByEncoding[undefined] = parserByType; - -// base64 -parsersByEncoding[Constants.ENCODING_BASE64] = {}; -parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_JSON] = - new JSONParser(new Base64Parser()); -parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_OCTET_STREAM] = { - parse(payload) { return payload; } -}; - -const allowedContentTypes = []; -allowedContentTypes.push(Constants.MIME_JSON); -allowedContentTypes.push(Constants.MIME_OCTET_STREAM); - -const allowedEncodings = []; -allowedEncodings.push(Constants.ENCODING_BASE64); - -const requiredHeaders = []; -requiredHeaders.push(Constants.BINARY_HEADERS_03.TYPE); -requiredHeaders.push(Constants.BINARY_HEADERS_03.SPEC_VERSION); -requiredHeaders.push(Constants.BINARY_HEADERS_03.SOURCE); -requiredHeaders.push(Constants.BINARY_HEADERS_03.ID); - -const setterByHeader = {}; -setterByHeader[Constants.BINARY_HEADERS_03.TYPE] = { - name: "type", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_03.SPEC_VERSION] = { - name: "specversion", - parser: () => "0.3" -}; -setterByHeader[Constants.BINARY_HEADERS_03.SOURCE] = { - name: "source", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_03.ID] = { - name: "id", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_03.TIME] = { - name: "time", - parser: (v) => new Date(Date.parse(v)) -}; -setterByHeader[Constants.BINARY_HEADERS_03.SCHEMA_URL] = { - name: "schemaurl", - parser: (v) => v -}; -setterByHeader[Constants.HEADER_CONTENT_TYPE] = { - name: "dataContentType", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_03.CONTENT_ENCONDING] = { - name: "dataContentEncoding", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_03.SUBJECT] = { - name: "subject", - parser: (v) => v -}; - -// Leaving this in place for now. TODO: fixme -// eslint-disable-next-line -function checkDecorator(payload, headers) { - Object.keys(headers) - .map((header) => header.toLocaleLowerCase("en-US")) - .filter((header) => - header === Constants.BINARY_HEADERS_03.CONTENT_ENCONDING) - .filter((header) => !allowedEncodings.includes(headers[header])) - .forEach((header) => { - // TODO: using forEach here seems off - const err = new TypeError("unsupported datacontentencoding"); - err.errors = [headers[header]]; - throw err; - }); -} - -// Leaving this in place for now. TODO: fixme -// eslint-disable-next-line -function Receiver(configuration) { - this.receiver = new BinaryHTTPReceiver( - parsersByEncoding, - setterByHeader, - allowedContentTypes, - requiredHeaders, - Spec, - Constants.SPEC_V03, - Constants.BINARY_HEADERS_03.EXTENSIONS_PREFIX, - checkDecorator - ); -} - -Receiver.prototype.check = function(payload, headers) { - this.receiver.check(payload, headers); -}; - -Receiver.prototype.parse = function(payload, headers) { - // firstly specific local checks - this.check(payload, headers); - - return this.receiver.parse(payload, headers); -}; - -module.exports = Receiver; diff --git a/lib/bindings/http/receiver_binary_1.js b/lib/bindings/http/receiver_binary_1.js deleted file mode 100644 index 6cbc8d59..00000000 --- a/lib/bindings/http/receiver_binary_1.js +++ /dev/null @@ -1,114 +0,0 @@ -const Constants = require("./constants.js"); -const Spec = require("../../specs/spec_1.js"); - -const JSONParser = require("../../formats/json/parser.js"); -const Base64Parser = require("../../formats/base64.js"); - -const BinaryHTTPReceiver = require("./receiver_binary.js"); - -const { - isString, - isBase64 -} = require("../../utils/fun.js"); - -const parserByType = {}; -parserByType[Constants.MIME_JSON] = new JSONParser(); -parserByType[Constants.MIME_OCTET_STREAM] = { - parse(payload) { return payload; } -}; - -const parsersByEncoding = {}; -parsersByEncoding.null = parserByType; -parsersByEncoding[undefined] = parserByType; - -// base64 -parsersByEncoding[Constants.ENCODING_BASE64] = {}; -parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_JSON] = - new JSONParser(new Base64Parser()); -parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_OCTET_STREAM] = { - parse(payload) { return payload; } -}; - -const allowedContentTypes = []; -allowedContentTypes.push(Constants.MIME_JSON); -allowedContentTypes.push(Constants.MIME_OCTET_STREAM); - -const allowedEncodings = []; -allowedEncodings.push(Constants.ENCODING_BASE64); - -const requiredHeaders = []; -requiredHeaders.push(Constants.BINARY_HEADERS_1.TYPE); -requiredHeaders.push(Constants.BINARY_HEADERS_1.SPEC_VERSION); -requiredHeaders.push(Constants.BINARY_HEADERS_1.SOURCE); -requiredHeaders.push(Constants.BINARY_HEADERS_1.ID); - -const setterByHeader = {}; -setterByHeader[Constants.BINARY_HEADERS_1.TYPE] = { - name: "type", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_1.SPEC_VERSION] = { - name: "specversion", - parser: () => "1.0" -}; -setterByHeader[Constants.BINARY_HEADERS_1.SOURCE] = { - name: "source", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_1.ID] = { - name: "id", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_1.TIME] = { - name: "time", - parser: (v) => new Date(Date.parse(v)) -}; -setterByHeader[Constants.BINARY_HEADERS_1.DATA_SCHEMA] = { - name: "dataschema", - parser: (v) => v -}; -setterByHeader[Constants.HEADER_CONTENT_TYPE] = { - name: "dataContentType", - parser: (v) => v -}; -setterByHeader[Constants.BINARY_HEADERS_1.SUBJECT] = { - name: "subject", - parser: (v) => v -}; - -// Leaving these in place for now. TODO: fixme -// eslint-disable-next-line -function checkDecorator(payload, headers) { -} - -// Leaving this in place for now. TODO: fixme -// eslint-disable-next-line -function Receiver(configuration) { - this.receiver = new BinaryHTTPReceiver( - parsersByEncoding, - setterByHeader, - allowedContentTypes, - requiredHeaders, - Spec, - Constants.SPEC_V1, - Constants.BINARY_HEADERS_1.EXTENSIONS_PREFIX, - checkDecorator - ); -} - -Receiver.prototype.check = function(payload, headers) { - this.receiver.check(payload, headers); -}; - -Receiver.prototype.parse = function(payload, headers) { - // firstly specific local checks - this.check(payload, headers); - - payload = isString(payload) && isBase64(payload) - ? Buffer.from(payload, "base64").toString() - : payload; - - return this.receiver.parse(payload, headers); -}; - -module.exports = Receiver; diff --git a/lib/bindings/http/receiver_structured.js b/lib/bindings/http/receiver_structured.js deleted file mode 100644 index f470e5e1..00000000 --- a/lib/bindings/http/receiver_structured.js +++ /dev/null @@ -1,89 +0,0 @@ -const Constants = require("./constants.js"); -const Commons = require("./commons.js"); -const CloudEvent = require("../../cloudevent.js"); - -const { - isDefinedOrThrow, - isStringOrObjectOrThrow -} = require("../../utils/fun.js"); - -function validateArgs(payload, attributes) { - Array.of(payload) - .filter((p) => isDefinedOrThrow(p, - { message: "payload is null or undefined" })) - .filter((p) => isStringOrObjectOrThrow(p, - { message: "payload must be an object or string" })) - .shift(); - - Array.of(attributes) - .filter((a) => isDefinedOrThrow(a, - { message: "attributes is null or undefined" })) - .shift(); -} - -function StructuredHTTPReceiver( - parserByMime, - setterByAttribute, - allowedContentTypes, - Spec) { - this.parserByMime = parserByMime; - this.setterByAttribute = setterByAttribute; - this.allowedContentTypes = allowedContentTypes; - this.Spec = Spec; - this.spec = new Spec(); -} - -StructuredHTTPReceiver.prototype.check = function(payload, headers) { - validateArgs(payload, headers); - - const sanityHeaders = Commons.sanityAndClone(headers); - - // Validation Level 1 - if (!this.allowedContentTypes - .includes(sanityHeaders[Constants.HEADER_CONTENT_TYPE])) { - const err = new TypeError("invalid content type"); - err.errors = [sanityHeaders[Constants.HEADER_CONTENT_TYPE]]; - throw err; - } - - // No erros! Its contains the minimum required attributes -}; - -StructuredHTTPReceiver.prototype.parse = function(payload, headers) { - this.check(payload, headers); - - const sanityHeaders = Commons.sanityAndClone(headers); - - const contentType = sanityHeaders[Constants.HEADER_CONTENT_TYPE]; - - const parser = this.parserByMime[contentType]; - const event = parser.parse(payload); - this.spec.check(event); - - const processedAttributes = []; - const cloudevent = new CloudEvent(this.Spec); - - Array.from(Object.keys(this.setterByAttribute)) - .filter((attribute) => event[attribute]) - .forEach((attribute) => { - const setterName = this.setterByAttribute[attribute].name; - const parserFun = this.setterByAttribute[attribute].parser; - - // invoke the setter function - cloudevent[setterName](parserFun(event[attribute])); - - // to use ahead, for extensions processing - processedAttributes.push(attribute); - }); - - // Every unprocessed attribute should be an extension - Array.from(Object.keys(event)) - .filter((attribute) => !processedAttributes.includes(attribute)) - .forEach((extension) => - cloudevent.addExtension(extension, event[extension]) - ); - - return cloudevent; -}; - -module.exports = StructuredHTTPReceiver; diff --git a/lib/bindings/http/receiver_structured_0_3.js b/lib/bindings/http/receiver_structured_0_3.js deleted file mode 100644 index 35cbfc40..00000000 --- a/lib/bindings/http/receiver_structured_0_3.js +++ /dev/null @@ -1,77 +0,0 @@ -const Constants = require("./constants.js"); -const Spec = require("../../specs/spec_0_3.js"); -const JSONParser = require("../../formats/json/parser.js"); - -const StructuredHTTPReceiver = require("./receiver_structured.js"); - -const jsonParserSpec = new JSONParser(); - -const parserByMime = {}; -parserByMime[Constants.MIME_JSON] = jsonParserSpec; -parserByMime[Constants.MIME_CE_JSON] = jsonParserSpec; - -const allowedContentTypes = []; -allowedContentTypes.push(Constants.MIME_CE_JSON); - -const setterByAttribute = {}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.TYPE] = { - name: "type", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.SPEC_VERSION] = { - name: "specversion", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.SOURCE] = { - name: "source", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.ID] = { - name: "id", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.TIME] = { - name: "time", - parser: (v) => new Date(Date.parse(v)) -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.SCHEMA_URL] = { - name: "schemaurl", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.CONTENT_ENCONDING] = { - name: "dataContentEncoding", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.CONTENT_TYPE] = { - name: "dataContentType", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.SUBJECT] = { - name: "subject", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_03.DATA] = { - name: "data", - parser: (v) => v -}; - -// Leaving this in place for now. TODO: fixme -// eslint-disable-next-line -function Receiver(configuration) { - this.receiver = new StructuredHTTPReceiver( - parserByMime, - setterByAttribute, - allowedContentTypes, - Spec - ); -} - -Receiver.prototype.check = function(payload, headers) { - this.receiver.check(payload, headers); -}; - -Receiver.prototype.parse = function(payload, headers) { - return this.receiver.parse(payload, headers); -}; - -module.exports = Receiver; diff --git a/lib/bindings/http/receiver_structured_1.js b/lib/bindings/http/receiver_structured_1.js deleted file mode 100644 index dbab767a..00000000 --- a/lib/bindings/http/receiver_structured_1.js +++ /dev/null @@ -1,77 +0,0 @@ -const Constants = require("./constants.js"); -const Spec = require("../../specs/spec_1.js"); -const JSONParser = require("../../formats/json/parser.js"); - -const StructuredHTTPReceiver = require("./receiver_structured.js"); - -const jsonParserSpec = new JSONParser(); - -const parserByMime = {}; -parserByMime[Constants.MIME_JSON] = jsonParserSpec; -parserByMime[Constants.MIME_CE_JSON] = jsonParserSpec; - -const allowedContentTypes = []; -allowedContentTypes.push(Constants.MIME_CE_JSON); - -const setterByAttribute = {}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.TYPE] = { - name: "type", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.SPEC_VERSION] = { - name: "specversion", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.SOURCE] = { - name: "source", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.ID] = { - name: "id", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.TIME] = { - name: "time", - parser: (v) => new Date(Date.parse(v)) -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.DATA_SCHEMA] = { - name: "dataschema", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.CONTENT_TYPE] = { - name: "dataContentType", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.SUBJECT] = { - name: "subject", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.DATA] = { - name: "data", - parser: (v) => v -}; -setterByAttribute[Constants.STRUCTURED_ATTRS_1.DATA_BASE64] = { - name: "data", - parser: (v) => v -}; - -// Leaving this in place for now. TODO: fixme -// eslint-disable-next-line -function Receiver(configuration) { - this.receiver = new StructuredHTTPReceiver( - parserByMime, - setterByAttribute, - allowedContentTypes, - Spec - ); -} - -Receiver.prototype.check = function(payload, headers) { - this.receiver.check(payload, headers); -}; - -Receiver.prototype.parse = function(payload, headers) { - return this.receiver.parse(payload, headers); -}; - -module.exports = Receiver; diff --git a/lib/bindings/http/unmarshaller.js b/lib/bindings/http/unmarshaller.js deleted file mode 100644 index 99688c39..00000000 --- a/lib/bindings/http/unmarshaller.js +++ /dev/null @@ -1,70 +0,0 @@ -const Constants = require("./constants.js"); -const Commons = require("./commons.js"); - -const STRUCTURED = "structured"; -const BINARY = "binary"; - -const allowedBinaryContentTypes = [ - Constants.MIME_JSON, - Constants.MIME_OCTET_STREAM -]; - -const allowedStructuredContentTypes = [ - Constants.MIME_CE_JSON -]; - -// Is it binary or structured? -function resolveBindingName(payload, headers) { - const contentType = - Commons.sanityContentType(headers[Constants.HEADER_CONTENT_TYPE]); - - if (contentType.startsWith(Constants.MIME_CE)) { - // Structured - if (allowedStructuredContentTypes.includes(contentType)) { - return STRUCTURED; - } else { - const err = new TypeError("structured+type not allowed"); - err.errors = [contentType]; - throw err; - } - } else { - // Binary - if (allowedBinaryContentTypes.includes(contentType)) { - return BINARY; - } else { - const err = new TypeError("content type not allowed"); - err.errors = [contentType]; - throw err; - } - } -} - -class Unmarshaller { - constructor(receiverByBinding) { - this.receiverByBinding = receiverByBinding; - } - - unmarshall(payload, headers) { - if (!payload) { - throw new TypeError("payload is null or undefined"); - } - if (!headers) { - throw new TypeError("headers is null or undefined"); - } - - // Validation level 1 - const sanityHeaders = Commons.sanityAndClone(headers); - if (!sanityHeaders[Constants.HEADER_CONTENT_TYPE]) { - throw new TypeError("content-type header not found"); - } - - // Resolve the binding - const bindingName = resolveBindingName(payload, sanityHeaders); - const cloudevent = this.receiverByBinding[bindingName] - .parse(payload, sanityHeaders); - - return cloudevent; - } -} - -module.exports = Unmarshaller; diff --git a/lib/bindings/http/unmarshaller_0_3.js b/lib/bindings/http/unmarshaller_0_3.js deleted file mode 100644 index a6bf300c..00000000 --- a/lib/bindings/http/unmarshaller_0_3.js +++ /dev/null @@ -1,19 +0,0 @@ -const GenericUnmarshaller = require("./unmarshaller.js"); - -const StructuredReceiver = require("./receiver_structured_0_3.js"); -const BinaryReceiver = require("./receiver_binary_0_3.js"); - -const RECEIVER_BY_BINDING = { - structured: new StructuredReceiver(), - binary: new BinaryReceiver() -}; - -const Unmarshaller = function() { - this.unmarshaller = new GenericUnmarshaller(RECEIVER_BY_BINDING); -}; - -Unmarshaller.prototype.unmarshall = function(payload, headers) { - return this.unmarshaller.unmarshall(payload, headers); -}; - -module.exports = Unmarshaller; diff --git a/lib/cloudevent.js b/lib/cloudevent.js deleted file mode 100644 index def107f7..00000000 --- a/lib/cloudevent.js +++ /dev/null @@ -1,122 +0,0 @@ -const Spec = require("./specs/spec_1.js"); -const Formatter = require("./formats/json/formatter.js"); - -/* - * Class created using the Builder Design Pattern. - * - * https://en.wikipedia.org/wiki/Builder_pattern - */ -class CloudEvent { - constructor(_spec, _formatter) { - this.spec = (_spec) ? new _spec(CloudEvent) : new Spec(CloudEvent); - this.formatter = (_formatter) ? new _formatter() : new Formatter(); - - // The map of extensions - this.extensions = {}; - } - - getFormats() { - return { json: Formatter }; - } - - format() { - // Check the constraints - this.spec.check(); - - // To run asData() - this.getData(); - - // Then, format - return this.formatter.format(this.spec.payload); - } - - toString() { - return this.formatter.toString(this.spec.payload); - } - - type(type) { - this.spec.type(type); - return this; - } - - getType() { - return this.spec.getType(); - } - - specversion(version) { - return this.spec.specversion(version); - } - - getSpecversion() { - return this.spec.getSpecversion(); - } - - source(_source) { - this.spec.source(_source); - return this; - } - - getSource() { - return this.spec.getSource(); - } - - id(_id) { - this.spec.id(_id); - return this; - } - - getId() { - return this.spec.getId(); - } - - time(_time) { - this.spec.time(_time); - return this; - } - - getTime() { - return this.spec.getTime(); - } - - schemaurl(_schemaurl) { - this.spec.schemaurl(_schemaurl); - return this; - } - - getSchemaurl() { - return this.spec.getSchemaurl(); - } - - dataContenttype(_contenttype) { - this.spec.dataContenttype(_contenttype); - return this; - } - - getDataContenttype() { - return this.spec.getDataContenttype(); - } - - data(_data) { - this.spec.data(_data); - return this; - } - - getData() { - return this.spec.getData(); - } - - addExtension(key, value) { - this.spec.addExtension(key, value); - - // Stores locally - this.extensions[key] = value; - - return this; - } - - getExtensions() { - return this.extensions; - } -} - -module.exports = CloudEvent; diff --git a/lib/formats/base64.js b/lib/formats/base64.js deleted file mode 100644 index cd73def6..00000000 --- a/lib/formats/base64.js +++ /dev/null @@ -1,16 +0,0 @@ -class Base64Parser { - constructor(decorator) { - this.decorator = decorator; - } - - parse(payload) { - let payloadToParse = payload; - if (this.decorator) { - payloadToParse = this.decorator.parse(payload); - } - - return Buffer.from(payloadToParse, "base64").toString(); - } -} - -module.exports = Base64Parser; diff --git a/lib/formats/json/formatter.js b/lib/formats/json/formatter.js deleted file mode 100644 index d4bc3d4f..00000000 --- a/lib/formats/json/formatter.js +++ /dev/null @@ -1,15 +0,0 @@ -class JSONFormatter { - /* - * Every internal data structure is JSON by nature, so - * no transformation is required - */ - format(payload) { - return payload; - } - - toString(payload) { - return JSON.stringify(payload); - } -} - -module.exports = JSONFormatter; diff --git a/lib/formats/json/parser.js b/lib/formats/json/parser.js deleted file mode 100644 index 0d833571..00000000 --- a/lib/formats/json/parser.js +++ /dev/null @@ -1,38 +0,0 @@ -const { - isString, - isDefinedOrThrow, - isStringOrObjectOrThrow -} = require("../../utils/fun.js"); - -const invalidPayloadTypeError = - new Error("invalid payload type, allowed are: string or object"); -const nullOrUndefinedPayload = - new Error("null or undefined payload"); - -const asJSON = (v) => (isString(v) ? JSON.parse(v) : v); - -class JSONParser { - constructor(decorator) { - this.decorator = decorator; - } - - /** - * Parses the payload with an optional decorator - * @param {object|string} payload the JSON payload - * @return {object} the parsed JSON payload. - */ - parse(payload) { - if (this.decorator) { - payload = this.decorator.parse(payload); - } - - return Array.of(payload) - - .filter((p) => isDefinedOrThrow(p, nullOrUndefinedPayload)) - .filter((p) => isStringOrObjectOrThrow(p, invalidPayloadTypeError)) - .map(asJSON) - .shift(); - } -} - -module.exports = JSONParser; diff --git a/lib/specs/spec_0_3.js b/lib/specs/spec_0_3.js deleted file mode 100644 index f07e0fb1..00000000 --- a/lib/specs/spec_0_3.js +++ /dev/null @@ -1,312 +0,0 @@ -const { v4: uuidv4 } = require("uuid"); -const Ajv = require("ajv"); - -const { - isBase64, - clone, - asData -} = require("../utils/fun.js"); - -const RESERVED_ATTRIBUTES = { - type: "type", - specversion: "specversion", - source: "source", - id: "id", - time: "time", - schemaurl: "schemaurl", - datacontentencoding: "datacontentencoding", - datacontenttype: "datacontenttype", - subject: "subject", - data: "data" -}; - -const SUPPORTED_CONTENT_ENCODING = {}; -SUPPORTED_CONTENT_ENCODING.base64 = { - check: (data) => isBase64(data) -}; - -const schema = { - $ref: "#/definitions/event", - definitions: { - specversion: { - const: "0.3" - }, - datacontenttype: { - type: "string" - }, - data: { - type: [ - "object", - "string" - ] - }, - event: { - properties: { - specversion: { - $ref: "#/definitions/specversion" - }, - datacontenttype: { - $ref: "#/definitions/datacontenttype" - }, - data: { - $ref: "#/definitions/data" - }, - id: { - $ref: "#/definitions/id" - }, - time: { - $ref: "#/definitions/time" - }, - schemaurl: { - $ref: "#/definitions/schemaurl" - }, - subject: { - $ref: "#/definitions/subject" - }, - type: { - $ref: "#/definitions/type" - }, - extensions: { - $ref: "#/definitions/extensions" - }, - source: { - $ref: "#/definitions/source" - } - }, - required: [ - "specversion", - "id", - "type", - "source" - ], - type: "object" - }, - id: { - type: "string", - minLength: 1 - }, - time: { - format: "date-time", - type: "string" - }, - schemaurl: { - type: "string", - format: "uri-reference" - }, - subject: { - type: "string", - minLength: 1 - }, - type: { - type: "string", - minLength: 1 - }, - extensions: { - type: "object" - }, - source: { - format: "uri-reference", - type: "string" - } - }, - type: "object" -}; - -const ajv = new Ajv({ - extendRefs: true -}); - -const isValidAgainstSchema = ajv.compile(schema); - -function Spec03(_caller) { - this.payload = { - specversion: schema.definitions.specversion.const, - id: uuidv4() - }; - - if (!_caller) { - _caller = require("../cloudevent.js"); - } - - /* - * Used to inject compatibility methods or attributes - */ - this.caller = _caller; - - /* - * Inject compatibility methods - */ - this.caller.prototype.dataContentEncoding = function(encoding) { - this.spec.dataContentEncoding(encoding); - return this; - }; - this.caller.prototype.getDataContentEncoding = function() { - return this.spec.getDataContentEncoding(); - }; - - this.caller.prototype.dataContentType = function(contentType) { - this.spec.dataContentType(contentType); - return this; - }; - this.caller.prototype.getDataContentType = function() { - return this.spec.getDataContentType(); - }; - - this.caller.prototype.subject = function(_subject) { - this.spec.subject(_subject); - return this; - }; - this.caller.prototype.getSubject = function() { - return this.spec.getSubject(); - }; -} - -/* - * Check the spec constraints - */ -Spec03.prototype.check = function(ce) { - const toCheck = (!ce ? this.payload : ce); - - if (!isValidAgainstSchema(toCheck)) { - const err = new TypeError("invalid payload"); - err.errors = isValidAgainstSchema.errors; - throw err; - } - - Array.of(toCheck) - .filter((tc) => tc.datacontentencoding) - .map((tc) => tc.datacontentencoding.toLocaleLowerCase("en-US")) - .filter((dce) => !Object.keys(SUPPORTED_CONTENT_ENCODING).includes(dce)) - .forEach((dce) => { - const err = new TypeError("invalid payload"); - err.errors = [ - `Unsupported content encoding: ${dce}` - ]; - throw err; - }); - - Array.of(toCheck) - .filter((tc) => tc.datacontentencoding) - .filter((tc) => (typeof tc.data) === "string") - .map((tc) => { - const newtc = clone(tc); - newtc.datacontentencoding = - newtc.datacontentencoding.toLocaleLowerCase("en-US"); - - return newtc; - }) - .filter((tc) => Object.keys(SUPPORTED_CONTENT_ENCODING) - .includes(tc.datacontentencoding)) - .filter((tc) => !SUPPORTED_CONTENT_ENCODING[tc.datacontentencoding] - .check(tc.data)) - .forEach((tc) => { - const err = new TypeError("invalid payload"); - err.errors = [ - `Invalid content encoding of data: ${tc.data}` - ]; - throw err; - }); -}; - -Spec03.prototype.id = function(_id) { - this.payload.id = _id; - return this; -}; - -Spec03.prototype.getId = function() { - return this.payload.id; -}; - -Spec03.prototype.source = function(_source) { - this.payload.source = _source; - return this; -}; - -Spec03.prototype.getSource = function() { - return this.payload.source; -}; - -Spec03.prototype.specversion = function() { - // does not set! This is right - return this; -}; - -Spec03.prototype.getSpecversion = function() { - return this.payload.specversion; -}; - -Spec03.prototype.type = function(_type) { - this.payload.type = _type; - return this; -}; - -Spec03.prototype.getType = function() { - return this.payload.type; -}; - -Spec03.prototype.dataContentEncoding = function(encoding) { - this.payload.datacontentencoding = encoding; - return this; -}; - -Spec03.prototype.getDataContentEncoding = function() { - return this.payload.datacontentencoding; -}; - -Spec03.prototype.dataContentType = function(_contenttype) { - this.payload.datacontenttype = _contenttype; - return this; -}; -Spec03.prototype.getDataContentType = function() { - return this.payload.datacontenttype; -}; - -Spec03.prototype.schemaurl = function(_schemaurl) { - this.payload.schemaurl = _schemaurl; - return this; -}; -Spec03.prototype.getSchemaurl = function() { - return this.payload.schemaurl; -}; - -Spec03.prototype.subject = function(_subject) { - this.payload.subject = _subject; - return this; -}; -Spec03.prototype.getSubject = function() { - return this.payload.subject; -}; - -Spec03.prototype.time = function(_time) { - this.payload.time = _time.toISOString(); - return this; -}; -Spec03.prototype.getTime = function() { - return this.payload.time; -}; - -Spec03.prototype.data = function(_data) { - this.payload.data = _data; - return this; -}; -Spec03.prototype.getData = function() { - const dct = this.payload.datacontenttype; - const dce = this.payload.datacontentencoding; - - if (dct && !dce) { - this.payload.data = asData(this.payload.data, dct); - } - - return this.payload.data; -}; - -Spec03.prototype.addExtension = function(key, value) { - if (!Object.prototype.hasOwnProperty.call(RESERVED_ATTRIBUTES, key)) { - this.payload[key] = value; - } else { - throw new TypeError(`Reserved attribute name: '${key}'`); - } - return this; -}; - -module.exports = Spec03; diff --git a/lib/specs/spec_1.js b/lib/specs/spec_1.js deleted file mode 100644 index 6415d15e..00000000 --- a/lib/specs/spec_1.js +++ /dev/null @@ -1,295 +0,0 @@ -const { v4: uuidv4 } = require("uuid"); -const Ajv = require("ajv"); - -const { - asData, - isBoolean, - isInteger, - isString, - isDate, - isBinary, - clone -} = require("../utils/fun.js"); - -const isValidType = (v) => - (isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v)); - -const RESERVED_ATTRIBUTES = { - type: "type", - specversion: "specversion", - source: "source", - id: "id", - time: "time", - dataschema: "schemaurl", - datacontenttype: "datacontenttype", - subject: "subject", - data: "data", - data_base64: "data_base64" -}; - -const schema = { - $ref: "#/definitions/event", - definitions: { - specversion: { - type: "string", - minLength: 1, - const: "1.0" - }, - datacontenttype: { - type: "string" - }, - data: { - type: ["object", "string"] - }, - data_base64: { - type: "string" - }, - event: { - properties: { - specversion: { - $ref: "#/definitions/specversion" - }, - datacontenttype: { - $ref: "#/definitions/datacontenttype" - }, - data: { - $ref: "#/definitions/data" - }, - data_base64: { - $ref: "#/definitions/data_base64" - }, - id: { - $ref: "#/definitions/id" - }, - time: { - $ref: "#/definitions/time" - }, - dataschema: { - $ref: "#/definitions/dataschema" - }, - subject: { - $ref: "#/definitions/subject" - }, - type: { - $ref: "#/definitions/type" - }, - source: { - $ref: "#/definitions/source" - } - }, - required: ["specversion", "id", "type", "source"], - type: "object" - }, - id: { - type: "string", - minLength: 1 - }, - time: { - format: "date-time", - type: "string" - }, - dataschema: { - type: "string", - format: "uri" - }, - subject: { - type: "string", - minLength: 1 - }, - type: { - type: "string", - minLength: 1 - }, - source: { - format: "uri-reference", - type: "string" - } - }, - type: "object" -}; - -const ajv = new Ajv({ - extendRefs: true -}); - -const isValidAgainstSchema = ajv.compile(schema); - -function Spec1(_caller) { - this.payload = { - specversion: schema.definitions.specversion.const, - id: uuidv4() - }; - - if (!_caller) { - _caller = require("../cloudevent.js"); - } - - /* - * Used to inject compatibility methods or attributes - */ - this.caller = _caller; - - // dataschema attribute - this.caller.prototype.dataschema = function(dataschema) { - this.spec.dataschema(dataschema); - return this; - }; - this.caller.prototype.getDataschema = function() { - return this.spec.getDataschema(); - }; - - // datacontenttype attribute - this.caller.prototype.dataContentType = function(contentType) { - this.spec.dataContentType(contentType); - return this; - }; - this.caller.prototype.getDataContentType = function() { - return this.spec.getDataContentType(); - }; - - // subject attribute - this.caller.prototype.subject = function(_subject) { - this.spec.subject(_subject); - return this; - }; - this.caller.prototype.getSubject = function() { - return this.spec.getSubject(); - }; - - // format() method override - this.caller.prototype.format = function() { - // Check the constraints - this.spec.check(); - - // Check before getData() call - const isbin = isBinary(this.spec.payload[RESERVED_ATTRIBUTES.data]); - - // May be used, if isbin==true - const payload = clone(this.spec.payload); - - // To run asData() - this.getData(); - - // Handle when is binary, creating the data_base64 - if (isbin) { - payload[RESERVED_ATTRIBUTES.data_base64] = - this.spec.payload[RESERVED_ATTRIBUTES.data]; - delete payload[RESERVED_ATTRIBUTES.data]; - - return this.formatter.format(payload); - } - - // Then, format - return this.formatter.format(this.spec.payload); - }; -} - -/* - * Check the spec constraints - */ -Spec1.prototype.check = function(ce) { - const toCheck = (!ce ? this.payload : ce); - - if (!isValidAgainstSchema(toCheck)) { - const err = new TypeError("invalid payload"); - err.errors = isValidAgainstSchema.errors; - throw err; - } -}; - -Spec1.prototype.id = function(_id) { - this.payload.id = _id; - return this; -}; - -Spec1.prototype.getId = function() { - return this.payload.id; -}; - -Spec1.prototype.source = function(_source) { - this.payload.source = _source; - return this; -}; - -Spec1.prototype.getSource = function() { - return this.payload.source; -}; - -Spec1.prototype.specversion = function() { - // does not set! This is right - return this; -}; - -Spec1.prototype.getSpecversion = function() { - return this.payload.specversion; -}; - -Spec1.prototype.type = function(_type) { - this.payload.type = _type; - return this; -}; - -Spec1.prototype.getType = function() { - return this.payload.type; -}; - -Spec1.prototype.dataContentType = function(_contenttype) { - this.payload.datacontenttype = _contenttype; - return this; -}; -Spec1.prototype.getDataContentType = function() { - return this.payload.datacontenttype; -}; - -Spec1.prototype.dataschema = function(_schema) { - this.payload.dataschema = _schema; - return this; -}; -Spec1.prototype.getDataschema = function() { - return this.payload.dataschema; -}; - -Spec1.prototype.subject = function(_subject) { - this.payload.subject = _subject; - return this; -}; -Spec1.prototype.getSubject = function() { - return this.payload.subject; -}; - -Spec1.prototype.time = function(_time) { - this.payload.time = _time.toISOString(); - return this; -}; -Spec1.prototype.getTime = function() { - return this.payload.time; -}; - -Spec1.prototype.data = function(_data) { - this.payload.data = _data; - return this; -}; -Spec1.prototype.getData = function() { - const dct = this.payload.datacontenttype; - - if (dct) { - this.payload.data = asData(this.payload.data, dct); - } - - return this.payload.data; -}; - -Spec1.prototype.addExtension = function(key, value) { - if (!Object.prototype.hasOwnProperty.call(RESERVED_ATTRIBUTES, key)) { - if (isValidType(value)) { - this.payload[key] = value; - } else { - throw new TypeError("Invalid type of extension value"); - } - } else { - throw new TypeError(`Reserved attribute name: '${key}'`); - } - return this; -}; - -module.exports = Spec1; diff --git a/lib/utils/fun.js b/lib/utils/fun.js deleted file mode 100644 index f7c9ad4c..00000000 --- a/lib/utils/fun.js +++ /dev/null @@ -1,92 +0,0 @@ -// Functional approach -const isString = (v) => (typeof v) === "string"; -const isObject = (v) => (typeof v) === "object"; -const isDefined = (v) => v && (typeof v) !== "undefined"; - -const isBoolean = (v) => (typeof v) === "boolean"; -const isInteger = (v) => Number.isInteger(v); -const isDate = (v) => (v instanceof Date); -const isBinary = (v) => (v instanceof Uint32Array); - -const isStringOrThrow = (v, t) => - (isString(v) - ? true - : (() => { throw t; })()); - -const isDefinedOrThrow = (v, t) => - (isDefined(v) - ? () => true - : (() => { throw t; })()); - -const isStringOrObjectOrThrow = (v, t) => - (isString(v) - ? true - : isObject(v) - ? true - : (() => { throw t; })()); - -const equalsOrThrow = (v1, v2, t) => - (v1 === v2 - ? true - : (() => { throw t; })()); - -const isBase64 = (value) => - Buffer.from(value, "base64").toString("base64") === value; - -const isBuffer = (value) => - value instanceof Buffer; - -const asBuffer = (value) => - isBinary(value) - ? Buffer.from(value) - : isBuffer(value) - ? value - : (() => { throw new TypeError("is not buffer or a valid binary"); })(); - -const asBase64 = (value) => - asBuffer(value).toString("base64"); - -const clone = (o) => - JSON.parse(JSON.stringify(o)); - -const isJsonContentType = (contentType) => - contentType && contentType.match(/(json)/i); - -const asData = (data, contentType) => { - let result = data; - - // pattern matching alike - result = isString(result) && - !isBase64(result) && - isJsonContentType(contentType) - ? JSON.parse(result) - : result; - - result = isBinary(result) - ? asBase64(result) - : result; - - return result; -}; - -module.exports = { - isString, - isStringOrThrow, - isObject, - isDefined, - - isBoolean, - isInteger, - isDate, - isBinary, - - isDefinedOrThrow, - isStringOrObjectOrThrow, - - equalsOrThrow, - isBase64, - clone, - - asData, - asBase64 -}; diff --git a/maintainer_guidelines.md b/maintainer_guidelines.md new file mode 100644 index 00000000..49a438ce --- /dev/null +++ b/maintainer_guidelines.md @@ -0,0 +1,40 @@ +# Maintainer's Guide + +## Tips + +Here are a few tips for repository maintainers. + +* Stay on top of your pull requests. PRs that languish for too long can become difficult to merge. +* Work from your own fork. As you are making contributions to the project, you should be working from your own fork just as outside contributors do. This keeps the branches in github to a minimum and reduces unnecessary CI runs. +* Try to proactively label issues and pull requests with labels +* Actively review pull requests as they are submitted +* Triage issues once in a while in order to keep the repository alive. + * If some issues are stale for too long because they are no longer valid/relevant or because the discussion reached no significant action items to perform, close them and invite the users to reopen if they need it. + * If some PRs are no longer valid due to conflicts, but the PR is still needed, ask the contributor to rebase their PR. + * If some issues and PRs are still relevant, use labels to help organize tasks. + * If you find an issue that you want to create a pull request for, be sure to assign it to yourself so that other maintainers don't start working on it at the same time. + +## Landing Pull Requests + +When landing pull requests, be sure to check the first line uses an appropriate commit message prefix (e.g. docs, feat, lib, etc). If there is more than one commit, try to squash into a single commit. Usually this can just be done with the GitHub UI when merging the PR. Use "Squash and merge". To help ensure that everyone in the community has an opportunity to review and comment on pull requests, it's often good to have some time after a pull request has been submitted, and before it has landed. Some guidelines here about approvals and timing. + +* No pull request may land without passing all automated checks +* All pull requests require at least one approval from a maintainer before landing +* A pull request author may approve their own PR, but will need an additional approval to land it +* If a maintainer has submitted a pull request and it has not received approval from at least one other maintainer, it can be landed after 72 hours +* If a pull request has both approvals and requested changes, it can't be landed until those requested changes are resolved + +## Branch Management + +The `master` branch is the bleeding edge. New major versions of the module +are cut from this branch and tagged. If you intend to submit a pull request +you should use `master HEAD` as your starting point. + +Each major release will result in a new branch and tag. For example, the +release of version 1.0.0 of the module will result in a `v1.0.0` tag on the +release commit, and a new branch `v1.x.y` for subsequent minor and patch +level releases of that major version. However, development will continue +apace on `master` for the next major version - e.g. 2.0.0. Version branches +are only created for each major version. Minor and patch level releases +are simply tagged. + diff --git a/package-lock.json b/package-lock.json index c276e0f3..9ca47155 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cloudevents-sdk", - "version": "1.0.0", + "version": "2.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -193,6 +193,16 @@ "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", "dev": true }, + "@babel/runtime-corejs3": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz", + "integrity": "sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -318,12 +328,390 @@ "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 + }, + "@types/ajv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/ajv/-/ajv-1.0.0.tgz", + "integrity": "sha1-T7JEB0Ly9sMOf7B5e4OfxvaWaCo=", + "dev": true, + "requires": { + "ajv": "*" + } + }, + "@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", + "dev": true, + "requires": { + "axios": "*" + } + }, + "@types/chai": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", + "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/cucumber": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cucumber/-/cucumber-6.0.1.tgz", + "integrity": "sha512-+GZV6xfN0MeN9shDCdny8GbC8N0+U6uca8cjyaJndcwmrUhwS6qOU2vmYn0d71EOwJF568/v3SxJ8VKxuZNYRw==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", + "dev": true + }, + "@types/mocha": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", + "dev": true + }, + "@types/node": { + "version": "13.13.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.9.tgz", + "integrity": "sha512-EPZBIGed5gNnfWCiwEIwTE2Jdg4813odnG8iNPMQGrqVxrI+wL68SPtPeCX+ZxGBaA6pKAVc6jaKgP/Q0QzfdQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz", + "integrity": "sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "3.4.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "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" + } + }, + "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 + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz", + "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "3.4.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.4.0.tgz", + "integrity": "sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "3.4.0", + "@typescript-eslint/typescript-estree": "3.4.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz", + "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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 + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", @@ -335,9 +723,9 @@ } }, "acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "dev": true }, "acorn-jsx": { @@ -363,9 +751,9 @@ } }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -373,29 +761,24 @@ "uri-js": "^4.2.2" } }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, - "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" - }, - "dependencies": { - "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 - } - } - }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -411,6 +794,12 @@ "color-convert": "^1.9.0" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", @@ -430,12 +819,41 @@ "default-require-extensions": "^3.0.0" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "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 + } + } + }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -445,6 +863,24 @@ "sprintf-js": "~1.0.2" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "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 + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -468,6 +904,12 @@ "is-string": "^1.0.5" } }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, "array.prototype.flat": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", @@ -479,22 +921,112 @@ } }, "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "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 + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "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 + }, + "assertion-error-formatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz", + "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", + "dev": true, + "requires": { + "diff": "^4.0.1", + "pad-right": "^0.2.2", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "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-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true, + "optional": 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 }, "axios": { "version": "0.19.2", @@ -510,12 +1042,133 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "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 + }, + "becke-ch--regex--s0-0-v1--base--pl--lib": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz", + "integrity": "sha1-Qpzuu/pffpNueNc/vcfacWKyDiA=", + "dev": true + }, + "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 + }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "dev": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -535,18 +1188,258 @@ "fill-range": "^7.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, "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 }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "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 }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "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": { + "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 + }, + "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 + } + } + }, "caching-transform": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", @@ -559,6 +1452,12 @@ "write-file-atomic": "^3.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", @@ -572,22 +1471,14 @@ "dev": true }, "camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.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 - } + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" } }, "chai": { @@ -615,6 +1506,12 @@ "supports-color": "^5.3.0" }, "dependencies": { + "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 + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -626,12 +1523,6 @@ } } }, - "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", @@ -654,27 +1545,71 @@ "readdirp": "~3.2.0" } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "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==", + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", "dev": true, "requires": { - "restore-cursor": "^3.1.0" + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "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-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" } }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -714,6 +1649,25 @@ } } }, + "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" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -729,12 +1683,17 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, "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, - "optional": true + "dev": true }, "commondir": { "version": "1.0.1", @@ -743,15 +1702,21 @@ "dev": true }, "compare-func": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", - "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz", + "integrity": "sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==", "dev": true, "requires": { "array-ify": "^1.0.0", "dot-prop": "^3.0.0" } }, + "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 + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -770,35 +1735,56 @@ "typedarray": "^0.0.6" } }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, + "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" + } + }, "conventional-changelog": { - "version": "3.1.15", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.15.tgz", - "integrity": "sha512-CoWM+Z9bYyF00QzNpTnxkCLiuLAeRocJz3C/foFjvhsdltdtkJgMChp7GytQNjm4pT7JFBVJTpqLHTpxNtOzaA==", + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.21.tgz", + "integrity": "sha512-ZGecVZPEo3aC75VVE4nu85589dDhpMyqfqgUM5Myq6wfKWiNqhDJLSDMsc8qKXshZoY7dqs1hR0H/15kI/G2jQ==", "dev": true, "requires": { - "conventional-changelog-angular": "^5.0.6", - "conventional-changelog-atom": "^2.0.3", - "conventional-changelog-codemirror": "^2.0.3", - "conventional-changelog-conventionalcommits": "^4.2.3", - "conventional-changelog-core": "^4.1.1", - "conventional-changelog-ember": "^2.0.4", - "conventional-changelog-eslint": "^3.0.4", - "conventional-changelog-express": "^2.0.1", - "conventional-changelog-jquery": "^3.0.6", - "conventional-changelog-jshint": "^2.0.3", - "conventional-changelog-preset-loader": "^2.3.0" + "conventional-changelog-angular": "^5.0.10", + "conventional-changelog-atom": "^2.0.7", + "conventional-changelog-codemirror": "^2.0.7", + "conventional-changelog-conventionalcommits": "^4.3.0", + "conventional-changelog-core": "^4.1.7", + "conventional-changelog-ember": "^2.0.8", + "conventional-changelog-eslint": "^3.0.8", + "conventional-changelog-express": "^2.0.5", + "conventional-changelog-jquery": "^3.0.10", + "conventional-changelog-jshint": "^2.0.7", + "conventional-changelog-preset-loader": "^2.3.4" } }, "conventional-changelog-angular": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", - "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", + "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -806,18 +1792,18 @@ } }, "conventional-changelog-atom": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.3.tgz", - "integrity": "sha512-szZe2ut97qNO6vCCMkm1I/tWu6ol4Rr8a9Lx0y/VlpDnpY0PNp+oGpFgU55lplhx+I3Lro9Iv4/gRj0knfgjzg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.7.tgz", + "integrity": "sha512-7dOREZwzB+tCEMjRTDfen0OHwd7vPUdmU0llTy1eloZgtOP4iSLVzYIQqfmdRZEty+3w5Jz+AbhfTJKoKw1JeQ==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-codemirror": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.3.tgz", - "integrity": "sha512-t2afackdgFV2yBdHhWPqrKbpaQeVnz2hSJKdWqjasPo5EpIB6TBL0er3cOP1mnGQmuzk9JSvimNSuqjWGDtU5Q==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.7.tgz", + "integrity": "sha512-Oralk1kiagn3Gb5cR5BffenWjVu59t/viE6UMD/mQa1hISMPkMYhJIqX+CMeA1zXgVBO+YHQhhokEj99GP5xcg==", "dev": true, "requires": { "q": "^1.5.1" @@ -830,9 +1816,9 @@ "dev": true }, "conventional-changelog-conventionalcommits": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", - "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.3.0.tgz", + "integrity": "sha512-oYHydvZKU+bS8LnGqTMlNrrd7769EsuEHKy4fh1oMdvvDi7fem8U+nvfresJ1IDB8K00Mn4LpiA/lR+7Gs6rgg==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -841,24 +1827,25 @@ } }, "conventional-changelog-core": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.1.4.tgz", - "integrity": "sha512-LO58ZbEpp1Ul+y/vOI8rJRsWkovsYkCFbOCVgi6UnVfU8WC0F8K8VQQwaBZWWUpb6JvEiN4GBR5baRP2txZ+Vg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.1.7.tgz", + "integrity": "sha512-UBvSrQR2RdKbSQKh7RhueiiY4ZAIOW3+CSWdtKOwRv+KxIMNFKm1rOcGBFx0eA8AKhGkkmmacoTWJTqyz7Q0VA==", "dev": true, "requires": { "add-stream": "^1.0.0", - "conventional-changelog-writer": "^4.0.11", - "conventional-commits-parser": "^3.0.8", + "conventional-changelog-writer": "^4.0.16", + "conventional-commits-parser": "^3.1.0", "dateformat": "^3.0.0", "get-pkg-repo": "^1.0.0", "git-raw-commits": "2.0.0", "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^3.0.1", + "git-semver-tags": "^4.0.0", "lodash": "^4.17.15", "normalize-package-data": "^2.3.5", "q": "^1.5.1", "read-pkg": "^3.0.0", "read-pkg-up": "^3.0.0", + "shelljs": "^0.8.3", "through2": "^3.0.0" }, "dependencies": { @@ -923,45 +1910,45 @@ } }, "conventional-changelog-ember": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.4.tgz", - "integrity": "sha512-q1u73sO9uCnxN4TSw8xu6MRU8Y1h9kpwtcdJuNRwu/LSKI1IE/iuNSH5eQ6aLlQ3HTyrIpTfUuVybW4W0F17rA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.8.tgz", + "integrity": "sha512-JEMEcUAMg4Q9yxD341OgWlESQ4gLqMWMXIWWUqoQU8yvTJlKnrvcui3wk9JvnZQyONwM2g1MKRZuAjKxr8hAXA==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-eslint": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.4.tgz", - "integrity": "sha512-CPwTUENzhLGl3auunrJxiIEWncAGaby7gOFCdj2gslIuOFJ0KPJVOUhRz4Da/I53sdo/7UncUJkiLg94jEsjxg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.8.tgz", + "integrity": "sha512-5rTRltgWG7TpU1PqgKHMA/2ivjhrB+E+S7OCTvj0zM/QGg4vmnVH67Vq/EzvSNYtejhWC+OwzvDrLk3tqPry8A==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-express": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.1.tgz", - "integrity": "sha512-G6uCuCaQhLxdb4eEfAIHpcfcJ2+ao3hJkbLrw/jSK/eROeNfnxCJasaWdDAfFkxsbpzvQT4W01iSynU3OoPLIw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.5.tgz", + "integrity": "sha512-pW2hsjKG+xNx/Qjof8wYlAX/P61hT5gQ/2rZ2NsTpG+PgV7Rc8RCfITvC/zN9K8fj0QmV6dWmUefCteD9baEAw==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-jquery": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.6.tgz", - "integrity": "sha512-gHAABCXUNA/HjnZEm+vxAfFPJkgtrZvCDIlCKfdPVXtCIo/Q0lN5VKpx8aR5p8KdVRQFF3OuTlvv5kv6iPuRqA==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.10.tgz", + "integrity": "sha512-QCW6wF8QgPkq2ruPaxc83jZxoWQxLkt/pNxIDn/oYjMiVgrtqNdd7lWe3vsl0hw5ENHNf/ejXuzDHk6suKsRpg==", "dev": true, "requires": { "q": "^1.5.1" } }, "conventional-changelog-jshint": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.3.tgz", - "integrity": "sha512-Pc2PnMPcez634ckzr4EOWviwRSpZcURaK7bjyD9oK6N5fsC/a+3G7LW5m/JpcHPhA9ZxsfIbm7uqZ3ZDGsQ/sw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.7.tgz", + "integrity": "sha512-qHA8rmwUnLiIxANJbz650+NVzqDIwNtc0TcpIa0+uekbmKHttidvQ1dGximU3vEDdoJVKFgR3TXFqYuZmYy9ZQ==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -969,24 +1956,24 @@ } }, "conventional-changelog-preset-loader": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz", - "integrity": "sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true }, "conventional-changelog-writer": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz", - "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz", + "integrity": "sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ==", "dev": true, "requires": { "compare-func": "^1.3.1", - "conventional-commits-filter": "^2.0.2", + "conventional-commits-filter": "^2.0.6", "dateformat": "^3.0.0", - "handlebars": "^4.4.0", + "handlebars": "^4.7.6", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.15", - "meow": "^5.0.0", + "meow": "^7.0.0", "semver": "^6.0.0", "split": "^1.0.0", "through2": "^3.0.0" @@ -1001,9 +1988,9 @@ } }, "conventional-commits-filter": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz", - "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", + "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", "dev": true, "requires": { "lodash.ismatch": "^4.4.0", @@ -1011,33 +1998,33 @@ } }, "conventional-commits-parser": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz", - "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz", + "integrity": "sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA==", "dev": true, "requires": { "JSONStream": "^1.0.4", "is-text-path": "^1.0.1", "lodash": "^4.17.15", - "meow": "^5.0.0", + "meow": "^7.0.0", "split2": "^2.0.0", "through2": "^3.0.0", "trim-off-newlines": "^1.0.0" } }, "conventional-recommended-bump": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.0.5.tgz", - "integrity": "sha512-srkferrB4kACPEbKYltZwX1CQZAEqbQkabKN444mavLRVMetzwJFJf23/+pwvtMsWbd+cc4HaleV1nHke0f8Rw==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.0.9.tgz", + "integrity": "sha512-DpRmW1k8CpRrcsXHOPGgHgOd4BMGiq2gtXAveGM8B9pSd9b4r4WKnqp1Fd0vkDtk8l973mIk8KKKUYnKRr9SFw==", "dev": true, "requires": { "concat-stream": "^2.0.0", - "conventional-changelog-preset-loader": "^2.3.0", - "conventional-commits-filter": "^2.0.2", - "conventional-commits-parser": "^3.0.8", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.6", + "conventional-commits-parser": "^3.1.0", "git-raw-commits": "2.0.0", - "git-semver-tags": "^3.0.1", - "meow": "^5.0.0", + "git-semver-tags": "^4.0.0", + "meow": "^7.0.0", "q": "^1.5.1" } }, @@ -1050,12 +2037,94 @@ "safe-buffer": "~5.1.1" } }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js-pure": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==", + "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 }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "cross-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", @@ -1078,6 +2147,105 @@ } } }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cucumber": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cucumber/-/cucumber-6.0.5.tgz", + "integrity": "sha512-x+W9Fwk6TvcapQsYMxwFU5AsQJDOIJVGrPKmH15OC7jzb9/Dk7Hb0ZAyw4WcpaDcUDRc8bi2k2yJejDp5eTRlg==", + "dev": true, + "requires": { + "assertion-error-formatter": "^3.0.0", + "bluebird": "^3.4.1", + "cli-table3": "^0.5.1", + "colors": "^1.1.2", + "commander": "^3.0.1", + "cucumber-expressions": "^8.1.0", + "cucumber-tag-expressions": "^2.0.2", + "duration": "^0.2.1", + "escape-string-regexp": "^2.0.0", + "figures": "^3.0.0", + "gherkin": "5.0.0", + "glob": "^7.1.3", + "indent-string": "^4.0.0", + "is-generator": "^1.0.2", + "is-stream": "^2.0.0", + "knuth-shuffle-seeded": "^1.0.6", + "lodash": "^4.17.14", + "mz": "^2.4.0", + "progress": "^2.0.0", + "resolve": "^1.3.3", + "serialize-error": "^4.1.0", + "stack-chain": "^2.0.0", + "stacktrace-js": "^2.0.0", + "string-argv": "^0.3.0", + "title-case": "^2.1.1", + "util-arity": "^1.0.2", + "verror": "^1.9.0" + }, + "dependencies": { + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + } + } + }, + "cucumber-expressions": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-8.3.0.tgz", + "integrity": "sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ==", + "dev": true, + "requires": { + "becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0", + "xregexp": "^4.2.4" + } + }, + "cucumber-pretty": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-6.0.0.tgz", + "integrity": "sha512-ddx/VInPVKFB7N86QujgLivihJhuzexKwExMuFaUjSlEs5zVVqBgaf55f88h97VafXTWX+ZAcxTUwMBS4mYj/g==", + "dev": true, + "requires": { + "cli-table3": "^0.5.1", + "colors": "^1.4.0", + "figures": "^3.0.0" + } + }, + "cucumber-tag-expressions": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.3.tgz", + "integrity": "sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ==", + "dev": true + }, + "cucumber-tsflow": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cucumber-tsflow/-/cucumber-tsflow-3.2.0.tgz", + "integrity": "sha512-ftVzqCAmeBavSKMTxGn+8do2/bX1k+IRxYawmC7mmfLvyYb6NpzAi2a4kngGz035OmbRfitqE9ZkBux+XiqedA==", + "dev": true, + "requires": { + "callsite": "^1.0.0", + "underscore": "^1.8.3" + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -1087,6 +2255,22 @@ "array-find-index": "^1.0.1" } }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "dargs": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", @@ -1110,12 +2294,6 @@ "ms": "2.0.0" } }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", - "dev": true - }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -1140,6 +2318,163 @@ } } }, + "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 + } + } + } + } + }, + "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" + } + }, + "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": { + "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 + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + } + } + }, + "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 + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "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 + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "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" + } + } + } + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -1181,20 +2516,63 @@ "object-keys": "^1.0.12" } }, - "deglob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-4.0.1.tgz", - "integrity": "sha512-/g+RDZ7yf2HvoW+E5Cy+K94YhgcFgr6C8LuHZD1O5HoNPkf3KY6RfXJ0DBGlB/NkLi5gml+G9zqRzk9S0mHZCg==", + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^5.0.0", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, "detect-indent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", @@ -1213,15 +2591,40 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true }, "dot-prop": { "version": "3.0.0", @@ -1287,12 +2690,181 @@ } } }, + "download": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/download/-/download-8.0.0.tgz", + "integrity": "sha512-ASRY5QhDk7FK+XrQtQyvhpDKanLluEEQtWl/J7Lxuf/b+i8RYh997QeXvL85xitrmRKVlx9c7eTrcRdq2GS4eA==", + "dev": true, + "requires": { + "archive-type": "^4.0.0", + "content-disposition": "^0.5.2", + "decompress": "^4.2.1", + "ext-name": "^5.0.0", + "file-type": "^11.1.0", + "filenamify": "^3.0.0", + "get-stream": "^4.1.0", + "got": "^8.3.1", + "make-dir": "^2.1.0", + "p-event": "^2.1.0", + "pify": "^4.0.1" + }, + "dependencies": { + "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" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "downtotemp": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/downtotemp/-/downtotemp-0.1.2.tgz", + "integrity": "sha512-Uyvur1ra4BGZjfiW4yminLsQpBGsAj8Hol38AxcO9fkS+t8Z1dp7cO7eMaWUa8A0JFsLbFHcsSjnkM8rp7YDJA==", + "dev": true, + "requires": { + "download": "^8.0.0", + "minimist": "^1.2.5", + "temp-dir": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "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 + }, + "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" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "enquirer": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", + "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", + "dev": true, + "requires": { + "ansi-colors": "^3.2.1" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1302,6 +2874,15 @@ "is-arrayish": "^0.2.1" } }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, "es-abstract": { "version": "1.17.5", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", @@ -1332,35 +2913,68 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, "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-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, "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=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.0.tgz", + "integrity": "sha512-dJMVXwfU5PT1cj2Nv2VPPrKahKTGdX+5Dh0Q3YuKt+Y2UhdL2YbzsVaBMyG9HC0tBismlv/r1+eZqs6SMIV38Q==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.2.0", + "espree": "^7.1.0", + "esquery": "^1.2.0", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", @@ -1369,53 +2983,65 @@ "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", + "levn": "^0.4.1", "lodash": "^4.17.14", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.3", + "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", "table": "^5.2.3", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "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" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "@types/color-name": "^1.1.1", + "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 + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -1434,15 +3060,22 @@ "esutils": "^2.0.2" } }, - "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==", + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, "globals": { "version": "12.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", @@ -1452,6 +3085,12 @@ "type-fest": "^0.8.1" } }, + "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 + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1464,52 +3103,45 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "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 - }, - "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 - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "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=", + "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": { - "shebang-regex": "^1.0.0" + "ansi-regex": "^5.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 - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "has-flag": "^4.0.0" } - }, - "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", - "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + } + } + }, + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "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 } } @@ -1520,12 +3152,6 @@ "integrity": "sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==", "dev": true }, - "eslint-config-standard-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-8.1.0.tgz", - "integrity": "sha512-ULVC8qH8qCqbU792ZOO6DaiaZyHNS/5CZt3hKqHkEhVlhPEPN3nfBqqxJCyp59XrjIBZPu1chMYe9T2DXZ7TMw==", - "dev": true - }, "eslint-import-resolver-node": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", @@ -1569,9 +3195,9 @@ } }, "eslint-plugin-es": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz", - "integrity": "sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "requires": { "eslint-utils": "^2.0.0", @@ -1631,50 +3257,19 @@ } } }, - "eslint-plugin-promise": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", - "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", - "dev": true + "eslint-plugin-prettier": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", + "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } }, - "eslint-plugin-react": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", - "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.1.0", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.0", - "object.values": "^1.1.0", - "prop-types": "^15.7.2", - "resolve": "^1.10.1" - }, - "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-plugin-standard": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", - "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", - "dev": true - }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -1697,14 +3292,22 @@ "dev": true }, "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", + "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", "dev": true, "requires": { - "acorn": "^7.1.1", + "acorn": "^7.2.0", "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^1.2.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "esprima": { @@ -1751,21 +3354,270 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "external-editor": { + "events": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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" + }, + "dependencies": { + "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" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "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 + }, + "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 + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.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" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "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-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } } }, + "extsprintf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", + "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=", + "dev": true + }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -1778,6 +3630,21 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "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" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", @@ -1785,6 +3652,14 @@ "dev": true, "requires": { "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "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 + } } }, "file-entry-cache": { @@ -1796,6 +3671,29 @@ "flat-cache": "^2.0.1" } }, + "file-type": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-11.1.0.tgz", + "integrity": "sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-3.0.0.tgz", + "integrity": "sha512-5EFZ//MsvJgXjBAFJ+Bh2YaCTRF/VP1YOmGrgt+KJ4SFRLjI87EIdwLLuT6wQX0I4F9W41xutobzczjsOKlI/g==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1876,12 +3774,6 @@ } } }, - "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": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -1891,6 +3783,18 @@ "locate-path": "^2.0.0" } }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, "flat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", @@ -1928,6 +3832,42 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -1936,6 +3876,12 @@ "debug": "=3.1.0" } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -1946,28 +3892,128 @@ "signal-exit": "^3.0.2" } }, - "fromentries": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", - "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", - "dev": true - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "null-check": "^1.0.0" + "map-cache": "^0.2.2" } }, - "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": { + "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" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.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": "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" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "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==", @@ -2206,6 +4252,27 @@ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, + "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" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "gherkin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gherkin/-/gherkin-5.0.0.tgz", + "integrity": "sha1-lt70EZjsOQgli1Ea909lWidk0qE=", + "dev": true + }, "git-raw-commits": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz", @@ -2219,6 +4286,35 @@ "through2": "^2.0.0" }, "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -2231,6 +4327,12 @@ "strip-bom": "^3.0.0" } }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, "meow": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", @@ -2248,6 +4350,16 @@ "trim-newlines": "^2.0.0" } }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -2273,6 +4385,12 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -2309,6 +4427,16 @@ "util-deprecate": "~1.0.1" } }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2318,6 +4446,12 @@ "safe-buffer": "~5.1.0" } }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -2327,6 +4461,12 @@ "readable-stream": "~2.3.6", "xtend": "~4.0.1" } + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true } } }, @@ -2341,12 +4481,12 @@ } }, "git-semver-tags": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-3.0.1.tgz", - "integrity": "sha512-Hzd1MOHXouITfCasrpVJbRDg9uvW7LfABk3GQmXYZByerBDrfrEMP9HXpNT7RxAbieiocP6u+xq20DkvjwxnCA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.0.0.tgz", + "integrity": "sha512-LajaAWLYVBff+1NVircURJFL8TQ3EMIcLAfHisWYX/nPoMwnTYfWAznQDmMujlLqoD12VtLmoSrF1sQ5MhimEQ==", "dev": true, "requires": { - "meow": "^5.0.0", + "meow": "^7.0.0", "semver": "^6.0.0" }, "dependencies": { @@ -2390,18 +4530,98 @@ "is-glob": "^4.0.1" } }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, "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 }, + "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" + }, + "dependencies": { + "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 + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "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 }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -2429,6 +4649,12 @@ } } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2444,12 +4670,114 @@ "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-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "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-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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" + } + }, "hasha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", @@ -2466,6 +4794,32 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "highlight.js": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.0.3.tgz", + "integrity": "sha512-9FG7SSzv9yOY5CGGxfI6NDm7xLYtMOjKtPBxw7Zff3t5UcRcUNTGEeS8lNjhceL34KeetLMoGMFTGoaa83HwyQ==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -2478,17 +4832,38 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "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" - } + "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 }, - "ignore": { - "version": "5.1.4", + "http-parser-js": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==", + "dev": true + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "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 + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "5.1.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", "dev": true @@ -2511,6 +4886,70 @@ } } }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "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" + } + }, + "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 + }, + "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" + } + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2523,6 +4962,12 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2545,113 +4990,58 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, - "inquirer": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", - "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "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": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "from2": "^2.1.1", + "p-is-promise": "^1.1.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.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "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 - }, - "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 - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "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 - }, - "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==", + } + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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 }, - "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" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "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": { - "has-flag": "^4.0.0" + "is-buffer": "^1.1.5" } } } @@ -2683,12 +5073,63 @@ "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "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", @@ -2707,6 +5148,12 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-generator": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", + "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -2716,6 +5163,12 @@ "is-extglob": "^2.1.1" } }, + "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-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2728,12 +5181,27 @@ "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-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -2743,6 +5211,12 @@ "has": "^1.0.3" } }, + "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": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -2791,6 +5265,12 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2803,6 +5283,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -2819,15 +5305,12 @@ } }, "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==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "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" @@ -2936,6 +5419,16 @@ "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" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2958,6 +5451,12 @@ "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", @@ -2990,32 +5489,70 @@ "minimist": "^1.2.5" } }, + "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" + } + }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, - "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==", + "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": { - "array-includes": "^3.0.3", - "object.assign": "^4.1.0" + "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 + }, + "knuth-shuffle-seeded": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", + "integrity": "sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE=", + "dev": true, + "requires": { + "seed-random": "~2.2.0" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" } }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, + "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 + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -3028,20 +5565,48 @@ "strip-bom": "^3.0.0" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "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": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } + "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": "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" + } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash._reinterpolate": { @@ -3090,15 +5655,6 @@ "chalk": "^2.4.2" } }, - "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" - } - }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -3109,6 +5665,33 @@ "signal-exit": "^3.0.0" } }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "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": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "lunr": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", + "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==", + "dev": true + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3126,110 +5709,418 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", "dev": true }, - "meow": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", - "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "camelcase-keys": "^4.0.0", - "decamelize-keys": "^1.0.0", - "loud-rejection": "^1.0.0", - "minimist-options": "^3.0.1", - "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0", - "yargs-parser": "^10.0.0" + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "meow": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", + "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "arrify": "^2.0.1", + "camelcase": "^6.0.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" }, "dependencies": { "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", + "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", "dev": true }, - "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=", + "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": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.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=", + "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "p-locate": "^4.1.0" } }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "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": { - "pify": "^3.0.0" + "p-try": "^2.0.0" } }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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" + } + }, + "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 + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "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 }, "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } } }, "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "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 + }, "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "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" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.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-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } } } }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "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 }, + "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 + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "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 + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3246,13 +6137,109 @@ "dev": true }, "minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "mkdirp": { @@ -3305,6 +6292,12 @@ "ms": "^2.1.1" } }, + "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 + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -3324,6 +6317,15 @@ "path-exists": "^3.0.0" } }, + "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" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -3353,6 +6355,12 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "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 } } }, @@ -3362,16 +6370,65 @@ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } }, "natural-compare": { "version": "1.4.0", @@ -3385,12 +6442,27 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "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 }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, "nock": { "version": "12.0.3", "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", @@ -3430,6 +6502,71 @@ "semver": "^5.7.0" } }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + }, + "dependencies": { + "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" + } + } + } + } + } + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -3457,6 +6594,45 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + } + } + }, "null-check": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", @@ -3688,6 +6864,43 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.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 + }, + "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" + } + } + } + }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -3700,6 +6913,15 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -3712,30 +6934,6 @@ "object-keys": "^1.0.11" } }, - "object.entries": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", - "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "object.fromentries": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", - "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, "object.getownpropertydescriptors": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", @@ -3746,6 +6944,15 @@ "es-abstract": "^1.17.0-next.1" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "object.values": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", @@ -3767,33 +6974,68 @@ "wrappy": "1" } }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { - "mimic-fn": "^2.1.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "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" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, - "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=", + "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-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "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": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", "dev": true }, "p-limit": { @@ -3823,6 +7065,15 @@ "aggregate-error": "^3.0.0" } }, + "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": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -3841,46 +7092,137 @@ "release-zalgo": "^1.0.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==", + "pad-right": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", + "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", "dev": true, "requires": { - "callsites": "^3.0.0" + "repeat-string": "^1.5.2" } }, - "parse-github-repo-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", - "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "error-ex": "^1.2.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-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "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-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-github-repo-url": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", + "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", + "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" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true, + "optional": true + }, + "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-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-parse": { @@ -3904,6 +7246,25 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -3931,107 +7292,6 @@ "pinkie": "^2.0.0" } }, - "pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" - }, - "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" - } - }, - "load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.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" - } - }, - "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 - }, - "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" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true - } - } - }, - "pkg-config": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", - "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", - "dev": true, - "requires": { - "debug-log": "^1.0.0", - "find-root": "^1.0.0", - "xtend": "^4.0.1" - } - }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -4041,10 +7301,43 @@ "find-up": "^2.1.0" } }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "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 + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "dev": true }, "process-nextick-args": { @@ -4068,16 +7361,11 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "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" - } + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true }, "propagate": { "version": "2.0.1", @@ -4085,6 +7373,67 @@ "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", "dev": true }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "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" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "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", @@ -4096,18 +7445,54 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, - "quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "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" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "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" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -4149,22 +7534,39 @@ "picomatch": "^2.0.4" } }, - "redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" - }, - "dependencies": { - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - } + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "regexpp": { @@ -4182,6 +7584,25 @@ "es6-error": "^4.0.1" } }, + "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, + "optional": 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 + }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", @@ -4212,22 +7633,73 @@ "path-parse": "^1.0.6" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "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 + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, "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 }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", "dev": true, "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "lowercase-keys": "^1.0.0" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -4237,25 +7709,23 @@ "glob": "^7.1.3" } }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } }, - "rxjs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", - "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { - "tslib": "^1.9.0" + "aproba": "^1.1.1" } }, "safe-buffer": { @@ -4264,24 +7734,126 @@ "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==", + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "seed-random": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", + "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", "dev": true }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "dev": true, + "requires": { + "commander": "~2.8.1" + }, + "dependencies": { + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + } + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "serialize-error": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz", + "integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==", + "dev": true, + "requires": { + "type-fest": "^0.3.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "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 }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4297,6 +7869,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -4314,12 +7897,195 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.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" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "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-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, "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-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "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 + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -4362,9 +8128,9 @@ "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==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -4386,6 +8152,15 @@ "through": "2" } }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -4437,139 +8212,86 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "standard": { - "version": "14.3.3", - "resolved": "https://registry.npmjs.org/standard/-/standard-14.3.3.tgz", - "integrity": "sha512-HBEAD5eVXrr2o/KZ3kU8Wwaxw90wzoq4dOQe6vlRnPoQ6stn4LCLRLBBDp0CjH/aOTL9bDZJbRUOZcBaBnNJ0A==", + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stack-chain": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-2.0.0.tgz", + "integrity": "sha512-GGrHXePi305aW7XQweYZZwiRwR7Js3MWoK/EHzzB9ROdc75nCnjSJVi21rdAGxFl+yCx2L2qdfl5y7NO4lTyqg==", + "dev": true + }, + "stack-generator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz", + "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, + "stacktrace-gps": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz", + "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", "dev": true, "requires": { - "eslint": "~6.8.0", - "eslint-config-standard": "14.1.0", - "eslint-config-standard-jsx": "8.1.0", - "eslint-plugin-import": "~2.18.0", - "eslint-plugin-node": "~10.0.0", - "eslint-plugin-promise": "~4.2.1", - "eslint-plugin-react": "~7.14.2", - "eslint-plugin-standard": "~4.0.0", - "standard-engine": "^12.0.0" + "source-map": "0.5.6", + "stackframe": "^1.1.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" - } - }, - "eslint-config-standard": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz", - "integrity": "sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==", - "dev": true - }, - "eslint-plugin-es": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", - "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", - "dev": true, - "requires": { - "eslint-utils": "^1.4.2", - "regexpp": "^3.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" - } - }, - "eslint-plugin-node": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", - "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", - "dev": true, - "requires": { - "eslint-plugin-es": "^2.0.0", - "eslint-utils": "^1.4.2", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - } - }, - "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" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", "dev": true } } }, - "standard-engine": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-12.0.0.tgz", - "integrity": "sha512-gJIIRb0LpL7AHyGbN9+hJ4UJns37lxmNTnMGRLC8CFrzQ+oB/K60IQjKNgPBCB2VP60Ypm6f8DFXvhVWdBOO+g==", + "stacktrace-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", + "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", "dev": true, "requires": { - "deglob": "^4.0.0", - "get-stdin": "^7.0.0", - "minimist": "^1.1.0", - "pkg-conf": "^3.1.0" - }, - "dependencies": { - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - } + "error-stack-parser": "^2.0.6", + "stack-generator": "^2.0.5", + "stacktrace-gps": "^3.0.4" } }, "standard-version": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-7.1.0.tgz", - "integrity": "sha512-bHY2E/1tYGeVl+0XSXFivb+54h2fA4pWJocXAd6FGbtSFUvGsnfmMbIXYDxrYErpq7oEqoKreV8xTAp78WoATA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-8.0.1.tgz", + "integrity": "sha512-FLZdjvL2tBdwlctfQeyBf4+dX+SFljwdWfUA0F3wPiU9Rn0+FSuD3I0WXuzC1RmcaWwU5WL3EyV4Aanejc8Pqg==", "dev": true, "requires": { - "chalk": "2.4.2", - "conventional-changelog": "3.1.15", + "chalk": "^2.4.2", + "conventional-changelog": "3.1.21", "conventional-changelog-config-spec": "2.1.0", - "conventional-changelog-conventionalcommits": "4.2.3", - "conventional-recommended-bump": "6.0.5", - "detect-indent": "6.0.0", - "detect-newline": "3.1.0", - "dotgitignore": "2.1.0", - "figures": "3.1.0", - "find-up": "4.1.0", - "fs-access": "1.0.1", - "git-semver-tags": "3.0.1", - "semver": "6.3.0", - "stringify-package": "1.0.1", - "yargs": "15.0.2" + "conventional-changelog-conventionalcommits": "4.3.0", + "conventional-recommended-bump": "6.0.9", + "detect-indent": "^6.0.0", + "detect-newline": "^3.1.0", + "dotgitignore": "^2.1.0", + "figures": "^3.1.0", + "find-up": "^4.1.0", + "fs-access": "^1.0.1", + "git-semver-tags": "^4.0.0", + "semver": "^7.1.1", + "stringify-package": "^1.0.1", + "yargs": "^15.3.1" }, "dependencies": { "ansi-regex": { @@ -4676,9 +8398,9 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, "string-width": { @@ -4713,9 +8435,9 @@ } }, "yargs": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz", - "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==", + "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", @@ -4728,13 +8450,13 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^16.1.0" + "yargs-parser": "^18.1.2" } }, "yargs-parser": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", - "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "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", @@ -4743,16 +8465,130 @@ } } }, - "standardx": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/standardx/-/standardx-5.0.0.tgz", - "integrity": "sha512-dWbhU91EqwwWTED224B4X0h1q01Tv2wIv30mFz4NOQ+JMEJKtCrBOUEgMpBIynSFm6MDJYr+H7xUPVMYjGd8HA==", + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { - "standard": "^14.0.0", - "standard-engine": "^12.0.0" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } } }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "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-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-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -4815,9 +8651,9 @@ }, "dependencies": { "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true } } @@ -4843,18 +8679,53 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "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-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "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=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", "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" + }, + "dependencies": { + "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 + } + } + }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", @@ -4901,190 +8772,1239 @@ "requires": { "ansi-regex": "^4.1.0" } - } - } - }, - "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" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "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" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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" + } + }, + "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" + } + } + } + }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true + }, + "terser": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", + "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "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 + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "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-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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "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 + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "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 + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "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-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "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" + } + }, + "trim-newlines": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "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" + }, + "dependencies": { + "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 + } + } + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "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.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typedoc": { + "version": "0.17.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.17.7.tgz", + "integrity": "sha512-PEnzjwQAGjb0O8a6VDE0lxyLAadqNujN5LltsTUhZETolRMiIJv6Ox+Toa8h0XhKHqAOh8MOmB0eBVcWz6nuAw==", + "dev": true, + "requires": { + "fs-extra": "^8.1.0", + "handlebars": "^4.7.6", + "highlight.js": "^10.0.0", + "lodash": "^4.17.15", + "lunr": "^2.3.8", + "marked": "1.0.0", + "minimatch": "^3.0.0", + "progress": "^2.0.3", + "shelljs": "^0.8.4", + "typedoc-default-themes": "^0.10.1" + }, + "dependencies": { + "marked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz", + "integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng==", + "dev": true + } + } + }, + "typedoc-clarity-theme": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/typedoc-clarity-theme/-/typedoc-clarity-theme-1.1.0.tgz", + "integrity": "sha1-ESlK3eTzQuL8ZqX6Yqb7dDjMVhw=" + }, + "typedoc-default-themes": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.10.1.tgz", + "integrity": "sha512-SuqAQI0CkwhqSJ2kaVTgl37cWs733uy9UGUqwtcds8pkFK8oRF4rZmCq+FXTGIb9hIUOu40rf5Kojg0Ha6akeg==", + "dev": true, + "requires": { + "lunr": "^2.3.8" + } + }, + "typescript": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.2.tgz", + "integrity": "sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==", + "dev": true + }, + "uglify-js": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.3.tgz", + "integrity": "sha512-r5ImcL6QyzQGVimQoov3aL2ZScywrOgBXGndbWrdehKoSvGe/RmiE5Jpw/v+GvxODt6l2tpBXwA7n+qZVlHBMA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3" + } + }, + "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" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "underscore": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", + "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "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 + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "optional": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "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==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "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" + } + }, + "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 + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-arity": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", + "integrity": "sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA=", + "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 + }, + "uuid": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "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" + } + }, + "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" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", + "integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==", + "dev": true, + "requires": { + "chokidar": "^3.4.0", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" + }, + "dependencies": { + "chokidar": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "dev": true, + "optional": 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.4.0" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + } + } + }, + "watchpack-chokidar2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", + "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "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, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.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, + "optional": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": 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, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "optional": 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" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "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, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "webpack": { + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz", + "integrity": "sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.1", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "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" + } + } + } + }, + "webpack-cli": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", + "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "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 + }, + "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" + } + }, + "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": { - "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" + "has-flag": "^3.0.0" + } + }, + "v8-compile-cache": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", + "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "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.0" } } } }, - "text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true - }, - "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 - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "dev": true, - "requires": { - "readable-stream": "2 || 3" - } - }, - "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-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" - } - }, - "trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", - "dev": true - }, - "trim-off-newlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true - }, - "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", - "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.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "uglify-js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.1.tgz", - "integrity": "sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.3" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "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==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" - }, - "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "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==", + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "source-list-map": "^2.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 + } } }, "which": { @@ -5123,6 +10043,15 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -5189,6 +10118,15 @@ "typedarray-to-buffer": "^3.1.5" } }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -5201,6 +10139,12 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "yargs": { "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", @@ -5310,6 +10254,22 @@ "lodash": "^4.17.15", "yargs": "^13.3.0" } + }, + "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" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 5811aa47..f1fc47c9 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,26 @@ { "name": "cloudevents-sdk", - "version": "1.0.0", + "version": "2.0.2", "description": "CloudEvents SDK for JavaScript", - "main": "index.js", + "main": "dist/index.js", "scripts": { - "lint": "standardx", - "fix": "standardx --fix", - "pretest": "npm run lint", - "test": "mocha test/**/*.js", + "watch": "tsc --project tsconfig.json --watch", + "build": "tsc --project tsconfig.json && tsc --project tsconfig.browser.json && webpack", + "lint": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}'", + "lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix", + "pretest": "npm run lint && npm run conformance", + "test": "mocha --require ts-node/register ./test/integration/**/*.ts", + "conformance": "npx downtotemp https://raw.githubusercontent.com/cloudevents/conformance/master/features/http-protocol-binding.feature && cucumber-js /tmp/http-protocol-binding.feature -p default", "coverage": "nyc --reporter=lcov --reporter=text npm run test", - "precoverage-publish": "npm run coverage", "coverage-publish": "wget -qO - https://coverage.codacy.com/get.sh | bash -s report -l JavaScript -r coverage/lcov.info", - "release": "standard-version" + "generate-docs": "typedoc --excludeNotDocumented --out docs src", + "release": "standard-version", + "prepublishOnly": "npm run build" }, + "files": [ + "dist", + "bundles" + ], "standard-version": { "types": [ { @@ -87,22 +95,46 @@ }, "homepage": "https://github.com/cloudevents/sdk-javascript#readme", "dependencies": { - "ajv": "~6.12.0", + "ajv": "~6.12.3", "axios": "~0.19.2", - "uuid": "~8.0.0" + "typedoc-clarity-theme": "^1.1.0", + "uuid": "~8.2.0" }, "devDependencies": { + "@types/ajv": "^1.0.0", + "@types/axios": "^0.14.0", + "@types/chai": "^4.2.11", + "@types/cucumber": "^6.0.1", + "@types/mocha": "^7.0.2", + "@types/node": "^13.13.9", + "@types/uuid": "^8.0.0", + "@typescript-eslint/eslint-plugin": "^3.4.0", + "@typescript-eslint/parser": "^3.4.0", "chai": "~4.2.0", - "mocha": "~7.1.1", - "nock": "~12.0.3", - "nyc": "~15.0.0", + "cucumber": "^6.0.5", + "cucumber-pretty": "^6.0.0", + "cucumber-tsflow": "^3.2.0", + "downtotemp": "^0.1.2", + "eslint": "^7.3.0", + "eslint-config-prettier": "^6.11.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.20.2", "eslint-plugin-node": "^11.1.0", - "standardx": "^5.0.0", - "standard-version": "^7.1.0" + "eslint-plugin-prettier": "^3.1.4", + "http-parser-js": "^0.5.2", + "mocha": "~7.1.1", + "nock": "~12.0.3", + "nyc": "~15.0.0", + "prettier": "^2.0.5", + "standard-version": "^8.0.1", + "ts-node": "^8.10.2", + "typedoc": "^0.17.7", + "typescript": "^3.8.3", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.11" }, "publishConfig": { "access": "public" - } + }, + "types": "./dist/index.d.ts" } diff --git a/plugins/ignore-typedef.js b/plugins/ignore-typedef.js new file mode 100644 index 00000000..8ebc9e08 --- /dev/null +++ b/plugins/ignore-typedef.js @@ -0,0 +1,6 @@ +exports.handlers = { + beforeParse(e) { + e.source = e.source.replace(/@typedef.*/, ""); + return e; + } +}; diff --git a/pr_guidelines.md b/pr_guidelines.md new file mode 100644 index 00000000..440674c8 --- /dev/null +++ b/pr_guidelines.md @@ -0,0 +1,177 @@ +# Pull Request Guidelines + +Here you will find step by step guidance for creating, submitting and updating +a pull request in this repository. We hope it will help you have an easy time +managing your work and a positive, satisfying experience when contributing +your code. Thanks for getting involved! :rocket: + +* [Getting Started](#getting-started) +* [Branches](#branches) +* [Commit Messages](#commit-messages) +* [Staying current with master](#staying-current-with-master) +* [Style Guide](#style-guide) +* [Submitting and Updating a Pull Request](#submitting-and-updating-a-pull-request) +* [Congratulations!](#congratulations) + +## Getting Started + +When creating a pull request, first fork this repository and clone it to your +local development environment. Then add this repository as the upstream. + +```console +git clone https://github.com/mygithuborg/sdk-javascript.git +cd sdk-javascript +git remote add upstream https://github.com/cloudevents/sdk-javascript.git +``` + +## Branches + +The first thing you'll need to do is create a branch for your work. +If you are submitting a pull request that fixes or relates to an existing +GitHub issue, you can use this in your branch name to keep things organized. +For example, if you were to create a pull request to fix +[this error with `httpAgent`](https://github.com/cloudevents/sdk-javascript/issues/48) +you might create a branch named `48-fix-http-agent-error`. + +```console +git fetch upstream +git reset --hard upstream/master +git checkout FETCH_HEAD +git checkout -b 48-fix-http-agent-error +``` + +## Commit Messages + +Please follow the +[Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary). +The first line of your commit should be prefixed with a type, be a single +sentence with no period, and succinctly indicate what this commit changes. + +All commit message lines should be kept to fewer than 80 characters if possible. + +An example of a good commit message. + +```log +docs: remove 0.1, 0.2 spec support from README +``` + +If you are unsure what prefix to use for a commit, you can consult the +[package.json](package.json) file. +In the `standard-version.types` section, you can see all of the commit +types that will be committed to the changelog based on the prefix in the first line of +your commit message. For example, the commit message: + +```log +fix: removed a bug that was causing the rotation of the earth to change +``` + +will show up in the "Bug Fixes" section of the changelog for a given release. + +### Signing your commits + +Each commit must be signed. Use the `--signoff` flag for your commits. + +```console +git commit --signoff +``` + +This will add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +The sign-off is a signature line at the end of your commit message. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as open-source code. See [developercertificate.org](http://developercertificate.org/) +for the full text of the certification. + +Be sure to have your `user.name` and `user.email` set in your git config. +If your git config information is set properly then viewing the `git log` +information for your commit will look something like this: + +``` +Author: Joe Smith +Date: Thu Feb 2 11:41:15 2018 -0800 + + Update README + + Signed-off-by: Joe Smith +``` + +Notice the `Author` and `Signed-off-by` lines match. If they don't your PR will +be rejected by the automated DCO check. + +## Staying Current with `master` + +As you are working on your branch, changes may happen on `master`. Before +submitting your pull request, be sure that your branch has been updated +with the latest commits. + +```console +git fetch upstream +git rebase upstream/master +``` + +This may cause conflicts if the files you are changing on your branch are +also changed on master. Error messages from `git` will indicate if conflicts +exist and what files need attention. Resolve the conflicts in each file, then +continue with the rebase with `git rebase --continue`. + + +If you've already pushed some changes to your `origin` fork, you'll +need to force push these changes. + +```console +git push -f origin 48-fix-http-agent-error +``` + +## Style Guide + +Code style for this module is maintained using [`eslint`](https://www.npmjs.com/package/eslint). +When you run tests with `npm test` linting is performed first. If you want to +check your code style for linting errors without running tests, you can just +run `npm run lint`. If there are errors, you can usually fix them automatically +by running `npm run fix`. + +Linting rules are declared in [.eslintrc](https://github.com/cloudevents/sdk-javascript/blob/master/.eslintrc). + +## Submitting and Updating Your Pull Request + +Before submitting a pull request, you should make sure that all of the tests +successfully pass by running `npm test`. + +Once you have sent your pull request, `master` may continue to evolve +before your pull request has landed. If there are any commits on `master` +that conflict with your changes, you may need to update your branch with +these changes before the pull request can land. Resolve conflicts the same +way as before. + +```console +git fetch upstream +git rebase upstream/master +# fix any potential conflicts +git push -f origin 48-fix-http-agent-error +``` + +This will cause the pull request to be updated with your changes, and +CI will rerun. + +A maintainer may ask you to make changes to your pull request. Sometimes these +changes are minor and shouldn't appear in the commit log. For example, you may +have a typo in one of your code comments that should be fixed before merge. +You can prevent this from adding noise to the commit log with an interactive +rebase. See the [git documentation](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) +for details. + +```console +git commit -m "fixup: fix typo" +git rebase -i upstream/master # follow git instructions +``` + +Once you have rebased your commits, you can force push to your fork as before. + +## Congratulations! + +Congratulations! You've done it! We really appreciate the time and energy +you've given to the project. Thank you. diff --git a/lib/bindings/http/constants.js b/src/constants.ts similarity index 59% rename from lib/bindings/http/constants.js rename to src/constants.ts index ab8fead4..449fe06a 100644 --- a/lib/bindings/http/constants.js +++ b/src/constants.ts @@ -1,71 +1,53 @@ -// Commons -module.exports = Object.freeze({ - HEADERS: "headers", +const CONSTANTS = Object.freeze({ CHARSET_DEFAULT: "utf-8", - - SPEC_V03: "0.3", - SPEC_V1: "1.0", - - DEFAULT_SPEC_VERSION_HEADER: "ce-specversion", - + EXTENSIONS_PREFIX: "ce-", ENCODING_BASE64: "base64", - DATA_ATTRIBUTE: "data", MIME_JSON: "application/json", MIME_OCTET_STREAM: "application/octet-stream", MIME_CE: "application/cloudevents", MIME_CE_JSON: "application/cloudevents+json", - HEADER_CONTENT_TYPE: "content-type", - DEFAULT_CONTENT_TYPE: "application/json; charset=utf-8", DEFAULT_CE_CONTENT_TYPE: "application/cloudevents+json; charset=utf-8", - BINARY_HEADERS_03: { + CE_HEADERS: { TYPE: "ce-type", SPEC_VERSION: "ce-specversion", SOURCE: "ce-source", ID: "ce-id", TIME: "ce-time", - SCHEMA_URL: "ce-schemaurl", - CONTENT_ENCONDING: "ce-datacontentencoding", SUBJECT: "ce-subject", - EXTENSIONS_PREFIX: "ce-" }, - STRUCTURED_ATTRS_03: { + + CE_ATTRIBUTES: { + ID: "id", TYPE: "type", - SPEC_VERSION: "specversion", SOURCE: "source", - ID: "id", + SPEC_VERSION: "specversion", TIME: "time", - SCHEMA_URL: "schemaurl", - CONTENT_ENCONDING: "datacontentencoding", CONTENT_TYPE: "datacontenttype", SUBJECT: "subject", - DATA: "data" + DATA: "data", + }, + + BINARY_HEADERS_03: { + SCHEMA_URL: "ce-schemaurl", + CONTENT_ENCODING: "ce-datacontentencoding", + }, + STRUCTURED_ATTRS_03: { + SCHEMA_URL: "schemaurl", + CONTENT_ENCODING: "datacontentencoding", }, BINARY_HEADERS_1: { - TYPE: "ce-type", - SPEC_VERSION: "ce-specversion", - SOURCE: "ce-source", - ID: "ce-id", - TIME: "ce-time", DATA_SCHEMA: "ce-dataschema", - SUBJECT: "ce-subject", - EXTENSIONS_PREFIX: "ce-" }, STRUCTURED_ATTRS_1: { - TYPE: "type", - SPEC_VERSION: "specversion", - SOURCE: "source", - ID: "id", - TIME: "time", DATA_SCHEMA: "dataschema", - CONTENT_TYPE: "datacontenttype", - SUBJECT: "subject", - DATA: "data", - DATA_BASE64: "data_base64" - } + DATA_BASE64: "data_base64", + }, }); + +export default CONSTANTS; diff --git a/src/event/cloudevent.ts b/src/event/cloudevent.ts new file mode 100644 index 00000000..93516e2c --- /dev/null +++ b/src/event/cloudevent.ts @@ -0,0 +1,195 @@ +import { v4 as uuidv4 } from "uuid"; + +import { CloudEventV1, validateV1, CloudEventV1Attributes, CloudEventV1OptionalAttributes } from "./v1"; +import { CloudEventV03, validateV03, CloudEventV03Attributes, CloudEventV03OptionalAttributes } from "./v03"; +import { ValidationError, isBinary, asBase64 } from "./validation"; +import CONSTANTS from "../constants"; +import { isString } from "util"; + +/** + * An enum representing the CloudEvent specification version + */ +export const enum Version { + V1 = "1.0", + V03 = "0.3", +} + +/** + * A CloudEvent describes event data in common formats to provide + * interoperability across services, platforms and systems. + * @see https://github.com/cloudevents/spec/blob/v1.0/spec.md + */ +export class CloudEvent implements CloudEventV1, CloudEventV03 { + id: string; + type: string; + source: string; + specversion: Version; + datacontenttype?: string; + dataschema?: string; + subject?: string; + #_time?: string | Date; + #_data?: Record | string | number | boolean | null | unknown; + data_base64?: string; + + // Extensions should not exist as it's own object, but instead + // exist as properties on the event as siblings of the others + [key: string]: unknown; + + // V03 deprecated attributes + schemaurl?: string; + datacontentencoding?: string; + + constructor(event: CloudEventV1 | CloudEventV1Attributes | CloudEventV03 | CloudEventV03Attributes) { + // copy the incoming event so that we can delete properties as we go + // everything left after we have deleted know properties becomes an extension + const properties = { ...event }; + + this.id = (properties.id as string) || uuidv4(); + delete properties.id; + + this.type = properties.type; + delete properties.type; + + this.source = properties.source; + delete properties.source; + + this.specversion = (properties.specversion as Version) || Version.V1; + delete properties.specversion; + + this.datacontenttype = properties.datacontenttype; + delete properties.datacontenttype; + + this.subject = properties.subject; + delete properties.subject; + + this.#_time = properties.time; + delete properties.time; + + this.datacontentencoding = properties.datacontentencoding as string; + delete properties.datacontentencoding; + + this.dataschema = properties.dataschema as string; + delete properties.dataschema; + + this.data_base64 = properties.data_base64 as string; + delete properties.data_base64; + + this.schemaurl = properties.schemaurl as string; + delete properties.schemaurl; + + this._setData(properties.data); + delete properties.data; + + // Make sure time has a default value and whatever is provided is formatted + if (!this.#_time) { + this.#_time = new Date().toISOString(); + } else if (this.#_time instanceof Date) { + this.#_time = this.#_time.toISOString(); + } + + // sanity checking + if (this.specversion === Version.V1 && this.schemaurl) { + throw new TypeError("cannot set schemaurl on version 1.0 event"); + } else if (this.specversion === Version.V03 && this.dataschema) { + throw new TypeError("cannot set dataschema on version 0.3 event"); + } + + // finally process any remaining properties - these are extensions + for (const [key, value] of Object.entries(properties)) { + // Extension names should only allow lowercase a-z and 0-9 in the name + // names should not exceed 20 characters in length + if (!key.match(/^[a-z0-9]{1,20}$/)) { + throw new ValidationError("invalid extension name"); + } + this[key] = value; + } + + this.validate(); + + Object.freeze(this); + } + + get time(): string | Date { + return this.#_time as string | Date; + } + + set time(val: string | Date) { + this.#_time = new Date(val).toISOString(); + } + + get data(): unknown { + if ( + this.datacontenttype === CONSTANTS.MIME_JSON && + !(this.datacontentencoding === CONSTANTS.ENCODING_BASE64) && + isString(this.#_data) + ) { + return JSON.parse(this.#_data as string); + } else if (isBinary(this.#_data)) { + return asBase64(this.#_data as Uint32Array); + } + return this.#_data; + } + + set data(value: unknown) { + this._setData(value); + } + + private _setData(value: unknown): void { + if (isBinary(value)) { + this.#_data = value; + this.data_base64 = asBase64(value as Uint32Array); + } + this.#_data = value; + } + + toJSON(): Record { + const event = { ...this }; + event.time = this.time; + event.data = this.data; + return event; + } + + toString(): string { + return JSON.stringify(this); + } + + /** + * Validates this CloudEvent against the schema + * @throws if the CloudEvent does not conform to the schema + * @return {boolean} true if this event is valid + */ + public validate(): boolean { + try { + if (this.specversion === Version.V1) { + return validateV1(this); + } else if (this.specversion === Version.V03) { + return validateV03(this); + } + throw new ValidationError("invalid payload"); + } catch (e) { + if (e instanceof ValidationError) { + throw e; + } else { + throw new ValidationError("invalid payload", e); + } + } + } + + /** + * Clone a CloudEvent with new/update attributes + * @param {object} options attributes to augment the CloudEvent with + * @throws if the CloudEvent does not conform to the schema + * @return {CloudEvent} returns a new CloudEvent + */ + public cloneWith( + options: + | CloudEventV1 + | CloudEventV1Attributes + | CloudEventV1OptionalAttributes + | CloudEventV03 + | CloudEventV03Attributes + | CloudEventV03OptionalAttributes, + ): CloudEvent { + return new CloudEvent(Object.assign({}, this.toJSON(), options) as CloudEvent); + } +} diff --git a/src/event/index.ts b/src/event/index.ts new file mode 100644 index 00000000..e852d4e2 --- /dev/null +++ b/src/event/index.ts @@ -0,0 +1,4 @@ +export * from "./cloudevent"; +export * from "./validation"; +export * from "./v1"; +export * from "./v03"; diff --git a/src/event/v03/cloudevent.ts b/src/event/v03/cloudevent.ts new file mode 100644 index 00000000..9d4b5d6d --- /dev/null +++ b/src/event/v03/cloudevent.ts @@ -0,0 +1,135 @@ +/** + * The object interface for CloudEvents 0.3. + * @see https://github.com/cloudevents/spec/blob/v0.3/spec.md + */ + +export interface CloudEventV03 extends CloudEventV03Attributes { + // REQUIRED Attributes + /** + * [REQUIRED] Identifies the event. Producers MUST ensure that `source` + `id` + * is unique for each distinct event. If a duplicate event is re-sent (e.g. due + * to a network error) it MAY have the same `id`. Consumers MAY assume that + * Events with identical `source` and `id` are duplicates. + * @required Non-empty string. Unique within producer. + * @example An event counter maintained by the producer + * @example A UUID + */ + id: string; + /** + * [REQUIRED] The version of the CloudEvents specification which the event + * uses. This enables the interpretation of the context. Compliant event + * producers MUST use a value of `1.0` when referring to this version of the + * specification. + * @required MUST be a non-empty string. + */ + specversion: string; +} + +export interface CloudEventV03Attributes extends CloudEventV03OptionalAttributes { + /** + * [REQUIRED] Identifies the context in which an event happened. Often this + * will include information such as the type of the event source, the + * organization publishing the event or the process that produced the event. The + * exact syntax and semantics behind the data encoded in the URI is defined by + * the event producer. + * Producers MUST ensure that `source` + `id` is unique for each distinct event. + * An application MAY assign a unique `source` to each distinct producer, which + * makes it easy to produce unique IDs since no other producer will have the same + * source. The application MAY use UUIDs, URNs, DNS authorities or an + * application-specific scheme to create unique `source` identifiers. + * A source MAY include more than one producer. In that case the producers MUST + * collaborate to ensure that `source` + `id` is unique for each distinct event. + * @required Non-empty URI-reference + */ + source: string; + /** + * [REQUIRED] This attribute contains a value describing the type of event + * related to the originating occurrence. Often this attribute is used for + * routing, observability, policy enforcement, etc. The format of this is + * producer defined and might include information such as the version of the + * `type` - see + * [Versioning of Attributes in the Primer](primer.md#versioning-of-attributes) + * for more information. + * @required MUST be a non-empty string + * @should SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the + * organization which defines the semantics of this event type. + * @example com.github.pull.create + * @example com.example.object.delete.v2 + */ + type: string; +} + +export interface CloudEventV03OptionalAttributes { + /** + * The following fields are optional. + */ + + /** + * [OPTIONAL] Describes the content encoding for the data attribute for when the + * data field MUST be encoded as a string, like with structured transport binding + * modes using the JSON event format, but the datacontenttype indicates a non-string + * media type. When the data field's effective data type is not String, this attribute + * MUST NOT be set and MUST be ignored when set. + */ + datacontentencoding?: string; + + /** + * [OPTIONAL] Content type of `data` value. This attribute enables `data` to + * carry any type of content, whereby format and encoding might differ from that + * of the chosen event format. For example, an event rendered using the + * [JSON envelope](./json-format.md#3-envelope) format might carry an XML payload + * in `data`, and the consumer is informed by this attribute being set to + * "application/xml". The rules for how `data` content is rendered for different + * `datacontenttype` values are defined in the event format specifications; for + * example, the JSON event format defines the relationship in + * [section 3.1](./json-format.md#31-handling-of-data). + */ + datacontenttype?: string; + /** + * [OPTIONAL] A link to the schema that the data attribute adheres to. + * Incompatible changes to the schema SHOULD be reflected by a different URL. + * If present, MUST be a non-empty URI. + */ + schemaurl?: string; + /** + * [OPTIONAL] This describes the subject of the event in the context of the + * event producer (identified by `source`). In publish-subscribe scenarios, a + * subscriber will typically subscribe to events emitted by a `source`, but the + * `source` identifier alone might not be sufficient as a qualifier for any + * specific event if the `source` context has internal sub-structure. + * + * Identifying the subject of the event in context metadata (opposed to only in + * the `data` payload) is particularly helpful in generic subscription filtering + * scenarios where middleware is unable to interpret the `data` content. In the + * above example, the subscriber might only be interested in blobs with names + * ending with '.jpg' or '.jpeg' and the `subject` attribute allows for + * constructing a simple and efficient string-suffix filter for that subset of + * events. + * + * If present, MUST be a non-empty string. + * @example "https://example.com/storage/tenant/container" + * @example "mynewfile.jpg" + */ + subject?: string; + /** + * [OPTIONAL] Timestamp of when the occurrence happened. If the time of the + * occurrence cannot be determined then this attribute MAY be set to some other + * time (such as the current time) by the CloudEvents producer, however all + * producers for the same `source` MUST be consistent in this respect. In other + * words, either they all use the actual time of the occurrence or they all use + * the same algorithm to determine the value used. + * @example "2020-08-08T14:48:09.769Z" + */ + time?: Date | string; + /** + * [OPTIONAL] The event payload. This specification does not place any restriction + * on the type of this information. It is encoded into a media format which is + * specified by the datacontenttype attribute (e.g. application/json), and adheres + * to the dataschema format when those respective attributes are present. + */ + data?: Record | string | number | boolean | null | unknown; + /** + * [OPTIONAL] CloudEvents extension attributes. + */ + [key: string]: unknown; +} diff --git a/src/event/v03/index.ts b/src/event/v03/index.ts new file mode 100644 index 00000000..e207dd46 --- /dev/null +++ b/src/event/v03/index.ts @@ -0,0 +1,3 @@ +export * from "./cloudevent"; +export * from "./spec"; +export * from "./schema"; diff --git a/src/event/v03/schema.ts b/src/event/v03/schema.ts new file mode 100644 index 00000000..f6423d40 --- /dev/null +++ b/src/event/v03/schema.ts @@ -0,0 +1,74 @@ +const schemaV03 = { + $ref: "#/definitions/event", + definitions: { + specversion: { + const: "0.3", + }, + datacontenttype: { + type: "string", + }, + data: { + type: ["object", "string"], + }, + event: { + properties: { + specversion: { + $ref: "#/definitions/specversion", + }, + datacontenttype: { + $ref: "#/definitions/datacontenttype", + }, + data: { + $ref: "#/definitions/data", + }, + id: { + $ref: "#/definitions/id", + }, + time: { + $ref: "#/definitions/time", + }, + schemaurl: { + $ref: "#/definitions/schemaurl", + }, + subject: { + $ref: "#/definitions/subject", + }, + type: { + $ref: "#/definitions/type", + }, + source: { + $ref: "#/definitions/source", + }, + }, + required: ["specversion", "id", "type", "source"], + type: "object", + }, + id: { + type: "string", + minLength: 1, + }, + time: { + format: "date-time", + type: "string", + }, + schemaurl: { + type: "string", + format: "uri-reference", + }, + subject: { + type: "string", + minLength: 1, + }, + type: { + type: "string", + minLength: 1, + }, + source: { + format: "uri-reference", + type: "string", + }, + }, + type: "object", +}; + +export { schemaV03 as schema }; diff --git a/src/event/v03/spec.ts b/src/event/v03/spec.ts new file mode 100644 index 00000000..280d7285 --- /dev/null +++ b/src/event/v03/spec.ts @@ -0,0 +1,42 @@ +import { v4 as uuidv4 } from "uuid"; +import Ajv from "ajv"; +import { ValidationError, isBase64 } from "../validation"; +import { CloudEventV03, CloudEventV03Attributes } from "./cloudevent"; +import { CloudEvent } from "../.."; +import { schema } from "./schema"; +import CONSTANTS from "../../constants"; + +const ajv = new Ajv({ extendRefs: true }); +const isValidAgainstSchema = ajv.compile(schema); + +export function createV03(attributes: CloudEventV03Attributes): CloudEventV03 { + const event: CloudEventV03 = { + specversion: schema.definitions.specversion.const, + id: uuidv4(), + time: new Date().toISOString(), + ...attributes, + }; + return new CloudEvent(event); +} + +export function validateV03(event: CloudEventV03): boolean { + if (!isValidAgainstSchema(event)) { + throw new ValidationError("invalid payload", isValidAgainstSchema.errors); + } + return checkDataContentEncoding(event); +} + +function checkDataContentEncoding(event: CloudEventV03): boolean { + if (event.datacontentencoding) { + // we only support base64 + const encoding = event.datacontentencoding.toLocaleLowerCase(); + if (encoding !== CONSTANTS.ENCODING_BASE64) { + throw new ValidationError("invalid payload", [`Unsupported content encoding: ${encoding}`]); + } else { + if (!isBase64(event.data)) { + throw new ValidationError("invalid payload", [`Invalid content encoding of data: ${event.data}`]); + } + } + } + return true; +} diff --git a/src/event/v1/cloudevent.ts b/src/event/v1/cloudevent.ts new file mode 100644 index 00000000..f9f27291 --- /dev/null +++ b/src/event/v1/cloudevent.ts @@ -0,0 +1,137 @@ +/** + * The object interface for CloudEvents 1.0. + * @see https://github.com/cloudevents/spec/blob/v1.0/spec.md + */ +export interface CloudEventV1 extends CloudEventV1Attributes { + // REQUIRED Attributes + /** + * [REQUIRED] Identifies the event. Producers MUST ensure that `source` + `id` + * is unique for each distinct event. If a duplicate event is re-sent (e.g. due + * to a network error) it MAY have the same `id`. Consumers MAY assume that + * Events with identical `source` and `id` are duplicates. + * @required Non-empty string. Unique within producer. + * @example An event counter maintained by the producer + * @example A UUID + */ + id: string; + + /** + * [REQUIRED] The version of the CloudEvents specification which the event + * uses. This enables the interpretation of the context. Compliant event + * producers MUST use a value of `1.0` when referring to this version of the + * specification. + * @required MUST be a non-empty string. + */ + specversion: string; +} + +export interface CloudEventV1Attributes extends CloudEventV1OptionalAttributes { + /** + * [REQUIRED] Identifies the context in which an event happened. Often this + * will include information such as the type of the event source, the + * organization publishing the event or the process that produced the event. The + * exact syntax and semantics behind the data encoded in the URI is defined by + * the event producer. + * Producers MUST ensure that `source` + `id` is unique for each distinct event. + * An application MAY assign a unique `source` to each distinct producer, which + * makes it easy to produce unique IDs since no other producer will have the same + * source. The application MAY use UUIDs, URNs, DNS authorities or an + * application-specific scheme to create unique `source` identifiers. + * A source MAY include more than one producer. In that case the producers MUST + * collaborate to ensure that `source` + `id` is unique for each distinct event. + * @required Non-empty URI-reference + */ + source: string; + + /** + * [REQUIRED] This attribute contains a value describing the type of event + * related to the originating occurrence. Often this attribute is used for + * routing, observability, policy enforcement, etc. The format of this is + * producer defined and might include information such as the version of the + * `type` - see + * [Versioning of Attributes in the Primer](primer.md#versioning-of-attributes) + * for more information. + * @required MUST be a non-empty string + * @should SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the + * organization which defines the semantics of this event type. + * @example com.github.pull.create + * @example com.example.object.delete.v2 + */ + type: string; +} + +export interface CloudEventV1OptionalAttributes { + /** + * The following fields are optional. + */ + + /** + * [OPTIONAL] Content type of `data` value. This attribute enables `data` to + * carry any type of content, whereby format and encoding might differ from that + * of the chosen event format. For example, an event rendered using the + * [JSON envelope](./json-format.md#3-envelope) format might carry an XML payload + * in `data`, and the consumer is informed by this attribute being set to + * "application/xml". The rules for how `data` content is rendered for different + * `datacontenttype` values are defined in the event format specifications; for + * example, the JSON event format defines the relationship in + * [section 3.1](./json-format.md#31-handling-of-data). + */ + datacontenttype?: string; + /** + * [OPTIONAL] Identifies the schema that `data` adheres to. Incompatible + * changes to the schema SHOULD be reflected by a different URI. See + * [Versioning of Attributes in the Primer](primer.md#versioning-of-attributes) + * for more information. + * If present, MUST be a non-empty URI. + */ + dataschema?: string; + /** + * [OPTIONAL] This describes the subject of the event in the context of the + * event producer (identified by `source`). In publish-subscribe scenarios, a + * subscriber will typically subscribe to events emitted by a `source`, but the + * `source` identifier alone might not be sufficient as a qualifier for any + * specific event if the `source` context has internal sub-structure. + * + * Identifying the subject of the event in context metadata (opposed to only in + * the `data` payload) is particularly helpful in generic subscription filtering + * scenarios where middleware is unable to interpret the `data` content. In the + * above example, the subscriber might only be interested in blobs with names + * ending with '.jpg' or '.jpeg' and the `subject` attribute allows for + * constructing a simple and efficient string-suffix filter for that subset of + * events. + * + * If present, MUST be a non-empty string. + * @example "https://example.com/storage/tenant/container" + * @example "mynewfile.jpg" + */ + subject?: string; + /** + * [OPTIONAL] Timestamp of when the occurrence happened. If the time of the + * occurrence cannot be determined then this attribute MAY be set to some other + * time (such as the current time) by the CloudEvents producer, however all + * producers for the same `source` MUST be consistent in this respect. In other + * words, either they all use the actual time of the occurrence or they all use + * the same algorithm to determine the value used. + * @example "2020-08-08T14:48:09.769Z" + */ + time?: Date | string; + /** + * [OPTIONAL] The event payload. This specification does not place any restriction + * on the type of this information. It is encoded into a media format which is + * specified by the datacontenttype attribute (e.g. application/json), and adheres + * to the dataschema format when those respective attributes are present. + */ + data?: Record | string | number | boolean | null | unknown; + + /** + * [OPTIONAL] The event payload encoded as base64 data. This is used when the + * data is in binary form. + * @see https://github.com/cloudevents/spec/blob/v1.0/json-format.md#31-handling-of-data + */ + data_base64?: string; + + /** + * [OPTIONAL] CloudEvents extension attributes. + */ + [key: string]: unknown; +} diff --git a/src/event/v1/index.ts b/src/event/v1/index.ts new file mode 100644 index 00000000..e207dd46 --- /dev/null +++ b/src/event/v1/index.ts @@ -0,0 +1,3 @@ +export * from "./cloudevent"; +export * from "./spec"; +export * from "./schema"; diff --git a/src/event/v1/schema.ts b/src/event/v1/schema.ts new file mode 100644 index 00000000..f56d76e3 --- /dev/null +++ b/src/event/v1/schema.ts @@ -0,0 +1,82 @@ +const schemaV1 = { + $ref: "#/definitions/event", + definitions: { + specversion: { + type: "string", + minLength: 1, + const: "1.0", + }, + datacontenttype: { + type: "string", + }, + data: { + type: ["object", "string"], + }, + data_base64: { + type: "string", + }, + event: { + properties: { + specversion: { + $ref: "#/definitions/specversion", + }, + datacontenttype: { + $ref: "#/definitions/datacontenttype", + }, + data: { + $ref: "#/definitions/data", + }, + data_base64: { + $ref: "#/definitions/data_base64", + }, + id: { + $ref: "#/definitions/id", + }, + time: { + $ref: "#/definitions/time", + }, + dataschema: { + $ref: "#/definitions/dataschema", + }, + subject: { + $ref: "#/definitions/subject", + }, + type: { + $ref: "#/definitions/type", + }, + source: { + $ref: "#/definitions/source", + }, + }, + required: ["specversion", "id", "type", "source"], + type: "object", + }, + id: { + type: "string", + minLength: 1, + }, + time: { + format: "date-time", + type: "string", + }, + dataschema: { + type: "string", + format: "uri", + }, + subject: { + type: "string", + minLength: 1, + }, + type: { + type: "string", + minLength: 1, + }, + source: { + format: "uri-reference", + type: "string", + }, + }, + type: "object", +}; + +export { schemaV1 }; diff --git a/src/event/v1/spec.ts b/src/event/v1/spec.ts new file mode 100644 index 00000000..e4af5a87 --- /dev/null +++ b/src/event/v1/spec.ts @@ -0,0 +1,28 @@ +import Ajv from "ajv"; +import { v4 as uuidv4 } from "uuid"; + +import { CloudEvent } from "../cloudevent"; +import { CloudEventV1, CloudEventV1Attributes } from "./cloudevent"; +import { ValidationError } from "../validation"; + +import { schemaV1 } from "./schema"; + +const ajv = new Ajv({ extendRefs: true }); +const isValidAgainstSchema = ajv.compile(schemaV1); + +export function createV1(attributes: CloudEventV1Attributes): CloudEventV1 { + const event: CloudEventV1 = { + specversion: schemaV1.definitions.specversion.const, + id: uuidv4(), + time: new Date().toISOString(), + ...attributes, + }; + return new CloudEvent(event); +} + +export function validateV1(event: CloudEventV1): boolean { + if (!isValidAgainstSchema(event)) { + throw new ValidationError("invalid payload", isValidAgainstSchema.errors); + } + return true; +} diff --git a/src/event/validation/index.ts b/src/event/validation/index.ts new file mode 100644 index 00000000..5b4ab37b --- /dev/null +++ b/src/event/validation/index.ts @@ -0,0 +1,2 @@ +export * from "./is"; +export * from "./validation_error"; diff --git a/src/event/validation/is.ts b/src/event/validation/is.ts new file mode 100644 index 00000000..328746dd --- /dev/null +++ b/src/event/validation/is.ts @@ -0,0 +1,87 @@ +const isString = (v: unknown): boolean => typeof v === "string"; +const isObject = (v: unknown): boolean => typeof v === "object"; +const isDefined = (v: unknown): boolean => v && typeof v !== "undefined"; + +const isBoolean = (v: unknown): boolean => typeof v === "boolean"; +const isInteger = (v: unknown): boolean => Number.isInteger(v as number); +const isDate = (v: unknown): boolean => v instanceof Date; +const isBinary = (v: unknown): boolean => v instanceof Uint32Array; + +const isStringOrThrow = (v: unknown, t: Error): boolean => + isString(v) + ? true + : (() => { + throw t; + })(); + +const isDefinedOrThrow = (v: unknown, t: Error): boolean => + isDefined(v) + ? true + : (() => { + throw t; + })(); + +const isStringOrObjectOrThrow = (v: unknown, t: Error): boolean => + isString(v) + ? true + : isObject(v) + ? true + : (() => { + throw t; + })(); + +const equalsOrThrow = (v1: unknown, v2: unknown, t: Error): boolean => + v1 === v2 + ? true + : (() => { + throw t; + })(); + +const isBase64 = (value: unknown): boolean => Buffer.from(value as string, "base64").toString("base64") === value; + +const isBuffer = (value: unknown): boolean => value instanceof Buffer; + +const asBuffer = (value: string | Buffer | Uint32Array): Buffer => + isBinary(value) + ? Buffer.from(value as string) + : isBuffer(value) + ? (value as Buffer) + : (() => { + throw new TypeError("is not buffer or a valid binary"); + })(); + +const asBase64 = (value: string | Buffer | Uint32Array): string => asBuffer(value).toString("base64"); + +const clone = (o: Record): Record => JSON.parse(JSON.stringify(o)); + +const isJsonContentType = (contentType: string) => contentType && contentType.match(/(json)/i); + +const asData = (data: unknown, contentType: string): string => { + // pattern matching alike + const maybeJson = + isString(data) && !isBase64(data) && isJsonContentType(contentType) ? JSON.parse(data as string) : data; + + return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson; +}; + +const isValidType = (v: boolean | number | string | Date | Uint32Array): boolean => + isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v); + +export { + isString, + isStringOrThrow, + isObject, + isDefined, + isBoolean, + isInteger, + isDate, + isBinary, + isDefinedOrThrow, + isStringOrObjectOrThrow, + isValidType, + equalsOrThrow, + isBase64, + clone, + asData, + asBase64, +}; diff --git a/src/event/validation/validation_error.ts b/src/event/validation/validation_error.ts new file mode 100644 index 00000000..598fee68 --- /dev/null +++ b/src/event/validation/validation_error.ts @@ -0,0 +1,14 @@ +import { ErrorObject } from "ajv"; + +/** + * An Error class that will be thrown when a CloudEvent + * cannot be properly validated against a specification. + */ +export class ValidationError extends TypeError { + errors?: string[] | ErrorObject[] | null; + + constructor(message: string, errors?: string[] | ErrorObject[] | null) { + super(message); + this.errors = errors ? errors : []; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..3f630b76 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,31 @@ +import { + CloudEvent, + CloudEventV03, + CloudEventV03Attributes, + CloudEventV1, + CloudEventV1Attributes, + ValidationError, + Version, +} from "./event"; + +import { Emitter, Receiver, Mode, Protocol, TransportOptions } from "./transport"; +import { Headers, headersFor } from "./transport/http/headers"; + +export { + // From event + CloudEvent, + CloudEventV03, + CloudEventV03Attributes, + CloudEventV1, + CloudEventV1Attributes, + Version, + ValidationError, + // From transport + Emitter, + Receiver, + Mode, + Protocol, + TransportOptions, + Headers, + headersFor, +}; diff --git a/src/parsers/base64.ts b/src/parsers/base64.ts new file mode 100644 index 00000000..bb442ff6 --- /dev/null +++ b/src/parsers/base64.ts @@ -0,0 +1,18 @@ +import { Parser } from "./parser"; + +export class Base64Parser implements Parser { + decorator?: Parser; + + constructor(decorator?: Parser) { + this.decorator = decorator; + } + + parse(payload: Record | string): string { + let payloadToParse = payload; + if (this.decorator) { + payloadToParse = this.decorator.parse(payload) as string; + } + + return Buffer.from(payloadToParse as string, "base64").toString(); + } +} diff --git a/src/parsers/date.ts b/src/parsers/date.ts new file mode 100644 index 00000000..77d53d4a --- /dev/null +++ b/src/parsers/date.ts @@ -0,0 +1,7 @@ +import { Parser } from "./parser"; + +export class DateParser extends Parser { + parse(payload: string): Date { + return new Date(Date.parse(payload)); + } +} diff --git a/src/parsers/index.ts b/src/parsers/index.ts new file mode 100644 index 00000000..56e3da88 --- /dev/null +++ b/src/parsers/index.ts @@ -0,0 +1,30 @@ +import { Parser } from "./parser"; +import { JSONParser } from "./json"; +import { PassThroughParser } from "./pass_through"; +import { Base64Parser } from "./base64"; +import CONSTANTS from "../constants"; + +export * from "./parser"; +export * from "./base64"; +export * from "./json"; +export * from "./date"; +export * from "./mapped"; +export * from "./pass_through"; + +const jsonParser = new JSONParser(); +const passThroughParser = new PassThroughParser(); + +export const parserByContentType: { [key: string]: Parser } = { + [CONSTANTS.MIME_JSON]: jsonParser, + [CONSTANTS.MIME_CE_JSON]: jsonParser, + [CONSTANTS.DEFAULT_CONTENT_TYPE]: jsonParser, + [CONSTANTS.DEFAULT_CE_CONTENT_TYPE]: jsonParser, + [CONSTANTS.MIME_OCTET_STREAM]: passThroughParser, +}; + +export const parserByEncoding: { [key: string]: { [key: string]: Parser } } = { + base64: { + [CONSTANTS.MIME_CE_JSON]: new JSONParser(new Base64Parser()), + [CONSTANTS.MIME_OCTET_STREAM]: new PassThroughParser(), + }, +}; diff --git a/src/parsers/json.ts b/src/parsers/json.ts new file mode 100644 index 00000000..062f9dad --- /dev/null +++ b/src/parsers/json.ts @@ -0,0 +1,30 @@ +import { Base64Parser } from "./base64"; +import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "../event/validation"; +import { Parser } from "./parser"; + +const invalidPayloadTypeError = new ValidationError("invalid payload type, allowed are: string or object"); +const nullOrUndefinedPayload = new ValidationError("null or undefined payload"); + +const parseJSON = (v: Record | string): string => (isString(v) ? JSON.parse(v as string) : v); + +export class JSONParser implements Parser { + decorator?: Base64Parser; + constructor(decorator?: Base64Parser) { + this.decorator = decorator; + } + + /** + * Parses the payload with an optional decorator + * @param {object|string} payload the JSON payload + * @return {object} the parsed JSON payload. + */ + parse(payload: Record | string): string { + if (this.decorator) { + payload = this.decorator.parse(payload); + } + + isDefinedOrThrow(payload, nullOrUndefinedPayload); + isStringOrObjectOrThrow(payload, invalidPayloadTypeError); + return parseJSON(payload); + } +} diff --git a/src/parsers/mapped.ts b/src/parsers/mapped.ts new file mode 100644 index 00000000..820e800e --- /dev/null +++ b/src/parsers/mapped.ts @@ -0,0 +1,6 @@ +import { Parser } from "./parser"; + +export interface MappedParser { + name: string; + parser: Parser; +} diff --git a/src/parsers/parser.ts b/src/parsers/parser.ts new file mode 100644 index 00000000..bf604f03 --- /dev/null +++ b/src/parsers/parser.ts @@ -0,0 +1,3 @@ +export abstract class Parser { + abstract parse(payload: Record | string): unknown; +} diff --git a/src/parsers/pass_through.ts b/src/parsers/pass_through.ts new file mode 100644 index 00000000..454fc758 --- /dev/null +++ b/src/parsers/pass_through.ts @@ -0,0 +1,7 @@ +import { Parser } from "./parser"; + +export class PassThroughParser extends Parser { + parse(payload: unknown): unknown { + return payload; + } +} diff --git a/src/transport/emitter.ts b/src/transport/emitter.ts new file mode 100644 index 00000000..316d39e1 --- /dev/null +++ b/src/transport/emitter.ts @@ -0,0 +1,76 @@ +import { CloudEvent } from "../event"; +import { emitBinary, emitStructured } from "./http"; +import { Protocol } from "."; +import { AxiosResponse } from "axios"; +import { Agent } from "http"; + +/** + * Options supplied to the Emitter when sending an event. + * In addition to url and protocol, TransportOptions may + * also accept custom options that will be passed to the + * Node.js http functions. + */ +export interface TransportOptions { + /** + * The endpoint that will receieve the event. + * @example http://cncf.example.com/receiver + */ + url?: string; + /** + * The network protocol over which the event will be sent. + * @example HTTPStructured + * @example HTTPBinary + */ + protocol?: Protocol; + + [key: string]: string | Record | Protocol | Agent | undefined; +} + +interface EmitterFunction { + (event: CloudEvent, options: TransportOptions): Promise; +} + +/** + * A class to send binary and structured CloudEvents to a remote endpoint. + * Currently, supported protocols are HTTPBinary and HTTPStructured. + * + * @see https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md + * @see https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md#13-content-modes + */ +export class Emitter { + url?: string; + protocol: Protocol; + emitter: EmitterFunction; + + constructor(options: TransportOptions = { protocol: Protocol.HTTPBinary }) { + this.protocol = options.protocol as Protocol; + this.url = options.url; + this.emitter = emitBinary; + if (this.protocol === Protocol.HTTPStructured) { + this.emitter = emitStructured; + } + } + + /** + * Sends the {CloudEvent} to an event receiver over HTTP POST + * + * @param {CloudEvent} event the CloudEvent to be sent + * @param {Object} [options] The configuration options for this event. Options + * provided will be passed along to Node.js `http.request()`. + * https://nodejs.org/api/http.html#http_http_request_options_callback + * @param {string} [options.url] The HTTP/S url that should receive this event. + * The URL is optional if one was provided when this emitter was constructed. + * In that case, it will be used as the recipient endpoint. The endpoint can + * be overridden by providing a URL here. + * @returns {Promise} Promise with an eventual response from the receiver + */ + send(event: CloudEvent, options?: TransportOptions): Promise { + options = options || {}; + options.url = options.url || this.url; + if (options.protocol != this.protocol) { + if (this.protocol === Protocol.HTTPBinary) return emitBinary(event, options); + return emitStructured(event, options); + } + return this.emitter(event, options); + } +} diff --git a/src/transport/http/binary_emitter.ts b/src/transport/http/binary_emitter.ts new file mode 100644 index 00000000..cdaa0dce --- /dev/null +++ b/src/transport/http/binary_emitter.ts @@ -0,0 +1,31 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; + +import { CloudEvent, Version } from "../../event"; +import { TransportOptions } from "../emitter"; +import { Headers, headersFor } from "./headers"; +import { asData } from "../../event/validation"; +import CONSTANTS from "../../constants"; + +/** + * Send a CloudEvent over HTTP POST to the `options.url` provided. + * @param {CloudEvent} event the event to send to the remote endpoint + * @param {TransportOptions} options options provided to the transport layer + * @returns {Promise} the HTTP response from the transport layer + */ +export async function emitBinary(event: CloudEvent, options: TransportOptions): Promise { + if (event.specversion !== Version.V1 && event.specversion !== Version.V03) { + return Promise.reject(`Unknown spec version ${event.specversion}`); + } + return emit(event, options, headersFor(event)); +} + +async function emit(event: CloudEvent, options: TransportOptions, headers: Headers): Promise { + const contentType: Headers = { [CONSTANTS.HEADER_CONTENT_TYPE]: CONSTANTS.DEFAULT_CE_CONTENT_TYPE }; + const config = { + ...options, + method: "POST", + headers: { ...contentType, ...headers, ...(options.headers as Headers) }, + data: asData(event.data, event.datacontenttype as string), + }; + return axios.request(config as AxiosRequestConfig); +} diff --git a/src/transport/http/binary_receiver.ts b/src/transport/http/binary_receiver.ts new file mode 100644 index 00000000..5be62edf --- /dev/null +++ b/src/transport/http/binary_receiver.ts @@ -0,0 +1,86 @@ +import { CloudEvent, Version } from "../.."; +import { CloudEventV1, validateV1 } from "../../event/v1"; +import { CloudEventV03, validateV03 } from "../../event/v03"; +import { Headers, validate } from "./headers"; +import { binaryParsers as v1Parsers } from "./v1/parsers"; +import { binaryParsers as v03Parsers } from "./v03/parsers"; +import { parserByContentType, MappedParser } from "../../parsers"; +import { isString, isBase64, ValidationError, isStringOrObjectOrThrow } from "../../event/validation"; +import CONSTANTS from "../../constants"; + +/** + * A class that receives binary CloudEvents over HTTP. This class can be used + * if you know that all incoming events will be using binary transport. If + * events can come as either binary or structured, use {HTTPReceiver}. + */ +export class BinaryHTTPReceiver { + /** + * The specification version of the incoming cloud event + */ + version: Version; + constructor(version: Version = Version.V1) { + this.version = version; + } + + /** + * Parses an incoming HTTP request, converting it to a {CloudEvent} + * instance if it conforms to the Cloud Event specification for this receiver. + * + * @param {Object|string} payload the HTTP request body + * @param {Object} headers the HTTP request headers + * @param {Version} version the spec version of the incoming event + * @returns {CloudEvent} an instance of CloudEvent representing the incoming request + * @throws {ValidationError} of the event does not conform to the spec + */ + parse(payload: string | Record | undefined | null, headers: Headers): CloudEvent { + if (!headers) throw new ValidationError("headers is null or undefined"); + if (payload) { + isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string")); + } + + if ( + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] && + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] !== Version.V03 && + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] !== Version.V1 + ) { + throw new ValidationError(`invalid spec version ${headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]}`); + } + + payload = isString(payload) && isBase64(payload) ? Buffer.from(payload as string, "base64").toString() : payload; + + // Clone and low case all headers names + const sanitizedHeaders = validate(headers); + + const eventObj: { [key: string]: unknown | string | Record } = {}; + const parserMap: Record = this.version === Version.V1 ? v1Parsers : v03Parsers; + + for (const header in parserMap) { + if (sanitizedHeaders[header]) { + const mappedParser: MappedParser = parserMap[header]; + eventObj[mappedParser.name] = mappedParser.parser.parse(sanitizedHeaders[header]); + delete sanitizedHeaders[header]; + } + } + + let parsedPayload; + + if (payload) { + const parser = parserByContentType[eventObj.datacontenttype as string]; + if (!parser) { + throw new ValidationError(`no parser found for content type ${eventObj.datacontenttype}`); + } + parsedPayload = parser.parse(payload); + } + + // Every unprocessed header can be an extension + for (const header in sanitizedHeaders) { + if (header.startsWith(CONSTANTS.EXTENSIONS_PREFIX)) { + eventObj[header.substring(CONSTANTS.EXTENSIONS_PREFIX.length)] = headers[header]; + } + } + + const cloudevent = new CloudEvent({ ...eventObj, data: parsedPayload } as CloudEventV1 | CloudEventV03); + this.version === Version.V1 ? validateV1(cloudevent) : validateV03(cloudevent); + return cloudevent; + } +} diff --git a/src/transport/http/headers.ts b/src/transport/http/headers.ts new file mode 100644 index 00000000..22506cfd --- /dev/null +++ b/src/transport/http/headers.ts @@ -0,0 +1,101 @@ +import { ValidationError, CloudEvent } from "../.."; +import { headerMap as v1Map } from "./v1"; +import { headerMap as v03Map } from "./v03"; +import { Version } from "../../event"; +import { MappedParser } from "../../parsers"; +import CONSTANTS from "../../constants"; + +/** + * An interface representing HTTP headers as key/value string pairs + */ +export interface Headers { + [key: string]: string; +} + +export const allowedContentTypes = [CONSTANTS.DEFAULT_CONTENT_TYPE, CONSTANTS.MIME_JSON, CONSTANTS.MIME_OCTET_STREAM]; +export const requiredHeaders = [ + CONSTANTS.CE_HEADERS.ID, + CONSTANTS.CE_HEADERS.SOURCE, + CONSTANTS.CE_HEADERS.TYPE, + CONSTANTS.CE_HEADERS.SPEC_VERSION, +]; + +/** + * Validates cloud event headers and their values + * @param {Headers} headers event transport headers for validation + * @throws {ValidationError} if the headers are invalid + * @return {boolean} true if headers are valid + */ +export function validate(headers: Headers): Headers { + const sanitizedHeaders = sanitize(headers); + + // if content-type exists, be sure it's an allowed type + const contentTypeHeader = sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE]; + const noContentType = !allowedContentTypes.includes(contentTypeHeader); + if (contentTypeHeader && noContentType) { + throw new ValidationError("invalid content type", [sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE]]); + } + + requiredHeaders + .filter((required: string) => !sanitizedHeaders[required]) + .forEach((required: string) => { + throw new ValidationError(`header '${required}' not found`); + }); + + if (!sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE]) { + sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE] = CONSTANTS.MIME_JSON; + } + + return sanitizedHeaders; +} + +/** + * Returns the HTTP headers that will be sent for this event when the HTTP transmission + * mode is "binary". Events sent over HTTP in structured mode only have a single CE header + * and that is "ce-id", corresponding to the event ID. + * @param {CloudEvent} event a CloudEvent + * @returns {Object} the headers that will be sent for the event + */ +export function headersFor(event: CloudEvent): Headers { + const headers: Headers = {}; + let headerMap: Readonly<{ [key: string]: MappedParser }>; + if (event.specversion === Version.V1) { + headerMap = v1Map; + } else { + headerMap = v03Map; + } + + // iterate over the event properties - generate a header for each + Object.getOwnPropertyNames(event).forEach((property) => { + const value = event[property]; + if (value) { + const map: MappedParser | undefined = headerMap[property] as MappedParser; + if (map) { + headers[map.name] = map.parser.parse(value as string) as string; + } else if (property !== CONSTANTS.DATA_ATTRIBUTE && property !== `${CONSTANTS.DATA_ATTRIBUTE}_base64`) { + headers[`${CONSTANTS.EXTENSIONS_PREFIX}${property}`] = value as string; + } + } + }); + // Treat time specially, since it's handled with getters and setters in CloudEvent + if (event.time) { + headers[CONSTANTS.CE_HEADERS.TIME] = event.time as string; + } + return headers; +} + +/** + * Sanitizes incoming headers by lowercasing them and potentially removing + * encoding from the content-type header. + * @param {Headers} headers HTTP headers as key/value pairs + * @returns {Headers} the sanitized headers + */ +export function sanitize(headers: Headers): Headers { + const sanitized: Headers = {}; + + Array.from(Object.keys(headers)) + .filter((header) => Object.hasOwnProperty.call(headers, header)) + .forEach((header) => (sanitized[header.toLowerCase()] = headers[header])); + + return sanitized; +} diff --git a/src/transport/http/index.ts b/src/transport/http/index.ts new file mode 100644 index 00000000..f25036dc --- /dev/null +++ b/src/transport/http/index.ts @@ -0,0 +1,2 @@ +export * from "./binary_emitter"; +export * from "./structured_emitter"; diff --git a/src/transport/http/structured_emitter.ts b/src/transport/http/structured_emitter.ts new file mode 100644 index 00000000..b147d338 --- /dev/null +++ b/src/transport/http/structured_emitter.ts @@ -0,0 +1,20 @@ +import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; +import { CloudEvent } from "../../event"; +import { TransportOptions } from "../emitter"; +import CONSTANTS from "../../constants"; + +const defaults = { + headers: { + [CONSTANTS.HEADER_CONTENT_TYPE]: CONSTANTS.DEFAULT_CE_CONTENT_TYPE, + }, +}; + +export function emitStructured(event: CloudEvent, options: TransportOptions): Promise { + const config = { + ...defaults, + ...options, + method: "POST", + data: event, + }; + return axios.request(config as AxiosRequestConfig); +} diff --git a/src/transport/http/structured_receiver.ts b/src/transport/http/structured_receiver.ts new file mode 100644 index 00000000..bf6a7ea1 --- /dev/null +++ b/src/transport/http/structured_receiver.ts @@ -0,0 +1,87 @@ +import { CloudEvent, Version } from "../.."; +import { Headers, sanitize } from "./headers"; +import { Parser, JSONParser, MappedParser } from "../../parsers"; +import { parserByContentType } from "../../parsers"; +import { structuredParsers as v1Parsers } from "./v1/parsers"; +import { structuredParsers as v03Parsers } from "./v03/parsers"; +import { isString, isBase64, ValidationError, isStringOrObjectOrThrow } from "../../event/validation"; +import { CloudEventV1, validateV1 } from "../../event/v1"; +import { CloudEventV03, validateV03 } from "../../event/v03"; +import CONSTANTS from "../../constants"; + +/** + * A utility class used to receive structured CloudEvents + * over HTTP. + * @see {StructuredReceiver} + */ +export class StructuredHTTPReceiver { + /** + * The specification version of the incoming cloud event + */ + version: Version; + constructor(version: Version = Version.V1) { + this.version = version; + } + + /** + * Creates a new CloudEvent instance based on the provided payload and headers. + * + * @param {object} payload the cloud event data payload + * @param {object} headers the HTTP headers received for this cloud event + * @returns {CloudEvent} a new CloudEvent instance for the provided headers and payload + * @throws {ValidationError} if the payload and header combination do not conform to the spec + */ + parse(payload: Record | string | undefined | null, headers: Headers): CloudEvent { + if (!payload) throw new ValidationError("payload is null or undefined"); + if (!headers) throw new ValidationError("headers is null or undefined"); + isStringOrObjectOrThrow(payload, new ValidationError("payload must be an object or a string")); + + if ( + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] && + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] != Version.V03 && + headers[CONSTANTS.CE_HEADERS.SPEC_VERSION] != Version.V1 + ) { + throw new ValidationError(`invalid spec version ${headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]}`); + } + + payload = isString(payload) && isBase64(payload) ? Buffer.from(payload as string, "base64").toString() : payload; + + // Clone and low case all headers names + const sanitizedHeaders = sanitize(headers); + + const contentType = sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE]; + const parser: Parser = contentType ? parserByContentType[contentType] : new JSONParser(); + if (!parser) throw new ValidationError(`invalid content type ${sanitizedHeaders[CONSTANTS.HEADER_CONTENT_TYPE]}`); + const incoming = { ...(parser.parse(payload) as Record) }; + + const eventObj: { [key: string]: unknown } = {}; + const parserMap: Record = this.version === Version.V1 ? v1Parsers : v03Parsers; + + for (const key in parserMap) { + const property = incoming[key]; + if (property) { + const parser: MappedParser = parserMap[key]; + eventObj[parser.name] = parser.parser.parse(property as string); + } + delete incoming[key]; + } + + // extensions are what we have left after processing all other properties + for (const key in incoming) { + eventObj[key] = incoming[key]; + } + + // ensure data content is correctly encoded + if (eventObj.data && eventObj.datacontentencoding) { + if (eventObj.datacontentencoding === CONSTANTS.ENCODING_BASE64 && !isBase64(eventObj.data)) { + throw new ValidationError("invalid payload"); + } + } + + const cloudevent = new CloudEvent(eventObj as CloudEventV1 | CloudEventV03); + + // Validates the event + this.version === Version.V1 ? validateV1(cloudevent) : validateV03(cloudevent); + return cloudevent; + } +} diff --git a/src/transport/http/v03/headers.ts b/src/transport/http/v03/headers.ts new file mode 100644 index 00000000..e2d79d64 --- /dev/null +++ b/src/transport/http/v03/headers.ts @@ -0,0 +1,23 @@ +import { PassThroughParser, MappedParser } from "../../../parsers"; +import CONSTANTS from "../../../constants"; + +const passThrough = new PassThroughParser(); +function parser(header: string, parser = passThrough): MappedParser { + return { name: header, parser }; +} + +/** + * A utility Map used to retrieve the header names for a CloudEvent + * using the CloudEvent getter function. + */ +export const headerMap: Readonly<{ [key: string]: MappedParser }> = Object.freeze({ + [CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE]: parser(CONSTANTS.HEADER_CONTENT_TYPE), + [CONSTANTS.CE_ATTRIBUTES.SUBJECT]: parser(CONSTANTS.CE_HEADERS.SUBJECT), + [CONSTANTS.CE_ATTRIBUTES.TYPE]: parser(CONSTANTS.CE_HEADERS.TYPE), + [CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]: parser(CONSTANTS.CE_HEADERS.SPEC_VERSION), + [CONSTANTS.CE_ATTRIBUTES.SOURCE]: parser(CONSTANTS.CE_HEADERS.SOURCE), + [CONSTANTS.CE_ATTRIBUTES.ID]: parser(CONSTANTS.CE_HEADERS.ID), + [CONSTANTS.CE_ATTRIBUTES.TIME]: parser(CONSTANTS.CE_HEADERS.TIME), + [CONSTANTS.STRUCTURED_ATTRS_03.CONTENT_ENCODING]: parser(CONSTANTS.BINARY_HEADERS_03.CONTENT_ENCODING), + [CONSTANTS.STRUCTURED_ATTRS_03.SCHEMA_URL]: parser(CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL), +}); diff --git a/src/transport/http/v03/index.ts b/src/transport/http/v03/index.ts new file mode 100644 index 00000000..c871fea5 --- /dev/null +++ b/src/transport/http/v03/index.ts @@ -0,0 +1 @@ +export * from "./headers"; diff --git a/src/transport/http/v03/parsers.ts b/src/transport/http/v03/parsers.ts new file mode 100644 index 00000000..04c3a8c3 --- /dev/null +++ b/src/transport/http/v03/parsers.ts @@ -0,0 +1,34 @@ +import { MappedParser, DateParser, PassThroughParser } from "../../../parsers"; +import CONSTANTS from "../../../constants"; + +const passThrough = new PassThroughParser(); +function parser(name: string, parser = passThrough): MappedParser { + return { name: name, parser: parser }; +} + +const binaryParsers: Record = Object.freeze({ + [CONSTANTS.CE_HEADERS.TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.TYPE), + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: parser(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION), + [CONSTANTS.CE_HEADERS.SOURCE]: parser(CONSTANTS.CE_ATTRIBUTES.SOURCE), + [CONSTANTS.CE_HEADERS.ID]: parser(CONSTANTS.CE_ATTRIBUTES.ID), + [CONSTANTS.CE_HEADERS.TIME]: parser(CONSTANTS.CE_ATTRIBUTES.TIME, new DateParser()), + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: parser(CONSTANTS.STRUCTURED_ATTRS_03.SCHEMA_URL), + [CONSTANTS.CE_HEADERS.SUBJECT]: parser(CONSTANTS.CE_ATTRIBUTES.SUBJECT), + [CONSTANTS.BINARY_HEADERS_03.CONTENT_ENCODING]: parser(CONSTANTS.STRUCTURED_ATTRS_03.CONTENT_ENCODING), + [CONSTANTS.HEADER_CONTENT_TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE), +}); + +const structuredParsers: Record = Object.freeze({ + [CONSTANTS.CE_ATTRIBUTES.TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.TYPE), + [CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]: parser(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION), + [CONSTANTS.CE_ATTRIBUTES.SOURCE]: parser(CONSTANTS.CE_ATTRIBUTES.SOURCE), + [CONSTANTS.CE_ATTRIBUTES.ID]: parser(CONSTANTS.CE_ATTRIBUTES.ID), + [CONSTANTS.CE_ATTRIBUTES.TIME]: parser(CONSTANTS.CE_ATTRIBUTES.TIME, new DateParser()), + [CONSTANTS.STRUCTURED_ATTRS_03.SCHEMA_URL]: parser(CONSTANTS.STRUCTURED_ATTRS_03.SCHEMA_URL), + [CONSTANTS.STRUCTURED_ATTRS_03.CONTENT_ENCODING]: parser(CONSTANTS.STRUCTURED_ATTRS_03.CONTENT_ENCODING), + [CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE), + [CONSTANTS.CE_ATTRIBUTES.SUBJECT]: parser(CONSTANTS.CE_ATTRIBUTES.SUBJECT), + [CONSTANTS.CE_ATTRIBUTES.DATA]: parser(CONSTANTS.CE_ATTRIBUTES.DATA), +}); + +export { binaryParsers, structuredParsers }; diff --git a/src/transport/http/v1/headers.ts b/src/transport/http/v1/headers.ts new file mode 100644 index 00000000..d527d279 --- /dev/null +++ b/src/transport/http/v1/headers.ts @@ -0,0 +1,22 @@ +import { MappedParser, PassThroughParser } from "../../../parsers"; +import CONSTANTS from "../../../constants"; + +const passThrough = new PassThroughParser(); +function parser(header: string, parser = passThrough): MappedParser { + return { name: header, parser }; +} + +/** + * A utility Map used to retrieve the header names for a CloudEvent + * using the CloudEvent getter function. + */ +export const headerMap: Readonly<{ [key: string]: MappedParser }> = Object.freeze({ + [CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE]: parser(CONSTANTS.HEADER_CONTENT_TYPE), + [CONSTANTS.CE_ATTRIBUTES.SUBJECT]: parser(CONSTANTS.CE_HEADERS.SUBJECT), + [CONSTANTS.CE_ATTRIBUTES.TYPE]: parser(CONSTANTS.CE_HEADERS.TYPE), + [CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]: parser(CONSTANTS.CE_HEADERS.SPEC_VERSION), + [CONSTANTS.CE_ATTRIBUTES.SOURCE]: parser(CONSTANTS.CE_HEADERS.SOURCE), + [CONSTANTS.CE_ATTRIBUTES.ID]: parser(CONSTANTS.CE_HEADERS.ID), + [CONSTANTS.CE_ATTRIBUTES.TIME]: parser(CONSTANTS.CE_HEADERS.TIME), + [CONSTANTS.STRUCTURED_ATTRS_1.DATA_SCHEMA]: parser(CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA), +}); diff --git a/src/transport/http/v1/index.ts b/src/transport/http/v1/index.ts new file mode 100644 index 00000000..c871fea5 --- /dev/null +++ b/src/transport/http/v1/index.ts @@ -0,0 +1 @@ +export * from "./headers"; diff --git a/src/transport/http/v1/parsers.ts b/src/transport/http/v1/parsers.ts new file mode 100644 index 00000000..907df37f --- /dev/null +++ b/src/transport/http/v1/parsers.ts @@ -0,0 +1,35 @@ +import { PassThroughParser, DateParser, MappedParser } from "../../../parsers"; +import CONSTANTS from "../../../constants"; + +const passThrough = new PassThroughParser(); + +function parser(name: string, parser = passThrough): MappedParser { + return { name: name, parser: parser }; +} + +const binaryParsers: Record = Object.freeze({ + [CONSTANTS.CE_HEADERS.TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.TYPE), + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: parser(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION), + [CONSTANTS.CE_HEADERS.SOURCE]: parser(CONSTANTS.CE_ATTRIBUTES.SOURCE), + [CONSTANTS.CE_HEADERS.ID]: parser(CONSTANTS.CE_ATTRIBUTES.ID), + [CONSTANTS.CE_HEADERS.TIME]: parser(CONSTANTS.CE_ATTRIBUTES.TIME, new DateParser()), + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: parser(CONSTANTS.STRUCTURED_ATTRS_1.DATA_SCHEMA), + [CONSTANTS.CE_HEADERS.SUBJECT]: parser(CONSTANTS.CE_ATTRIBUTES.SUBJECT), + [CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE), + [CONSTANTS.HEADER_CONTENT_TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE), +}); + +const structuredParsers: Record = Object.freeze({ + [CONSTANTS.CE_ATTRIBUTES.TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.TYPE), + [CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]: parser(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION), + [CONSTANTS.CE_ATTRIBUTES.SOURCE]: parser(CONSTANTS.CE_ATTRIBUTES.SOURCE), + [CONSTANTS.CE_ATTRIBUTES.ID]: parser(CONSTANTS.CE_ATTRIBUTES.ID), + [CONSTANTS.CE_ATTRIBUTES.TIME]: parser(CONSTANTS.CE_ATTRIBUTES.TIME, new DateParser()), + [CONSTANTS.STRUCTURED_ATTRS_1.DATA_SCHEMA]: parser(CONSTANTS.STRUCTURED_ATTRS_1.DATA_SCHEMA), + [CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE]: parser(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE), + [CONSTANTS.CE_ATTRIBUTES.SUBJECT]: parser(CONSTANTS.CE_ATTRIBUTES.SUBJECT), + [CONSTANTS.CE_ATTRIBUTES.DATA]: parser(CONSTANTS.CE_ATTRIBUTES.DATA), + [CONSTANTS.STRUCTURED_ATTRS_1.DATA_BASE64]: parser(CONSTANTS.STRUCTURED_ATTRS_1.DATA_BASE64), +}); + +export { structuredParsers, binaryParsers }; diff --git a/src/transport/index.ts b/src/transport/index.ts new file mode 100644 index 00000000..8a077285 --- /dev/null +++ b/src/transport/index.ts @@ -0,0 +1,6 @@ +export * from "./emitter"; +export * from "./receiver"; +export * as v1Headers from "./http/v1"; +export * as v03Headers from "./http/v03"; +export * as http from "./http/headers"; +export * from "./protocols"; diff --git a/src/transport/protocols.ts b/src/transport/protocols.ts new file mode 100644 index 00000000..4b46cad1 --- /dev/null +++ b/src/transport/protocols.ts @@ -0,0 +1,8 @@ +/** + * An enum representing the transport protocols for an event + */ +export const enum Protocol { + HTTPBinary, + HTTPStructured, + HTTP, +} diff --git a/src/transport/receiver.ts b/src/transport/receiver.ts new file mode 100644 index 00000000..996d5469 --- /dev/null +++ b/src/transport/receiver.ts @@ -0,0 +1,122 @@ +import { Headers, sanitize } from "./http/headers"; +import { CloudEvent, Version, ValidationError } from ".."; +import { BinaryHTTPReceiver as BinaryReceiver } from "./http/binary_receiver"; +import { StructuredHTTPReceiver as StructuredReceiver } from "./http/structured_receiver"; +import { CloudEventV03 } from "../event/v03"; +import { CloudEventV1 } from "../event/v1"; +import { Protocol } from "./protocols"; +import CONSTANTS from "../constants"; + +/** + * An enum representing the two HTTP transport modes, binary and structured + */ +export enum Mode { + BINARY = "binary", + STRUCTURED = "structured", +} + +/** + * A class to receive a CloudEvent from an HTTP POST request. + */ +export class Receiver { + protocol: Protocol; + receivers: { + v1: { + structured: StructuredReceiver; + binary: BinaryReceiver; + [key: string]: unknown; + }; + v03: { + structured: StructuredReceiver; + binary: BinaryReceiver; + [key: string]: unknown; + }; + }; + + /** + * Create an instance of an HTTPReceiver to accept incoming CloudEvents. + * @param {Protocol} protocol the transport protocol - currently only Protocol.HTTP is supported + */ + constructor(protocol: Protocol = Protocol.HTTP) { + // currently unused, but reserved for future protocol implementations + this.protocol = protocol; + this.receivers = { + v1: { + structured: new StructuredReceiver(Version.V1), + binary: new BinaryReceiver(Version.V1), + }, + v03: { + structured: new StructuredReceiver(Version.V03), + binary: new BinaryReceiver(Version.V03), + }, + }; + } + /** + * Acceptor for an incoming HTTP CloudEvent POST. Can process + * binary and structured incoming CloudEvents. + * + * @param {Object} headers HTTP headers keyed by header name ("Content-Type") + * @param {Object|JSON} body The body of the HTTP request + * @return {CloudEvent} A new {CloudEvent} instance + */ + accept( + headers: Headers, + body: string | Record | CloudEventV1 | CloudEventV03 | undefined | null, + ): CloudEvent { + const cleanHeaders: Headers = sanitize(headers); + const mode: Mode = getMode(cleanHeaders); + const version = getVersion(mode, cleanHeaders, body); + switch (version) { + case Version.V1: + return this.receivers.v1[mode].parse(body, headers); + case Version.V03: + return this.receivers.v03[mode].parse(body, headers); + default: + console.error(`Unknown spec version ${version}. Default to ${Version.V1}`); + return this.receivers.v1[mode].parse(body, headers); + } + } +} + +/** + * Determines the HTTP transport mode (binary or structured) based + * on the incoming HTTP headers. + * @param {Headers} headers the incoming HTTP headers + * @returns {Mode} the transport mode + */ +function getMode(headers: Headers): Mode { + const contentType = headers[CONSTANTS.HEADER_CONTENT_TYPE]; + if (contentType && contentType.startsWith(CONSTANTS.MIME_CE)) { + return Mode.STRUCTURED; + } + if (headers[CONSTANTS.CE_HEADERS.ID]) { + return Mode.BINARY; + } + throw new ValidationError("no cloud event detected"); +} + +/** + * Determines the version of an incoming CloudEvent based on the + * HTTP headers or HTTP body, depending on transport mode. + * @param {Mode} mode the HTTP transport mode + * @param {Headers} headers the incoming HTTP headers + * @param {Record} body the HTTP request body + * @returns {Version} the CloudEvent specification version + */ +function getVersion( + mode: Mode, + headers: Headers, + body: string | Record | CloudEventV03 | CloudEventV1 | undefined | null, +) { + if (mode === Mode.BINARY) { + // Check the headers for the version + const versionHeader = headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]; + if (versionHeader) { + return versionHeader; + } + } else { + // structured mode - the version is in the body + return typeof body === "string" ? JSON.parse(body).specversion : (body as CloudEvent).specversion; + } + return Version.V1; +} diff --git a/test/bindings/http/promiscuous_receiver_test.js b/test/bindings/http/promiscuous_receiver_test.js deleted file mode 100644 index e5509166..00000000 --- a/test/bindings/http/promiscuous_receiver_test.js +++ /dev/null @@ -1,90 +0,0 @@ -const { expect } = require("chai"); -const { CloudEvent, HTTPReceiver } = require("../../../index.js"); -const constants = require("../../../lib/bindings/http/constants.js"); - -const receiver = new HTTPReceiver(); -const id = "1234"; -const type = "org.cncf.cloudevents.test"; -const source = "urn:event:from:myapi/resourse/123"; -const data = { - lunch: "sushi" -}; - -describe("HTTP Transport Binding Receiver for CloudEvents", () => { - describe("V1", () => { - const specversion = "1.0"; - - it("Structured data returns a CloudEvent", () => { - const payload = { - id, - type, - source, - data, - specversion - }; - - const headers = { - [constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON - }; - - const event = receiver.accept(headers, payload); - validateEvent(event, specversion); - }); - - it("Binary data returns a CloudEvent", () => { - const headers = { - [constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE, - [constants.DEFAULT_SPEC_VERSION_HEADER]: specversion, - [constants.BINARY_HEADERS_1.ID]: id, - [constants.BINARY_HEADERS_1.TYPE]: type, - [constants.BINARY_HEADERS_1.SOURCE]: source - }; - - const event = receiver.accept(headers, data); - validateEvent(event, specversion); - }); - }); - - describe("V03", () => { - const specversion = "0.3"; - - it("Structured data returns a CloudEvent", () => { - const payload = { - id, - type, - source, - data, - specversion - }; - - const headers = { - [constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON - }; - - const event = receiver.accept(headers, payload); - validateEvent(event, specversion); - }); - - it("Binary data returns a CloudEvent", () => { - const headers = { - [constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE, - [constants.DEFAULT_SPEC_VERSION_HEADER]: specversion, - [constants.BINARY_HEADERS_03.ID]: id, - [constants.BINARY_HEADERS_03.TYPE]: type, - [constants.BINARY_HEADERS_03.SOURCE]: source - }; - - const event = receiver.accept(headers, data); - validateEvent(event, specversion); - }); - }); -}); - -function validateEvent(event, specversion) { - expect(event instanceof CloudEvent).to.equal(true); - expect(event.getId()).to.equal(id); - expect(event.getType()).to.equal(type); - expect(event.getSource()).to.equal(source); - expect(event.getData()).to.deep.equal(data); - expect(event.getSpecversion()).to.equal(specversion); -} diff --git a/test/bindings/http/receiver_binary_0_3_tests.js b/test/bindings/http/receiver_binary_0_3_tests.js deleted file mode 100644 index cbddc1d2..00000000 --- a/test/bindings/http/receiver_binary_0_3_tests.js +++ /dev/null @@ -1,448 +0,0 @@ -const expect = require("chai").expect; - -const HTTPBinaryReceiver = - require("../../../lib/bindings/http/receiver_binary_0_3.js"); -const { - BINARY_HEADERS_03, - SPEC_V03, - HEADER_CONTENT_TYPE -} = require("../../../lib/bindings/http/constants.js"); - -const receiver = new HTTPBinaryReceiver(); - -describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => { - describe("Check", () => { - it("Throw error when payload arg is null or undefined", () => { - // setup - const payload = null; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload is null or undefined"); - }); - - it("Throw error when attributes arg is null or undefined", () => { - // setup - const payload = {}; - const attributes = null; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("attributes is null or undefined"); - }); - - it("Throw error when payload is not an object or string", () => { - // setup - const payload = 1.2; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload must be an object or a string"); - }); - - it("Throw error when headers has no 'ce-type'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-type' not found"); - }); - - it("Throw error when headers has no 'ce-specversion'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-specversion' not found"); - }); - - it("Throw error when headers has no 'ce-source'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-source' not found"); - }); - - it("Throw error when headers has no 'ce-id'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_03.SOURCE]: "source", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-id' not found"); - }); - - it("Throw error when spec is not 0.3", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "0.2", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.parse.bind(receiver, payload, attributes)) - .to.throw("invalid spec version"); - }); - - it("Throw error when the content-type is invalid", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "text/html" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("invalid content type"); - }); - - it("No error when all required headers are in place", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - - it("No error when content-type is unspecified", () => { - const payload = {}; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - }); - - describe("Parse", () => { - it("CloudEvent contains 'type'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getType()) - .to.equal("type"); - }); - - it("CloudEvent contains 'specversion'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getSpecversion()) - .to.equal(SPEC_V03); - }); - - it("CloudEvent contains 'source'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getSource()) - .to.equal("/source"); - }); - - it("CloudEvent contains 'id'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getId()) - .to.equal("id"); - }); - - it("CloudEvent contains 'time'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getTime()) - .to.equal("2019-06-16T11:42:00.000Z"); - }); - - it("CloudEvent contains 'schemaurl'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getSchemaurl()) - .to.equal("http://schema.registry/v1"); - }); - - it("CloudEvent contains 'datacontenttype' (application/json)", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getDataContentType()) - .to.equal("application/json"); - }); - - it("CloudEvent contains 'datacontenttype' (application/octet-stream)", - () => { - // setup - const payload = "The payload is binary data"; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/octet-stream" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getDataContentType()) - .to.equal("application/octet-stream"); - }); - - it("CloudEvent contains 'data' (application/json)", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getData()) - .to.deep.equal(payload); - }); - - it("CloudEvent contains 'data' (application/octet-stream)", () => { - // setup - const payload = "The payload is binary data"; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "/source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/octet-stream" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getData()) - .to.deep.equal(payload); - }); - - it("No error when all attributes are in place", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual) - .to.be.an("object"); - - expect(actual) - .to.have.property("format"); - }); - - it("Should accept 'extension1'", () => { - // setup - const extension1 = "mycuston-ext1"; - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: SPEC_V03, - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json", - [`${[BINARY_HEADERS_03.EXTENSIONS_PREFIX]}extension1`]: extension1 - }; - - // act - const actual = receiver.parse(payload, attributes); - const actualExtensions = actual.getExtensions(); - - // assert - expect(actualExtensions.extension1) - .to.equal(extension1); - }); - }); -}); diff --git a/test/bindings/http/receiver_binary_1_tests.js b/test/bindings/http/receiver_binary_1_tests.js deleted file mode 100644 index 4be6900c..00000000 --- a/test/bindings/http/receiver_binary_1_tests.js +++ /dev/null @@ -1,476 +0,0 @@ -const expect = require("chai").expect; -const { asBase64 } = require("../../../lib/utils/fun.js"); -const { - BINARY_HEADERS_1, - SPEC_V1, - HEADER_CONTENT_TYPE -} = require("../../../lib/bindings/http/constants.js"); - -const HTTPBinaryReceiver = - require("../../../lib/bindings/http/receiver_binary_1.js"); - -const receiver = new HTTPBinaryReceiver(); - -describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => { - describe("Check", () => { - it("Throw error when payload arg is null or undefined", () => { - // setup - const payload = null; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload is null or undefined"); - }); - - it("Throw error when attributes arg is null or undefined", () => { - // setup - const payload = {}; - const attributes = null; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("attributes is null or undefined"); - }); - - it("Throw error when payload is not an object or string", () => { - // setup - const payload = 1.2; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload must be an object or a string"); - }); - - it("Throw error when headers has no 'ce-type'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-type' not found"); - }); - - it("Throw error when headers has no 'ce-specversion'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-specversion' not found"); - }); - - it("Throw error when headers has no 'ce-source'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-source' not found"); - }); - - it("Throw error when headers has no 'ce-id'", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_1.SOURCE]: "source", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("header 'ce-id' not found"); - }); - - it("Throw error when spec is not 1.0", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: "0.2", - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.parse.bind(receiver, payload, attributes)) - .to.throw("invalid spec version"); - }); - - it("Throw error when the content-type is invalid", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: "specversion", - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "text/html" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("invalid content type"); - }); - - it("No error when content-type is unspecified", () => { - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - - it("No error when all required headers are in place", () => { - // setup - const payload = {}; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - }); - - describe("Parse", () => { - it("CloudEvent contains 'type'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getType()) - .to.equal("type"); - }); - - it("CloudEvent contains 'specversion'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getSpecversion()) - .to.equal(SPEC_V1); - }); - - it("CloudEvent contains 'source'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getSource()) - .to.equal("/source"); - }); - - it("CloudEvent contains 'id'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getId()) - .to.equal("id"); - }); - - it("CloudEvent contains 'time'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getTime()) - .to.equal("2019-06-16T11:42:00.000Z"); - }); - - it("CloudEvent contains 'dataschema'", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getDataschema()) - .to.equal("http://schema.registry/v1"); - }); - - it("CloudEvent contains 'contenttype' (application/json)", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getDataContentType()) - .to.equal("application/json"); - }); - - it("CloudEvent contains 'contenttype' (application/octet-stream)", () => { - // setup - const payload = "The payload is binary data"; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/octet-stream" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getDataContentType()) - .to.equal("application/octet-stream"); - }); - - it("CloudEvent contains 'data' (application/json)", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getData()) - .to.deep.equal(payload); - }); - - it("CloudEvent contains 'data' (application/octet-stream)", () => { - // setup - const payload = "The payload is binary data"; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/octet-stream" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getData()) - .to.deep.equal(payload); - }); - - it("The content of 'data' is base64 for binary", () => { - // setup - const expected = { - data: "dataString" - }; - - const bindata = Uint32Array - .from(JSON.stringify(expected), (c) => c.codePointAt(0)); - const payload = asBase64(bindata); - - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "/source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual.getData()) - .to.deep.equal(expected); - }); - - it("No error when all attributes are in place", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - // act - const actual = receiver.parse(payload, attributes); - - // assert - expect(actual) - .to.be.an("object"); - - expect(actual) - .to.have.property("format"); - }); - - it("Should accept 'extension1'", () => { - // setup - const extension1 = "mycustom-ext1"; - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_1.TYPE]: "type", - [BINARY_HEADERS_1.SPEC_VERSION]: SPEC_V1, - [BINARY_HEADERS_1.SOURCE]: "source", - [BINARY_HEADERS_1.ID]: "id", - [BINARY_HEADERS_1.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json", - [`${[BINARY_HEADERS_1.EXTENSIONS_PREFIX]}extension1`]: extension1 - }; - - // act - const actual = receiver.parse(payload, attributes); - const actualExtensions = actual.getExtensions(); - - // assert - expect(actualExtensions.extension1) - .to.equal(extension1); - }); - }); -}); diff --git a/test/bindings/http/receiver_structured_0_3_test.js b/test/bindings/http/receiver_structured_0_3_test.js deleted file mode 100644 index a3742403..00000000 --- a/test/bindings/http/receiver_structured_0_3_test.js +++ /dev/null @@ -1,219 +0,0 @@ -const expect = require("chai").expect; -const v03 = require("../../../v03/index.js"); - -const HTTPStructuredReceiver = - require("../../../lib/bindings/http/receiver_structured_0_3.js"); - -const receiver = new HTTPStructuredReceiver(); - -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resourse/123"; -const now = new Date(); -const schemaurl = "http://cloudevents.io/schema.json"; - -const ceContentType = "application/json"; - -const data = { - foo: "bar" -}; - -const ext1Name = "extension1"; -const ext1Value = "foobar"; -const ext2Name = "extension2"; -const ext2Value = "acme"; - -describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => { - describe("Check", () => { - it("Throw error when payload arg is null or undefined", () => { - // setup - const payload = null; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload is null or undefined"); - }); - - it("Throw error when attributes arg is null or undefined", () => { - // setup - const payload = {}; - const attributes = null; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("attributes is null or undefined"); - }); - - it("Throw error when payload is not an object or string", () => { - // setup - const payload = 1.0; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload must be an object or string"); - }); - - it("Throw error when the content-type is invalid", () => { - // setup - const payload = {}; - const attributes = { - "Content-Type": "text/html" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("invalid content type"); - }); - - it("Throw error data content encoding is base64, but 'data' is not", - () => { - // setup - const payload = v03.event() - .type(type) - .source(source) - .dataContentType("text/plain") - .dataContentEncoding("base64") - .time(now) - .schemaurl(schemaurl) - .data("No base 64 value") - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value) - .toString(); - - const attributes = { - "Content-Type": "application/cloudevents+json" - }; - - // act and assert - expect(receiver.parse.bind(receiver, payload, attributes)) - .to.throw("invalid payload"); - }); - - it("No error when all required stuff are in place", () => { - // setup - const payload = {}; - const attributes = { - "Content-Type": "application/cloudevents+json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - }); - - describe("Parse", () => { - it("Throw error when the event does not follow the spec", () => { - // setup - const payload = {}; - const attributes = { - "Content-Type": "application/cloudevents+json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - }); - - describe("Parse", () => { - it("Throw error when the event does not follow the spec", () => { - // setup - const payload = - v03.event() - .type(type) - .source(source) - .time(now) - .schemaurl(schemaurl) - .data(data) - .toString(); - - const headers = { - "Content-Type": "application/cloudevents+xml" - }; - - // act and assert - expect(receiver.parse.bind(receiver, payload, headers)) - .to.throw("invalid content type"); - }); - - it("Should accept event that follows the spec", () => { - // setup - const id = "id-x0dk"; - const payload = v03.event() - .type(type) - .source(source) - .id(id) - .dataContentType(ceContentType) - .time(now) - .schemaurl(schemaurl) - .data(data) - .toString(); - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - - // assert - expect(actual) - .to.be.an("object"); - - expect(actual) - .to.have.property("format"); - - expect(actual.getId()) - .to.equals(id); - }); - - it("Should accept 'extension1'", () => { - // setup - const extension1 = "mycuston-ext1"; - const payload = v03.event() - .type(type) - .source(source) - .dataContentType(ceContentType) - .time(now) - .schemaurl(schemaurl) - .data(data) - .addExtension("extension1", extension1) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - const actualExtensions = actual.getExtensions(); - - // assert - expect(actualExtensions.extension1) - .to.equal(extension1); - }); - - it("Should parse 'data' stringfied json to json object", () => { - // setup - const payload = v03.event() - .type(type) - .source(source) - .dataContentType(ceContentType) - .time(now) - .schemaurl(schemaurl) - .data(JSON.stringify(data)) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - - // assert - expect(actual.getData()).to.deep.equal(data); - }); - }); -}); diff --git a/test/bindings/http/receiver_structured_1_test.js b/test/bindings/http/receiver_structured_1_test.js deleted file mode 100644 index 2a5e9ee4..00000000 --- a/test/bindings/http/receiver_structured_1_test.js +++ /dev/null @@ -1,202 +0,0 @@ -const expect = require("chai").expect; -const v1 = require("../../../v1/index.js"); -const { CloudEvent } = require("../../../index.js"); - -const { asBase64 } = require("../../../lib/utils/fun.js"); - -const HTTPStructuredReceiver = - require("../../../lib/bindings/http/receiver_structured_1.js"); - -const receiver = new HTTPStructuredReceiver(); - -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resource/123"; -const now = new Date(); -const dataschema = "http://cloudevents.io/schema.json"; - -const ceContentType = "application/json"; - -const data = { - foo: "bar" -}; - -describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", - () => { - describe("Check", () => { - it("Throw error when payload arg is null or undefined", () => { - // setup - const payload = null; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload is null or undefined"); - }); - - it("Throw error when attributes arg is null or undefined", () => { - // setup - const payload = {}; - const attributes = null; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("attributes is null or undefined"); - }); - - it("Throw error when payload is not an object or string", () => { - // setup - const payload = 1.0; - const attributes = {}; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("payload must be an object or string"); - }); - - it("Throw error when the content-type is invalid", () => { - // setup - const payload = {}; - const attributes = { - "Content-Type": "text/html" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.throw("invalid content type"); - }); - - it("No error when all required stuff are in place", () => { - // setup - const payload = {}; - const attributes = { - "Content-Type": "application/cloudevents+json" - }; - - // act and assert - expect(receiver.check.bind(receiver, payload, attributes)) - .to.not.throw(); - }); - }); - - describe("Parse", () => { - it("Throw error when the event does not follow the spec", () => { - // setup - const payload = - new CloudEvent() - .type(type) - .source(source) - .time(now) - .data(data) - .toString(); - - const headers = { - "Content-Type": "application/cloudevents+xml" - }; - - // act and assert - expect(receiver.parse.bind(receiver, payload, headers)) - .to.throw("invalid content type"); - }); - - it("Should accept event that follows the spec", () => { - // setup - const id = "id-x0dk"; - const payload = v1.event() - .type(type) - .source(source) - .id(id) - .dataContentType(ceContentType) - .time(now) - .dataschema(dataschema) - .data(data) - .toString(); - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - - // assert - expect(actual) - .to.be.an("object"); - - expect(actual) - .to.have.property("format"); - - expect(actual.getId()) - .to.equals(id); - }); - - it("Should accept 'extension1'", () => { - // setup - const extension1 = "mycustom-ext1"; - const payload = v1.event() - .type(type) - .source(source) - .dataContentType(ceContentType) - .time(now) - .dataschema(dataschema) - .data(data) - .addExtension("extension1", extension1) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - const actualExtensions = actual.getExtensions(); - - // assert - expect(actualExtensions.extension1) - .to.equal(extension1); - }); - - it("Should parse 'data' stringified json to json object", () => { - // setup - const payload = v1.event() - .type(type) - .source(source) - .dataContentType(ceContentType) - .time(now) - .dataschema(dataschema) - .data(JSON.stringify(data)) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(payload, headers); - - // assert - expect(actual.getData()).to.deep.equal(data); - }); - - it("Should maps 'data_base64' to 'data' attribute", () => { - // setup - const bindata = Uint32Array - .from(JSON.stringify(data), (c) => c.codePointAt(0)); - const expected = asBase64(bindata); - const payload = v1.event() - .type(type) - .source(source) - .dataContentType(ceContentType) - .data(bindata) - .format(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - // act - const actual = receiver.parse(JSON.stringify(payload), headers); - - // assert - expect(actual.getData()).to.equal(expected); - }); - }); - }); diff --git a/test/bindings/http/unmarshaller_0_3_tests.js b/test/bindings/http/unmarshaller_0_3_tests.js deleted file mode 100644 index bee22b98..00000000 --- a/test/bindings/http/unmarshaller_0_3_tests.js +++ /dev/null @@ -1,214 +0,0 @@ -const expect = require("chai").expect; -const Unmarshaller = require("../../../lib/bindings/http/unmarshaller_0_3.js"); -const { CloudEvent } = require("../../../index.js"); -const v03 = require("../../../v03/index.js"); - -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resourse/123"; -const now = new Date(); -const schemaurl = "http://cloudevents.io/schema.json"; -const subject = "subject.ext"; -const { - BINARY_HEADERS_03, - HEADER_CONTENT_TYPE -} = require("../../../lib/bindings/http/constants.js"); - -const ceContentType = "application/json"; - -const data = { - foo: "bar" -}; - -const un = new Unmarshaller(); - -describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => { - it("Throw error when payload is null", () => { - expect(() => un.unmarshall(null)).to.throw("payload is null or undefined"); - }); - - it("Throw error when headers is null", () => { - expect(() => un.unmarshall({})).to.throw("headers is null or undefined"); - expect(() => un.unmarshall({}, null)).to - .throw("headers is null or undefined"); - }); - - it("Throw error when there is no content-type header", () => { - expect(() => un.unmarshall({}, {})).to - .throw("content-type header not found"); - }); - - it("Throw error when content-type is not allowed", () => { - const headers = { - "content-type": "text/xml" - }; - expect(() => un.unmarshall({}, headers)).to - .throw("content type not allowed"); - }); - - describe("Structured", () => { - it("Throw error when has not allowed mime", () => { - // setup - const headers = { - "content-type": "application/cloudevents+zip" - }; - - // act and assert - expect(() => un.unmarshall({}, headers)).to - .throw("structured+type not allowed"); - }); - - it("Throw error when the event does not follow the spec 0.3", () => { - const payload = - new CloudEvent(v03.Spec) - .time(now) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - expect(() => un.unmarshall(payload, headers)).to - .throw(TypeError); - }); - - it("Should accept event that follow the spec 0.3", () => { - const payload = - new CloudEvent(v03.Spec) - .type(type) - .data(data) - .source(source) - .dataContentType(ceContentType) - .time(now) - .schemaurl(schemaurl) - .subject(subject) - .format(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - const event = un.unmarshall(payload, headers); - expect(event instanceof CloudEvent).to.equal(true); - }); - - it("Should parse 'data' stringfied json to json object", () => { - // setup - const payload = - new CloudEvent(v03.Spec) - .type(type) - .source(source) - .dataContentType(ceContentType) - .time(now) - .schemaurl(schemaurl) - .subject(subject) - .data(JSON.stringify(data)) - .toString(); - - const headers = { - "content-type": "application/cloudevents+json" - }; - - const event = un.unmarshall(payload, headers); - expect(event.getData()).to.deep.equal(data); - }); - }); - - describe("Binary", () => { - it("Throw error when has not allowed mime", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "0.3", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "text/html" - }; - - expect(() => un.unmarshall(payload, attributes)).to - .throw("content type not allowed"); - }); - - it("Throw error when the event does not follow the spec 0.3", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - "CE-CloudEventsVersion": "0.1", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - expect(() => un.unmarshall(payload, attributes)).to - .throw("header 'ce-specversion' not found"); - }); - - it("No error when all attributes are in place", () => { - // setup - const payload = { - data: "dataString" - }; - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "0.3", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json" - }; - - const event = un.unmarshall(payload, attributes); - expect(event instanceof CloudEvent).to.equal(true); - }); - - it("Throw error when 'ce-datacontentencoding' is not allowed", () => { - // setup - const payload = "eyJtdWNoIjoid293In0="; - - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "0.3", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json", - [BINARY_HEADERS_03.CONTENT_ENCONDING]: "binary" - }; - - expect(() => un.unmarshall(payload, attributes)).to - .throw("unsupported datacontentencoding"); - }); - - it("No error when 'ce-datacontentencoding' is base64", () => { - // setup - const payload = "eyJtdWNoIjoid293In0="; - const expected = { - much: "wow" - }; - - const attributes = { - [BINARY_HEADERS_03.TYPE]: "type", - [BINARY_HEADERS_03.SPEC_VERSION]: "0.3", - [BINARY_HEADERS_03.SOURCE]: "source", - [BINARY_HEADERS_03.ID]: "id", - [BINARY_HEADERS_03.TIME]: "2019-06-16T11:42:00Z", - [BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", - [HEADER_CONTENT_TYPE]: "application/json", - [BINARY_HEADERS_03.CONTENT_ENCONDING]: "base64" - }; - - const event = un.unmarshall(payload, attributes); - expect(event.getData()).to.deep.equal(expected); - }); - }); -}); diff --git a/test/conformance/steps.ts b/test/conformance/steps.ts new file mode 100644 index 00000000..c6d267aa --- /dev/null +++ b/test/conformance/steps.ts @@ -0,0 +1,69 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { assert } from "chai"; +import { Given, When, Then, World } from "cucumber"; +import { Receiver } from "../../src"; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { HTTPParser } = require("http-parser-js"); + +const parser = new HTTPParser(HTTPParser.REQUEST); +const receiver = new Receiver(); + +Given("HTTP Protocol Binding is supported", function (this: World) { + return true; +}); + +Given("an HTTP request", function (request: string) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const world = this; + parser.onHeadersComplete = function (record: Record) { + world.headers = arrayToObject(record.headers); + }; + parser.onBody = function (body: Buffer, offset: number) { + world.body = body.slice(offset).toString(); + }; + parser.execute(Buffer.from(request), 0, request.length); + return true; +}); + +When("parsed as HTTP request", function () { + this.cloudevent = receiver.accept(this.headers, this.body); + return true; +}); + +Then("the attributes are:", function (attributes: { rawTable: [] }) { + const expected = tableToObject(attributes.rawTable); + assert.equal(this.cloudevent.id, expected.id); + assert.equal(this.cloudevent.type, expected.type); + assert.equal(this.cloudevent.source, expected.source); + assert.equal(this.cloudevent.time, new Date(expected.time).toISOString()); + assert.equal(this.cloudevent.specversion, expected.specversion); + assert.equal(this.cloudevent.datacontenttype, expected.datacontenttype); + return true; +}); + +Then("the data is equal to the following JSON:", function (json: string) { + assert.deepEqual(this.cloudevent.data, JSON.parse(json)); + return true; +}); + +function arrayToObject(arr: []): Record { + const obj: Record = {}; + // @ts-ignore + return arr.reduce(({}, keyOrValue, index, arr) => { + if (index % 2 === 0) { + obj[keyOrValue] = arr[index + 1]; + } + return obj; + }); +} + +function tableToObject(table: []): Record { + const obj: Record = {}; + // @ts-ignore + return table.reduce(({}, [key, value]: Array) => { + obj[key] = value; + return obj; + }); +} diff --git a/test/formats/json/parser_test.js b/test/formats/json/parser_test.js deleted file mode 100644 index 5cb2cffc..00000000 --- a/test/formats/json/parser_test.js +++ /dev/null @@ -1,66 +0,0 @@ -const expect = require("chai").expect; -const Parser = require("../../../lib/formats/json/parser.js"); - -describe("JSON Event Format Parser", () => { - it("Throw error when payload is an integer", () => { - // setup - const payload = 83; - const parser = new Parser(); - - // act and assert - expect(parser.parse.bind(parser, payload)) - .to.throw("invalid payload type, allowed are: string or object"); - }); - - it("Throw error when payload is null", () => { - // setup - const payload = null; - const parser = new Parser(); - - // act and assert - expect(parser.parse.bind(parser, payload)) - .to.throw("null or undefined payload"); - }); - - it("Throw error when payload is undefined", () => { - // setup - const parser = new Parser(); - - // act and assert - expect(parser.parse.bind(parser)) - .to.throw("null or undefined payload"); - }); - - it("Throw error when payload is a float", () => { - // setup - const payload = 8.3; - const parser = new Parser(); - - // act and assert - expect(parser.parse.bind(parser, payload)) - .to.throw("invalid payload type, allowed are: string or object"); - }); - - it("Throw error when payload is an invalid JSON", () => { - // setup - const payload = "gg"; - const parser = new Parser(); - - // act and assert - expect(parser.parse.bind(parser, payload)) - .to.throw("Unexpected token g in JSON at position 0"); - }); - - it("Must accept when the payload is a string well formed as JSON", () => { - // setup - const payload = "{\"much\" : \"wow\"}"; - const parser = new Parser(); - - // act - const actual = parser.parse(payload); - - // assert - expect(actual) - .to.be.an("object"); - }); -}); diff --git a/test/http_binding_0_3.js b/test/http_binding_0_3.js deleted file mode 100644 index d1e47cee..00000000 --- a/test/http_binding_0_3.js +++ /dev/null @@ -1,241 +0,0 @@ -const expect = require("chai").expect; -const nock = require("nock"); -const BinaryHTTPEmitter = - require("../lib/bindings/http/emitter_binary_0_3.js"); -const CloudEvent = require("../lib/cloudevent.js"); -const v03 = require("../v03/index.js"); - -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resourse/123"; -const contentEncoding = "base64"; -const contentType = "application/cloudevents+json; charset=utf-8"; -const now = new Date(); -const schemaurl = "http://cloudevents.io/schema.json"; - -const ceContentType = "application/json"; - -const data = { - foo: "bar" -}; -const dataBase64 = "Y2xvdWRldmVudHMK"; - -const ext1Name = "extension1"; -const ext1Value = "foobar"; -const ext2Name = "extension2"; -const ext2Value = "acme"; - -const cloudevent = - new CloudEvent(v03.Spec) - .type(type) - .source(source) - .dataContentType(ceContentType) - .subject("subject.ext") - .time(now) - .schemaurl(schemaurl) - .data(data) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - -const cebase64 = - new CloudEvent(v03.Spec) - .type(type) - .source(source) - .dataContentType(ceContentType) - .dataContentEncoding(contentEncoding) - .time(now) - .schemaurl(schemaurl) - .data(dataBase64) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - -const webhook = "https://cloudevents.io/webhook"; -const httpcfg = { - method: "POST", - url: `${webhook}/json` -}; - -const binary = new BinaryHTTPEmitter(httpcfg); -const structured = new v03.StructuredHTTPEmitter(httpcfg); - -describe("HTTP Transport Binding - Version 0.3", () => { - beforeEach(() => { - // Mocking the webhook - nock(webhook) - .post("/json") - .reply(201, { status: "accepted" }); - }); - - describe("Structured", () => { - describe("JSON Format", () => { - it(`requires '${contentType}' Content-Type in the header`, - () => structured.emit(cloudevent) - .then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(contentType); - })); - - it("the request payload should be correct", - () => structured.emit(cloudevent) - .then((response) => { - expect(JSON.parse(response.config.data)) - .to.deep.equal(cloudevent.format()); - })); - - describe("'data' attribute with 'base64' encoding", () => { - it("the request payload should be correct", - () => structured.emit(cebase64) - .then((response) => { - expect(JSON.parse(response.config.data).data) - .to.equal(cebase64.format().data); - })); - }); - }); - }); - - describe("Binary", () => { - describe("JSON Format", () => { - it(`requires ${cloudevent.getDataContentType()} in the header`, - () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(cloudevent.getDataContentType()); - })); - - it("the request payload should be correct", () => binary.emit(cloudevent) - .then((response) => { - expect(JSON.parse(response.config.data)) - .to.deep.equal(cloudevent.getData()); - })); - - it("HTTP Header contains 'ce-type'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-type"); - })); - - it("HTTP Header contains 'ce-specversion'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-specversion"); - })); - - it("HTTP Header contains 'ce-source'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-source"); - })); - - it("HTTP Header contains 'ce-id'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-id"); - })); - - it("HTTP Header contains 'ce-time'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-time"); - })); - - it("HTTP Header contains 'ce-schemaurl'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-schemaurl"); - })); - - it(`HTTP Header contains 'ce-${ext1Name}'`, () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property(`ce-${ext1Name}`); - })); - - it(`HTTP Header contains 'ce-${ext2Name}'`, () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property(`ce-${ext2Name}`); - })); - - it("HTTP Header contains 'ce-subject'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-subject"); - })); - - it("should 'ce-type' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getType()) - .to.equal(response.config.headers["ce-type"]); - })); - - it("should 'ce-specversion' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSpecversion()) - .to.equal(response.config.headers["ce-specversion"]); - })); - - it("should 'ce-source' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSource()) - .to.equal(response.config.headers["ce-source"]); - })); - - it("should 'ce-id' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getId()) - .to.equal(response.config.headers["ce-id"]); - })); - - it("should 'ce-time' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getTime()) - .to.equal(response.config.headers["ce-time"]); - })); - - it("should 'ce-schemaurl' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSchemaurl()) - .to.equal(response.config.headers["ce-schemaurl"]); - })); - - it(`should 'ce-${ext1Name}' have the right value`, - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getExtensions()[ext1Name]) - .to.equal(response.config.headers[`ce-${ext1Name}`]); - })); - - it(`should 'ce-${ext2Name}' have the right value`, - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getExtensions()[ext2Name]) - .to.equal(response.config.headers[`ce-${ext2Name}`]); - })); - - it("should 'ce-subject' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSubject()) - .to.equal(response.config.headers["ce-subject"]); - })); - - describe("'data' attribute with 'base64' encoding", () => { - it("HTTP Header contains 'ce-datacontentencoding'", - () => binary.emit(cebase64) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-datacontentencoding"); - })); - - it("should 'ce-datacontentencoding' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getDataContentEncoding()) - .to.equal(response.config.headers["ce-datacontentencoding"]); - })); - }); - }); - }); -}); diff --git a/test/http_binding_1.js b/test/http_binding_1.js deleted file mode 100644 index 300c908c..00000000 --- a/test/http_binding_1.js +++ /dev/null @@ -1,297 +0,0 @@ -const expect = require("chai").expect; -const nock = require("nock"); -const https = require("https"); -const { asBase64 } = require("../lib/utils/fun.js"); - -const { - Spec, - BinaryHTTPEmitter, - StructuredHTTPEmitter, - CloudEvent -} = require("../v1/index.js"); - -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resource/123"; -const contentType = "application/cloudevents+json; charset=utf-8"; -const now = new Date(); -const dataschema = "http://cloudevents.io/schema.json"; - -const ceContentType = "application/json"; - -const data = { - foo: "bar" -}; - -const ext1Name = "extension1"; -const ext1Value = "foobar"; -const ext2Name = "extension2"; -const ext2Value = "acme"; - -const cloudevent = - new CloudEvent(Spec) - .type(type) - .source(source) - .dataContentType(ceContentType) - .subject("subject.ext") - .time(now) - .dataschema(dataschema) - .data(data) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - -const dataString = ")(*~^my data for ce#@#$%"; - -const webhook = "https://cloudevents.io/webhook/v1"; -const httpcfg = { - method: "POST", - url: `${webhook}/json` -}; - -const binary = new BinaryHTTPEmitter(httpcfg); -const structured = new StructuredHTTPEmitter(httpcfg); - -describe("HTTP Transport Binding - Version 1.0", () => { - beforeEach(() => { - // Mocking the webhook - nock(webhook) - .post("/json") - .reply(201, { status: "accepted" }); - }); - - describe("Structured", () => { - it("works with mTLS authentication", () => { - const event = new StructuredHTTPEmitter({ - method: "POST", - url: `${webhook}/json`, - httpsAgent: new https.Agent({ - cert: "some value", - key: "other value" - }) - }); - return event.emit(cloudevent).then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(contentType); - }); - }); - - describe("JSON Format", () => { - it(`requires '${contentType}' Content-Type in the header`, - () => structured.emit(cloudevent) - .then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(contentType); - })); - - it("the request payload should be correct", - () => structured.emit(cloudevent) - .then((response) => { - expect(JSON.parse(response.config.data)) - .to.deep.equal(cloudevent.format()); - })); - - describe("Binary event data", () => { - it("the request payload should be correct when data is binary", () => { - const bindata = Uint32Array.from(dataString, (c) => c.codePointAt(0)); - const expected = asBase64(bindata); - const binevent = - new CloudEvent(Spec) - .type(type) - .source(source) - .dataContentType("text/plain") - .data(bindata) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - - return structured.emit(binevent) - .then((response) => { - expect(JSON.parse(response.config.data).data_base64) - .to.equal(expected); - }); - }); - - it("the payload must have 'data_base64' when data is binary", () => { - const binevent = - new CloudEvent(Spec) - .type(type) - .source(source) - .dataContentType("text/plain") - .data(Uint32Array.from(dataString, (c) => c.codePointAt(0))) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - - return structured.emit(binevent) - .then((response) => { - expect(JSON.parse(response.config.data)) - .to.have.property("data_base64"); - }); - }); - }); - }); - }); - - describe("Binary", () => { - it("works with mTLS authentication", () => { - const event = new BinaryHTTPEmitter({ - method: "POST", - url: `${webhook}/json`, - httpsAgent: new https.Agent({ - cert: "some value", - key: "other value" - }) - }); - return event.emit(cloudevent).then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(cloudevent.getDataContentType()); - }); - }); - - describe("JSON Format", () => { - it(`requires '${cloudevent.getDataContentType()}' in the header`, - () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers["Content-Type"]) - .to.equal(cloudevent.getDataContentType()); - })); - - it("the request payload should be correct", () => binary.emit(cloudevent) - .then((response) => { - expect(JSON.parse(response.config.data)) - .to.deep.equal(cloudevent.getData()); - })); - - it("the request payload should be correct when event data is binary", - () => { - const bindata = Uint32Array.from(dataString, (c) => c.codePointAt(0)); - const expected = asBase64(bindata); - const binevent = - new CloudEvent(Spec) - .type(type) - .source(source) - .dataContentType("text/plain") - .data(bindata) - .addExtension(ext1Name, ext1Value) - .addExtension(ext2Name, ext2Value); - - return binary.emit(binevent) - .then((response) => { - expect(response.config.data) - .to.equal(expected); - }); - }); - - it("HTTP Header contains 'ce-type'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-type"); - })); - - it("HTTP Header contains 'ce-specversion'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-specversion"); - })); - - it("HTTP Header contains 'ce-source'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-source"); - })); - - it("HTTP Header contains 'ce-id'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-id"); - })); - - it("HTTP Header contains 'ce-time'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-time"); - })); - - it("HTTP Header contains 'ce-dataschema'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-dataschema"); - })); - - it(`HTTP Header contains 'ce-${ext1Name}'`, () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property(`ce-${ext1Name}`); - })); - - it(`HTTP Header contains 'ce-${ext2Name}'`, () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property(`ce-${ext2Name}`); - })); - - it("HTTP Header contains 'ce-subject'", () => binary.emit(cloudevent) - .then((response) => { - expect(response.config.headers) - .to.have.property("ce-subject"); - })); - - it("should 'ce-type' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getType()) - .to.equal(response.config.headers["ce-type"]); - })); - - it("should 'ce-specversion' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSpecversion()) - .to.equal(response.config.headers["ce-specversion"]); - })); - - it("should 'ce-source' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSource()) - .to.equal(response.config.headers["ce-source"]); - })); - - it("should 'ce-id' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getId()) - .to.equal(response.config.headers["ce-id"]); - })); - - it("should 'ce-time' have the right value", () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getTime()) - .to.equal(response.config.headers["ce-time"]); - })); - - it("should 'ce-dataschema' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getDataschema()) - .to.equal(response.config.headers["ce-dataschema"]); - })); - - it(`should 'ce-${ext1Name}' have the right value`, - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getExtensions()[ext1Name]) - .to.equal(response.config.headers[`ce-${ext1Name}`]); - })); - - it(`should 'ce-${ext2Name}' have the right value`, - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getExtensions()[ext2Name]) - .to.equal(response.config.headers[`ce-${ext2Name}`]); - })); - - it("should 'ce-subject' have the right value", - () => binary.emit(cloudevent) - .then((response) => { - expect(cloudevent.getSubject()) - .to.equal(response.config.headers["ce-subject"]); - })); - }); - }); -}); diff --git a/test/integration/cloud_event_test.ts b/test/integration/cloud_event_test.ts new file mode 100644 index 00000000..8a98a62b --- /dev/null +++ b/test/integration/cloud_event_test.ts @@ -0,0 +1,186 @@ +import { expect } from "chai"; +import { CloudEvent, Version } from "../../src"; +import { CloudEventV03 } from "../../src/event/v03"; +import { CloudEventV1 } from "../../src/event/v1"; + +const type = "org.cncf.cloudevents.example"; +const source = "http://unit.test"; +const id = "b46cf653-d48a-4b90-8dfa-355c01061361"; + +const fixture: CloudEventV1 = { + id, + specversion: Version.V1, + source, + type, +}; + +describe("A CloudEvent", () => { + it("Can be constructed with a typed Message", () => { + const ce = new CloudEvent(fixture); + expect(ce.type).to.equal(type); + expect(ce.source).to.equal(source); + }); + + it("serializes as JSON with toString()", () => { + const ce = new CloudEvent(fixture); + expect(ce.toString()).to.deep.equal(JSON.stringify(ce)); + }); + + it("Throw a validation error for invalid extension names", () => { + expect(() => { + new CloudEvent({ "ext-1": "extension1", ...fixture }); + }).throw("invalid extension name"); + }); + + it("Throw a validation error for invalid extension names, more than 20 chars", () => { + expect(() => { + new CloudEvent({ "123456789012345678901": "extension1", ...fixture }); + }).throw("invalid extension name"); + }); +}); + +describe("A 1.0 CloudEvent", () => { + it("has retreivable source and type attributes", () => { + const ce = new CloudEvent(fixture); + expect(ce.source).to.equal("http://unit.test"); + expect(ce.type).to.equal("org.cncf.cloudevents.example"); + }); + + it("defaults to specversion 1.0", () => { + const ce = new CloudEvent({ source, type }); + expect(ce.specversion).to.equal("1.0"); + }); + + it("generates an ID if one is not provided in the constructor", () => { + const ce = new CloudEvent({ source, type }); + expect(ce.id).to.not.be.empty; + }); + + it("can be constructed with an ID", () => { + const ce = new CloudEvent({ id: "1234", specversion: Version.V1, source, type }); + expect(ce.id).to.equal("1234"); + }); + + it("generates a timestamp by default", () => { + const ce = new CloudEvent(fixture); + expect(ce.time).to.not.be.empty; + }); + + it("can be constructed with a timestamp", () => { + const time = new Date().toISOString(); + const ce = new CloudEvent({ time, ...fixture }); + expect(ce.time).to.equal(time); + }); + + it("can be constructed with a datacontenttype", () => { + const ce = new CloudEvent({ datacontenttype: "application/json", ...fixture }); + expect(ce.datacontenttype).to.equal("application/json"); + }); + + it("can be constructed with a dataschema", () => { + const ce = new CloudEvent({ dataschema: "http://my.schema", ...fixture }); + expect(ce.dataschema).to.equal("http://my.schema"); + }); + + it("can be constructed with a subject", () => { + const ce = new CloudEvent({ subject: "science", ...fixture }); + expect(ce.subject).to.equal("science"); + }); + + // Handle deprecated attribute - should this really throw? + it("throws a TypeError when constructed with a schemaurl", () => { + expect(() => { + new CloudEvent({ schemaurl: "http://throw.com", ...fixture }); + }).to.throw(TypeError, "cannot set schemaurl on version 1.0 event"); + }); + + it("can be constructed with data", () => { + const ce = new CloudEvent({ + ...fixture, + data: { lunch: "tacos" }, + }); + expect(ce.data).to.deep.equal({ lunch: "tacos" }); + }); + + it("can be constructed with extensions", () => { + const extensions = { + extensionkey: "extension-value", + }; + const ce = new CloudEvent({ + ...extensions, + ...fixture, + }); + expect(ce["extensionkey"]).to.equal(extensions["extensionkey"]); + }); + + it("throws ValidationError if the CloudEvent does not conform to the schema"); + it("returns a JSON string even if format is invalid"); + it("correctly formats a CloudEvent as JSON"); +}); + +describe("A 0.3 CloudEvent", () => { + const v03fixture: CloudEventV03 = { ...fixture }; + v03fixture.specversion = Version.V03; + + it("has retreivable source and type attributes", () => { + const ce = new CloudEvent(v03fixture); + expect(ce.source).to.equal("http://unit.test"); + expect(ce.type).to.equal("org.cncf.cloudevents.example"); + }); + + it("generates an ID if one is not provided in the constructor", () => { + const ce = new CloudEvent({ source, type, specversion: Version.V03 }); + expect(ce.id).to.not.be.empty; + expect(ce.specversion).to.equal(Version.V03); + }); + + it("generates a timestamp by default", () => { + const ce = new CloudEvent(v03fixture); + expect(ce.time).to.not.be.empty; + }); + + it("can be constructed with a timestamp", () => { + const time = new Date(); + const ce = new CloudEvent({ time, ...v03fixture }); + expect(ce.time).to.equal(time.toISOString()); + }); + + it("can be constructed with a datacontenttype", () => { + const ce = new CloudEvent({ datacontenttype: "application/json", ...v03fixture }); + expect(ce.datacontenttype).to.equal("application/json"); + }); + + it("can be constructed with a datacontentencoding", () => { + const ce = new CloudEvent({ datacontentencoding: "Base64", ...v03fixture, data: "SSB3YXMgZnVubnkg8J+Ygg==" }); + expect(ce.datacontentencoding).to.equal("Base64"); + }); + + it("can be constructed with a schemaurl", () => { + const ce = new CloudEvent({ schemaurl: "http://my.schema", ...v03fixture }); + expect(ce.schemaurl).to.equal("http://my.schema"); + }); + + it("can be constructed with a subject", () => { + const ce = new CloudEvent({ subject: "science", ...v03fixture }); + expect(ce.subject).to.equal("science"); + }); + + // Handle 1.0 attribute - should this really throw? + it("throws a TypeError when constructed with a dataschema", () => { + expect(() => { + new CloudEvent({ dataschema: "http://throw.com", ...v03fixture }); + }).to.throw(TypeError, "cannot set dataschema on version 0.3 event"); + }); + + it("can be constructed with data", () => { + const ce = new CloudEvent({ + ...v03fixture, + data: { lunch: "tacos" }, + }); + expect(ce.data).to.deep.equal({ lunch: "tacos" }); + }); + + it("throws ValidationError if the CloudEvent does not conform to the schema"); + it("returns a JSON string even if format is invalid"); + it("correctly formats a CloudEvent as JSON"); +}); diff --git a/test/integration/constants_test.ts b/test/integration/constants_test.ts new file mode 100644 index 00000000..f44c5a3b --- /dev/null +++ b/test/integration/constants_test.ts @@ -0,0 +1,150 @@ +import { expect } from "chai"; +import CONSTANTS from "../../src/constants"; + +describe("Constants exposed by top level exports", () => { + it("Exports an ENCODING_BASE64 constant", () => { + expect(CONSTANTS.ENCODING_BASE64).to.equal("base64"); + }); + it("Exports a DATA_ATTRIBUTE constant", () => { + expect(CONSTANTS.DATA_ATTRIBUTE).to.equal("data"); + }); + it("Exports a MIME_JSON constant", () => { + expect(CONSTANTS.MIME_JSON).to.equal("application/json"); + }); + it("Exports a MIME_OCTET_STREAM constant", () => { + expect(CONSTANTS.MIME_OCTET_STREAM).to.equal("application/octet-stream"); + }); + it("Exports a MIME_CE constant", () => { + expect(CONSTANTS.MIME_CE).to.equal("application/cloudevents"); + }); + it("Exports a MIME_CE_JSON constant", () => { + expect(CONSTANTS.MIME_CE_JSON).to.equal("application/cloudevents+json"); + }); + it("Exports a HEADER_CONTENT_TYPE constant", () => { + expect(CONSTANTS.HEADER_CONTENT_TYPE).to.equal("content-type"); + }); + it("Exports a DEFAULT_CONTENT_TYPE constant", () => { + expect(CONSTANTS.DEFAULT_CONTENT_TYPE).to.equal(`${CONSTANTS.MIME_JSON}; charset=${CONSTANTS.CHARSET_DEFAULT}`); + }); + it("Exports a DEFAULT_CE_CONTENT_TYPE constant", () => { + expect(CONSTANTS.DEFAULT_CE_CONTENT_TYPE).to.equal( + `${CONSTANTS.MIME_CE_JSON}; charset=${CONSTANTS.CHARSET_DEFAULT}`, + ); + }); + describe("V0.3 binary headers constants", () => { + it("Provides a TYPE header", () => { + expect(CONSTANTS.CE_HEADERS.TYPE).to.equal("ce-type"); + }); + it("Provides a SPEC_VERSION header", () => { + expect(CONSTANTS.CE_HEADERS.SPEC_VERSION).to.equal("ce-specversion"); + }); + it("Provides a SOURCE header", () => { + expect(CONSTANTS.CE_HEADERS.SOURCE).to.equal("ce-source"); + }); + it("Provides an ID header", () => { + expect(CONSTANTS.CE_HEADERS.ID).to.equal("ce-id"); + }); + it("Provides a TIME header", () => { + expect(CONSTANTS.CE_HEADERS.TIME).to.equal("ce-time"); + }); + it("Provides a SCHEMA_URL header", () => { + expect(CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL).to.equal("ce-schemaurl"); + }); + it("Provides a CONTENT_ENCODING header", () => { + expect(CONSTANTS.BINARY_HEADERS_03.CONTENT_ENCODING).to.equal("ce-datacontentencoding"); + }); + it("Provides a SUBJECT header", () => { + expect(CONSTANTS.CE_HEADERS.SUBJECT).to.equal("ce-subject"); + }); + it("Provides an EXTENSIONS_PREFIX constant", () => { + expect(CONSTANTS.EXTENSIONS_PREFIX).to.equal("ce-"); + }); + }); + describe("V0.3 structured attributes constants", () => { + it("Provides a TYPE attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.TYPE).to.equal("type"); + }); + it("Provides a SPEC_VERSION attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION).to.equal("specversion"); + }); + it("Provides a SOURCE attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SOURCE).to.equal("source"); + }); + it("Provides an ID attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.ID).to.equal("id"); + }); + it("Provides a TIME attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.TIME).to.equal("time"); + }); + it("Provides a SCHEMA_URL attribute", () => { + expect(CONSTANTS.STRUCTURED_ATTRS_03.SCHEMA_URL).to.equal("schemaurl"); + }); + it("Provides a CONTENT_ENCODING attribute", () => { + expect(CONSTANTS.STRUCTURED_ATTRS_03.CONTENT_ENCODING).to.equal("datacontentencoding"); + }); + it("Provides a SUBJECT attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SUBJECT).to.equal("subject"); + }); + it("Provides a DATA attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.DATA).to.equal("data"); + }); + }); + describe("V01 binary headers constants", () => { + it("Provides a TYPE header", () => { + expect(CONSTANTS.CE_HEADERS.TYPE).to.equal("ce-type"); + }); + it("Provides a SPEC_VERSION header", () => { + expect(CONSTANTS.CE_HEADERS.SPEC_VERSION).to.equal("ce-specversion"); + }); + it("Provides a SOURCE header", () => { + expect(CONSTANTS.CE_HEADERS.SOURCE).to.equal("ce-source"); + }); + it("Provides an ID header", () => { + expect(CONSTANTS.CE_HEADERS.ID).to.equal("ce-id"); + }); + it("Provides a TIME header", () => { + expect(CONSTANTS.CE_HEADERS.TIME).to.equal("ce-time"); + }); + it("Provides a DATA_SCHEMA header", () => { + expect(CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA).to.equal("ce-dataschema"); + }); + it("Provides a SUBJECT header", () => { + expect(CONSTANTS.CE_HEADERS.SUBJECT).to.equal("ce-subject"); + }); + it("Provides an EXTENSIONS_PREFIX constant", () => { + expect(CONSTANTS.EXTENSIONS_PREFIX).to.equal("ce-"); + }); + }); + describe("V1 structured attributes constants", () => { + it("Provides a TYPE attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.TYPE).to.equal("type"); + }); + it("Provides a SPEC_VERSION attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION).to.equal("specversion"); + }); + it("Provides a SOURCE attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SOURCE).to.equal("source"); + }); + it("Provides an ID attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.ID).to.equal("id"); + }); + it("Provides a TIME attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.TIME).to.equal("time"); + }); + it("Provides a DATA_SCHEMA attribute", () => { + expect(CONSTANTS.STRUCTURED_ATTRS_1.DATA_SCHEMA).to.equal("dataschema"); + }); + it("Provides a CONTENT_TYPE attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.CONTENT_TYPE).to.equal("datacontenttype"); + }); + it("Provides a SUBJECT attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.SUBJECT).to.equal("subject"); + }); + it("Provides a DATA attribute", () => { + expect(CONSTANTS.CE_ATTRIBUTES.DATA).to.equal("data"); + }); + it("Provides a DATA_BASE64 attribute", () => { + expect(CONSTANTS.STRUCTURED_ATTRS_1.DATA_BASE64).to.equal("data_base64"); + }); + }); +}); diff --git a/test/integration/http_binding_03.ts b/test/integration/http_binding_03.ts new file mode 100644 index 00000000..aae7f3b7 --- /dev/null +++ b/test/integration/http_binding_03.ts @@ -0,0 +1,206 @@ +import "mocha"; +import { expect } from "chai"; +import nock from "nock"; + +import { emitBinary, emitStructured } from "../../src/transport/http"; +import { CloudEvent, Version } from "../../src"; +import { AxiosResponse } from "axios"; + +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resourse/123"; +const contentEncoding = "base64"; +const contentType = "application/cloudevents+json; charset=utf-8"; +const time = new Date(); +const schemaurl = "http://cloudevents.io/schema.json"; + +const ceContentType = "application/json"; + +const data = { + foo: "bar", +}; +const dataBase64 = "Y2xvdWRldmVudHMK"; + +const ext1Name = "extension1"; +const ext1Value = "foobar"; +const ext2Name = "extension2"; +const ext2Value = "acme"; + +const cloudevent = new CloudEvent({ + specversion: Version.V03, + type, + source, + datacontenttype: ceContentType, + subject: "subject.ext", + time, + schemaurl, + data, + // set these so that deepEqual works + dataschema: "", + datacontentencoding: "", + data_base64: "", + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, +}); + +const cebase64 = new CloudEvent({ + specversion: Version.V03, + type, + source, + datacontenttype: ceContentType, + datacontentencoding: contentEncoding, + time, + schemaurl, + data: dataBase64, + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, +}); + +const webhook = "https://cloudevents.io/webhook"; +const httpcfg = { + method: "POST", + url: `${webhook}/json`, +}; + +describe("HTTP Transport Binding - Version 0.3", () => { + beforeEach(() => { + // Mocking the webhook + nock(webhook).post("/json").reply(201, { status: "accepted" }); + }); + + describe("Structured", () => { + describe("JSON Format", () => { + it(`requires '${contentType}' Content-Type in the header`, () => + emitStructured(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(contentType); + })); + + it("the request payload should be correct", () => + emitStructured(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.data).to.deep.equal(JSON.stringify(cloudevent)); + })); + + describe("'data' attribute with 'base64' encoding", () => { + it("the request payload should be correct", () => + emitStructured(cebase64, httpcfg).then((response: AxiosResponse) => { + expect(JSON.parse(response.config.data).data).to.equal(cebase64.data); + })); + }); + }); + }); + + describe("Binary", () => { + describe("JSON Format", () => { + it(`requires ${cloudevent.datacontenttype} in the header`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(cloudevent.datacontenttype); + })); + + it("the request payload should be correct", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(JSON.parse(response.config.data)).to.deep.equal(cloudevent.data); + })); + + it("HTTP Header contains 'ce-type'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-type"); + })); + + it("HTTP Header contains 'ce-specversion'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-specversion"); + })); + + it("HTTP Header contains 'ce-source'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-source"); + })); + + it("HTTP Header contains 'ce-id'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-id"); + })); + + it("HTTP Header contains 'ce-time'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-time"); + })); + + it("HTTP Header contains 'ce-schemaurl'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-schemaurl"); + })); + + it(`HTTP Header contains 'ce-${ext1Name}'`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property(`ce-${ext1Name}`); + })); + + it(`HTTP Header contains 'ce-${ext2Name}'`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property(`ce-${ext2Name}`); + })); + + it("HTTP Header contains 'ce-subject'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-subject"); + })); + + it("should 'ce-type' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.type).to.equal(response.config.headers["ce-type"]); + })); + + it("should 'ce-specversion' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.specversion).to.equal(response.config.headers["ce-specversion"]); + })); + + it("should 'ce-source' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.source).to.equal(response.config.headers["ce-source"]); + })); + + it("should 'ce-id' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.id).to.equal(response.config.headers["ce-id"]); + })); + + it("should 'ce-time' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.time).to.equal(response.config.headers["ce-time"]); + })); + + it("should 'ce-schemaurl' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.schemaurl).to.equal(response.config.headers["ce-schemaurl"]); + })); + + it(`should 'ce-${ext1Name}' have the right value`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent[ext1Name]).to.equal(response.config.headers[`ce-${ext1Name}`]); + })); + + it(`should 'ce-${ext2Name}' have the right value`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent[ext2Name]).to.equal(response.config.headers[`ce-${ext2Name}`]); + })); + + it("should 'ce-subject' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.subject).to.equal(response.config.headers["ce-subject"]); + })); + + describe("'data' attribute with 'base64' encoding", () => { + it("HTTP Header contains 'ce-datacontentencoding'", () => + emitBinary(cebase64, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-datacontentencoding"); + })); + + it("should 'ce-datacontentencoding' have the right value", () => + emitBinary(cebase64, httpcfg).then((response: AxiosResponse) => { + expect(cebase64.datacontentencoding).to.equal(response.config.headers["ce-datacontentencoding"]); + })); + }); + }); + }); +}); diff --git a/test/integration/http_binding_1.ts b/test/integration/http_binding_1.ts new file mode 100644 index 00000000..0a88a643 --- /dev/null +++ b/test/integration/http_binding_1.ts @@ -0,0 +1,239 @@ +import * as https from "https"; +import "mocha"; +import { expect } from "chai"; +import nock from "nock"; + +import { CloudEvent, Version } from "../../src"; +import { emitBinary, emitStructured } from "../../src/transport/http"; +import { asBase64 } from "../../src/event/validation/is"; +import { AxiosResponse } from "axios"; + +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resource/123"; +const contentType = "application/cloudevents+json; charset=utf-8"; +const time = new Date(); +const subject = "subject.ext"; +const dataschema = "http://cloudevents.io/schema.json"; +const datacontenttype = "application/json"; + +const data = { + foo: "bar", +}; + +const ext1Name = "extension1"; +const ext1Value = "foobar"; +const ext2Name = "extension2"; +const ext2Value = "acme"; + +let cloudevent = new CloudEvent({ + specversion: Version.V1, + type, + source, + datacontenttype, + subject, + time, + dataschema, + data, +}); +cloudevent = cloudevent.cloneWith({ [ext1Name]: ext1Value, [ext2Name]: ext2Value }); + +const dataString = ")(*~^my data for ce#@#$%"; + +const webhook = "https://cloudevents.io/webhook/v1"; +const httpcfg = { url: `${webhook}/json` }; + +describe("HTTP Transport Binding - Version 1.0", () => { + beforeEach(() => { + // Mocking the webhook + nock(webhook).post("/json").reply(201, { status: "accepted" }); + }); + + describe("Structured", () => { + it("works with mTLS authentication", () => { + const httpsAgent = new https.Agent({ + cert: "some value", + key: "other value", + }); + + return emitStructured(cloudevent, { ...httpcfg, httpsAgent }).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(contentType); + }); + }); + + describe("JSON Format", () => { + it(`requires '${contentType}' Content-Type in the header`, () => + emitStructured(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(contentType); + })); + + it("the request payload should be correct", () => + emitStructured(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.data).to.deep.equal(JSON.stringify(cloudevent)); + })); + + describe("Binary event data", () => { + it("the request payload should be correct when data is binary", () => { + const bindata = Uint32Array.from(dataString as string, (c) => c.codePointAt(0) as number); + const expected = asBase64(bindata); + const binevent = new CloudEvent({ + type, + source, + datacontenttype: "text/plain", + data: bindata, + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, + }); + + return emitStructured(binevent, httpcfg).then((response: AxiosResponse) => { + expect(JSON.parse(response.config.data).data_base64).to.equal(expected); + }); + }); + + it("the payload must have 'data_base64' when data is binary", () => { + const binevent = new CloudEvent({ + type, + source, + datacontenttype: "text/plain", + data: Uint32Array.from(dataString as string, (c) => c.codePointAt(0) as number), + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, + }); + + return emitStructured(binevent, httpcfg).then((response: AxiosResponse) => { + expect(JSON.parse(response.config.data)).to.have.property("data_base64"); + }); + }); + }); + }); + }); + + describe("Binary", () => { + it("works with mTLS authentication", () => + emitBinary(cloudevent, { + url: `${webhook}/json`, + httpsAgent: new https.Agent({ + cert: "some value", + key: "other value", + }), + }).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(cloudevent.datacontenttype); + })); + + describe("JSON Format", () => { + it(`requires '${cloudevent.datacontenttype}' in the header`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers["Content-Type"]).to.equal(cloudevent.datacontenttype); + })); + + it("the request payload should be correct", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(JSON.parse(response.config.data)).to.deep.equal(cloudevent.data); + })); + + it("the request payload should be correct when event data is binary", () => { + const bindata = Uint32Array.from(dataString as string, (c) => c.codePointAt(0) as number); + const expected = asBase64(bindata); + const binevent = new CloudEvent({ + type, + source, + datacontenttype: "text/plain", + data: bindata, + }); + + return emitBinary(binevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.data).to.equal(expected); + }); + }); + + it("HTTP Header contains 'ce-type'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-type"); + })); + + it("HTTP Header contains 'ce-specversion'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-specversion"); + })); + + it("HTTP Header contains 'ce-source'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-source"); + })); + + it("HTTP Header contains 'ce-id'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-id"); + })); + + it("HTTP Header contains 'ce-time'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-time"); + })); + + it("HTTP Header contains 'ce-dataschema'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-dataschema"); + })); + + it(`HTTP Header contains 'ce-${ext1Name}'`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property(`ce-${ext1Name}`); + })); + + it(`HTTP Header contains 'ce-${ext2Name}'`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property(`ce-${ext2Name}`); + })); + + it("HTTP Header contains 'ce-subject'", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(response.config.headers).to.have.property("ce-subject"); + })); + + it("should 'ce-type' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.type).to.equal(response.config.headers["ce-type"]); + })); + + it("should 'ce-specversion' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.specversion).to.equal(response.config.headers["ce-specversion"]); + })); + + it("should 'ce-source' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.source).to.equal(response.config.headers["ce-source"]); + })); + + it("should 'ce-id' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.id).to.equal(response.config.headers["ce-id"]); + })); + + it("should 'ce-time' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.time).to.equal(response.config.headers["ce-time"]); + })); + + it("should 'ce-dataschema' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.dataschema).to.equal(response.config.headers["ce-dataschema"]); + })); + + it(`should 'ce-${ext1Name}' have the right value`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent[ext1Name]).to.equal(response.config.headers[`ce-${ext1Name}`]); + })); + + it(`should 'ce-${ext2Name}' have the right value`, () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent[ext2Name]).to.equal(response.config.headers[`ce-${ext2Name}`]); + })); + + it("should 'ce-subject' have the right value", () => + emitBinary(cloudevent, httpcfg).then((response: AxiosResponse) => { + expect(cloudevent.subject).to.equal(response.config.headers["ce-subject"]); + })); + }); + }); +}); diff --git a/test/integration/http_emitter_test.ts b/test/integration/http_emitter_test.ts new file mode 100644 index 00000000..1644af9c --- /dev/null +++ b/test/integration/http_emitter_test.ts @@ -0,0 +1,225 @@ +import "mocha"; +import { expect } from "chai"; +import nock from "nock"; +import CONSTANTS from "../../src/constants"; + +const DEFAULT_CE_CONTENT_TYPE = CONSTANTS.DEFAULT_CE_CONTENT_TYPE; + +import { CloudEvent, Version, Emitter, Protocol, headersFor } from "../../src"; +import { AxiosResponse } from "axios"; + +const receiver = "https://cloudevents.io/"; +const type = "com.example.test"; +const source = "urn:event:from:myapi/resource/123"; +const ext1Name = "lunch"; +const ext1Value = "tacos"; +const ext2Name = "supper"; +const ext2Value = "sushi"; + +const data = { + lunchBreak: "noon", +}; + +describe("HTTP Transport Binding Emitter for CloudEvents", () => { + beforeEach(() => { + nock(receiver) + .post("/") + + .reply(function (uri: string, body: nock.Body) { + // return the request body and the headers so they can be + // examined in the test + if (typeof body === "string") { + body = JSON.parse(body); + } + const returnBody = { ...(body as Record), ...this.req.headers }; + return [201, returnBody]; + }); + }); + + describe("V1", () => { + const emitter = new Emitter({ url: receiver }); + const event = new CloudEvent({ + type, + source, + time: new Date(), + data, + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, + }); + + it("Sends a binary 1.0 CloudEvent by default", () => { + emitter + .send(event) + .then((response: AxiosResponse) => { + // A binary message will have a ce-id header + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(event.id); + expect(response.data[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1); + // A binary message will have a request body for the data + expect(response.data.lunchBreak).to.equal(data.lunchBreak); + // Ensure extensions are handled properly + expect(response.data[`${CONSTANTS.EXTENSIONS_PREFIX}${ext1Name}`]).to.equal(ext1Value); + expect(response.data[`${CONSTANTS.EXTENSIONS_PREFIX}${ext2Name}`]).to.equal(ext2Value); + }) + .catch(expect.fail); + }); + + it("Provides the HTTP headers for a binary event", () => { + const headers = headersFor(event); + expect(headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(event.type); + expect(headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(event.specversion); + expect(headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(event.source); + expect(headers[CONSTANTS.CE_HEADERS.ID]).to.equal(event.id); + expect(headers[CONSTANTS.CE_HEADERS.TIME]).to.equal(event.time); + }); + + it("Sends a binary CloudEvent with Custom Headers", () => { + emitter + .send(event, { headers: { customheader: "value" } }) + .then((response: { data: { [k: string]: string } }) => { + // A binary message will have a ce-id header + expect(response.data.customheader).to.equal("value"); + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(event.id); + expect(response.data[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1); + // A binary message will have a request body for the data + expect(response.data.lunchBreak).to.equal(data.lunchBreak); + }) + .catch(expect.fail); + }); + + it("Sends a structured 1.0 CloudEvent if specified", () => { + emitter + .send(event, { protocol: Protocol.HTTPStructured }) + .then((response: { data: { [k: string]: string | Record; data: { lunchBreak: string } } }) => { + // A structured message will have a cloud event content type + expect(response.data["content-type"]).to.equal(DEFAULT_CE_CONTENT_TYPE); + // Ensure other CE headers don't exist - just testing for ID + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(undefined); + // The spec version would have been specified in the body + expect(response.data.specversion).to.equal(Version.V1); + expect(response.data.data.lunchBreak).to.equal(data.lunchBreak); + // Ensure extensions are handled properly + expect(response.data[ext1Name]).to.equal(ext1Value); + expect(response.data[ext2Name]).to.equal(ext2Value); + }) + .catch(expect.fail); + }); + + it("Sends to an alternate URL if specified", () => { + nock(receiver) + .post("/alternate") + .reply(function (uri, requestBody: nock.Body) { + // return the request body and the headers so they can be + // examined in the test + if (typeof requestBody === "string") { + requestBody = JSON.parse(requestBody); + } + const returnBody = { ...(requestBody as Record), ...this.req.headers }; + return [201, returnBody]; + }); + + emitter + .send(event, { protocol: Protocol.HTTPStructured, url: `${receiver}alternate` }) + .then((response: AxiosResponse) => { + // A structured message will have a cloud event content type + expect(response.data["content-type"]).to.equal(DEFAULT_CE_CONTENT_TYPE); + // Ensure other CE headers don't exist - just testing for ID + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(undefined); + // The spec version would have been specified in the body + expect(response.data.specversion).to.equal(Version.V1); + expect(response.data.data.lunchBreak).to.equal(data.lunchBreak); + }) + .catch(expect.fail); + }); + }); + + describe("V03", () => { + const emitter = new Emitter({ url: receiver }); + const event = new CloudEvent({ + specversion: Version.V03, + type, + source, + time: new Date(), + data, + [ext1Name]: ext1Value, + [ext2Name]: ext2Value, + }); + + it("Sends a binary 0.3 CloudEvent", () => { + emitter + .send(event) + .then((response: AxiosResponse) => { + // A binary message will have a ce-id header + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(event.id); + expect(response.data[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V03); + // A binary message will have a request body for the data + expect(response.data.lunchBreak).to.equal(data.lunchBreak); + // Ensure extensions are handled properly + expect(response.data[`${CONSTANTS.EXTENSIONS_PREFIX}${ext1Name}`]).to.equal(ext1Value); + expect(response.data[`${CONSTANTS.EXTENSIONS_PREFIX}${ext2Name}`]).to.equal(ext2Value); + }) + .catch(expect.fail); + }); + + it("Provides the HTTP headers for a binary event", () => { + const headers = headersFor(event); + expect(headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(event.type); + expect(headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(event.specversion); + expect(headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(event.source); + expect(headers[CONSTANTS.CE_HEADERS.ID]).to.equal(event.id); + expect(headers[CONSTANTS.CE_HEADERS.TIME]).to.equal(event.time); + }); + + it("Sends a structured 0.3 CloudEvent if specified", () => { + emitter + .send(event, { protocol: Protocol.HTTPStructured }) + .then( + (response: { + data: { [k: string]: string | Record; specversion: string; data: { lunchBreak: string } }; + }) => { + // A structured message will have a cloud event content type + expect(response.data["content-type"]).to.equal(DEFAULT_CE_CONTENT_TYPE); + // Ensure other CE headers don't exist - just testing for ID + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(undefined); + // The spec version would have been specified in the body + expect(response.data.specversion).to.equal(Version.V03); + expect(response.data.data.lunchBreak).to.equal(data.lunchBreak); + // Ensure extensions are handled properly + expect(response.data[ext1Name]).to.equal(ext1Value); + expect(response.data[ext2Name]).to.equal(ext2Value); + }, + ) + .catch(expect.fail); + }); + + it("Sends to an alternate URL if specified", () => { + nock(receiver) + .post("/alternate") + .reply(function (uri, requestBody: nock.Body) { + // return the request body and the headers so they can be + // examined in the test + if (typeof requestBody === "string") { + requestBody = JSON.parse(requestBody); + } + const returnBody = { ...(requestBody as Record), ...this.req.headers }; + return [201, returnBody]; + }); + + emitter + .send(event, { protocol: Protocol.HTTPStructured, url: `${receiver}alternate` }) + .then( + (response: { + data: { specversion: string; data: { lunchBreak: string }; [k: string]: string | Record }; + }) => { + // A structured message will have a cloud event content type + expect(response.data["content-type"]).to.equal(DEFAULT_CE_CONTENT_TYPE); + // Ensure other CE headers don't exist - just testing for ID + expect(response.data[CONSTANTS.CE_HEADERS.ID]).to.equal(undefined); + // The spec version would have been specified in the body + expect(response.data.specversion).to.equal(Version.V03); + expect(response.data.data.lunchBreak).to.equal(data.lunchBreak); + }, + ) + .catch(expect.fail); + }); + }); +}); diff --git a/test/integration/http_receiver_test.ts b/test/integration/http_receiver_test.ts new file mode 100644 index 00000000..d8b440bc --- /dev/null +++ b/test/integration/http_receiver_test.ts @@ -0,0 +1,213 @@ +import "mocha"; +import { expect } from "chai"; +import { CloudEvent, Receiver, ValidationError } from "../../src"; +import { CloudEventV1 } from "../../src/event/v1"; + +const receiver = new Receiver(); +const id = "1234"; +const type = "org.cncf.cloudevents.test"; +const source = "urn:event:from:myapi/resourse/123"; +const structuredHeaders = { "content-type": "application/cloudevents+json" }; +const data = { lunch: "sushi" }; + +describe("HTTP Transport Binding Receiver for CloudEvents", () => { + describe("HTTP CloudEvent format detection", () => { + const specversion = "1.0"; + it("Throws when the event format cannot be detected", () => { + const payload = { + id, + type, + source, + data, + specversion, + }; + + expect(receiver.accept.bind(receiver, {}, payload)).to.throw(ValidationError, "no cloud event detected"); + }); + + it("Converts the JSON body of a binary event to an Object", () => { + const binaryHeaders = { + "content-type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + + const event: CloudEvent = receiver.accept(binaryHeaders, data); + expect(typeof event.data).to.equal("object"); + expect((event.data as Record).lunch).to.equal("sushi"); + }); + + it("Accepts binary events when the data property is undefined", () => { + const binaryHeaders = { + "content-type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + const event = receiver.accept(binaryHeaders, undefined); + expect(event.data).to.be.undefined; + }); + + it("Accepts binary events when the data property is null", () => { + const binaryHeaders = { + "content-type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + const event = receiver.accept(binaryHeaders, null); + expect(event.data).to.be.undefined; + }); + + it("Converts the JSON body of a structured event to an Object", () => { + const payload = { + id, + type, + source, + data, + specversion, + }; + + const event = receiver.accept(structuredHeaders, payload); + expect(typeof event.data).to.equal("object"); + expect((event.data as Record).lunch).to.equal("sushi"); + }); + + it("Recognizes headers in title case for binary events", () => { + const binaryHeaders = { + "Content-Type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + + const event: CloudEvent = receiver.accept(binaryHeaders, data); + expect(event.validate()).to.be.true; + expect((event.data as Record).lunch).to.equal("sushi"); + }); + + it("Recognizes headers in title case for structured events", () => { + const structuredHeaders = { "Content-Type": "application/cloudevents+json" }; + const payload = { + id, + type, + source, + data, + specversion, + }; + + const event: CloudEvent = receiver.accept(structuredHeaders, payload); + expect(event.validate()).to.be.true; + expect((event.data as Record).lunch).to.equal("sushi"); + }); + }); + + describe("V1", () => { + const specversion = "1.0"; + + it("Structured data returns a CloudEvent", () => { + const payload = { + id, + type, + source, + data, + specversion, + }; + + const event = receiver.accept(structuredHeaders, payload); + validateEvent(event, specversion); + }); + + it("Binary data returns a CloudEvent", () => { + const binaryHeaders = { + "content-type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + + const event = receiver.accept(binaryHeaders, data); + validateEvent(event, specversion); + }); + }); + + describe("V03", () => { + const specversion = "0.3"; + + it("Structured data returns a CloudEvent", () => { + const payload = { + id, + type, + source, + data, + specversion, + }; + + const event = receiver.accept(structuredHeaders, payload); + validateEvent(event, specversion); + }); + + it("Binary data returns a CloudEvent", () => { + const binaryHeaders = { + "content-type": "application/json; charset=utf-8", + "ce-specversion": specversion, + "ce-id": id, + "ce-type": type, + "ce-source": source, + }; + + const event = receiver.accept(binaryHeaders, data); + validateEvent(event, specversion); + }); + }); + + describe("Kafka-Knative event source", () => { + const specversion = "1.0"; + const id = "partition:1/offset:23"; + const type = "dev.knative.kafka.event"; + const source = "/apis/v1/namespaces/kafka/kafkasources/kafka-source#knative-demo-topic"; + + it("Should be parsable", () => { + const headers = { + host: "event-display.kafka.svc.cluster.local", + "user-agent": "Go-http-client/1.1", + "content-length": "59", + "accept-encoding": "gzip", + "ce-id": id, + "ce-source": source, + "ce-specversion": "1.0", + "ce-subject": "partition:1#23", + "ce-time": "2020-05-07T14:16:30.245Z", + "ce-type": type, + forwarded: "for=10.131.0.72;proto=http", + "k-proxy-request": "activator", + "x-envoy-expected-rq-timeout-ms": "600000", + "x-forwarded-for": "10.131.0.72, 10.128.2.99", + "x-forwarded-proto": "http", + "x-request-id": "d3649c1b-a968-40bf-a9da-3e853abc0c8b", + }; + const event = receiver.accept(headers, data); + expect(event instanceof CloudEvent).to.equal(true); + expect(event.id).to.equal(id); + expect(event.type).to.equal(type); + expect(event.source).to.equal(source); + expect(event.data).to.deep.equal(data); + expect(event.specversion).to.equal(specversion); + }); + }); +}); + +function validateEvent(event: CloudEventV1, specversion: string) { + expect(event instanceof CloudEvent).to.equal(true); + expect(event.id).to.equal(id); + expect(event.type).to.equal(type); + expect(event.source).to.equal(source); + expect(event.data).to.deep.equal(data); + expect(event.specversion).to.equal(specversion); +} diff --git a/test/integration/parser_test.ts b/test/integration/parser_test.ts new file mode 100644 index 00000000..2157e7db --- /dev/null +++ b/test/integration/parser_test.ts @@ -0,0 +1,69 @@ +import "mocha"; +import { expect } from "chai"; + +import { JSONParser as Parser } from "../../src/parsers/"; +import { ValidationError } from "../../src/"; + +describe("JSON Event Format Parser", () => { + it("Throw error when payload is an integer", () => { + // setup + const payload = 83; + const parser = new Parser(); + + expect(parser.parse.bind(parser, (payload as unknown) as string)).to.throw( + ValidationError, + "invalid payload type, allowed are: string or object", + ); + }); + + it("Throw error when payload is null", () => { + const payload = null; + const parser = new Parser(); + + expect(parser.parse.bind(parser, (payload as unknown) as string)).to.throw( + ValidationError, + "null or undefined payload", + ); + }); + + it("Throw error when payload is undefined", () => { + // setup + const parser = new Parser(); + + // act and assert + expect(parser.parse.bind(parser)).to.throw(ValidationError, "null or undefined payload"); + }); + + it("Throw error when payload is a float", () => { + // setup + const payload = 8.3; + const parser = new Parser(); + + expect(parser.parse.bind(parser, (payload as unknown) as string)).to.throw( + ValidationError, + "invalid payload type, allowed are: string or object", + ); + }); + + it("Throw error when payload is an invalid JSON", () => { + // setup + const payload = "gg"; + const parser = new Parser(); + + // TODO: Should the parser catch the SyntaxError and re-throw a ValidationError? + expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError, "Unexpected token g in JSON at position 0"); + }); + + it("Must accept when the payload is a string well formed as JSON", () => { + // setup + // eslint-disable-next-line prettier/prettier + const payload = "{\"much\" : \"wow\"}"; + const parser = new Parser(); + + // act + const actual = parser.parse(payload); + + // assert + expect(actual).to.be.an("object"); + }); +}); diff --git a/test/integration/receiver_binary_03_tests.ts b/test/integration/receiver_binary_03_tests.ts new file mode 100644 index 00000000..9ac4c6d0 --- /dev/null +++ b/test/integration/receiver_binary_03_tests.ts @@ -0,0 +1,422 @@ +import "mocha"; +import { expect } from "chai"; + +import { CloudEvent, ValidationError, Version } from "../../src"; +import { BinaryHTTPReceiver } from "../../src/transport/http/binary_receiver"; +import CONSTANTS from "../../src/constants"; + +const receiver = new BinaryHTTPReceiver(Version.V03); + +describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => { + describe("Check", () => { + it("Throw error when attributes arg is null or undefined", () => { + // setup + const payload = {}; + const attributes = undefined; + + expect(receiver.parse.bind(receiver, payload, (attributes as unknown) as string)).to.throw( + ValidationError, + "headers is null or undefined", + ); + }); + + it("Throw error when payload is not an object or string", () => { + // setup + const payload = 1.2; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "payload must be an object or a string", + ); + }); + + it("Throw error when headers has no 'ce-type'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-type' not found", + ); + }); + + it("Throw error when headers has no 'ce-specversion'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-specversion' not found", + ); + }); + + it("Throw error when headers has no 'ce-source'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-source' not found", + ); + }); + + it("Throw error when headers has no 'ce-id'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "header 'ce-id' not found"); + }); + + it("Throw error when spec is not 0.3", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: "0.2", + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid spec version"); + }); + + it("Throw error when the content-type is invalid", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "text/html", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid content type"); + }); + + it("No error when all required headers are in place", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + + it("No error when content-type is unspecified", () => { + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + }); + + describe("Parse", () => { + it("CloudEvent contains 'type'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.type).to.equal("type"); + }); + + it("CloudEvent contains 'specversion'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.specversion).to.equal(Version.V03); + }); + + it("CloudEvent contains 'source'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.source).to.equal("/source"); + }); + + it("CloudEvent contains 'id'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.id).to.equal("id"); + }); + + it("CloudEvent contains 'time'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.time).to.equal("2019-06-16T11:42:00.000Z"); + }); + + it("CloudEvent contains 'schemaurl'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.schemaurl).to.equal("http://schema.registry/v1"); + }); + + it("CloudEvent contains 'datacontenttype' (application/json)", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.datacontenttype).to.equal("application/json"); + }); + + it("CloudEvent contains 'datacontenttype' (application/octet-stream)", () => { + // setup + const payload = "The payload is binary data"; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/octet-stream", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.datacontenttype).to.equal("application/octet-stream"); + }); + + it("CloudEvent contains 'data' (application/json)", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.data).to.deep.equal(payload); + }); + + it("CloudEvent contains 'data' (application/octet-stream)", () => { + // setup + const payload = "The payload is binary data"; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/octet-stream", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.data).to.deep.equal(payload); + }); + + it("No error when all attributes are in place", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual).to.be.an.instanceof(CloudEvent); + }); + + it("Should accept 'extension1'", () => { + // setup + const extension1 = "mycuston-ext1"; + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V03, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_03.SCHEMA_URL]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + [`${[CONSTANTS.EXTENSIONS_PREFIX]}extension1`]: extension1, + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.extension1).to.equal(extension1); + }); + }); +}); diff --git a/test/integration/receiver_binary_1_tests.ts b/test/integration/receiver_binary_1_tests.ts new file mode 100644 index 00000000..368c55ed --- /dev/null +++ b/test/integration/receiver_binary_1_tests.ts @@ -0,0 +1,448 @@ +import "mocha"; +import { expect } from "chai"; + +import { CloudEvent, ValidationError, Version } from "../../src"; +import { asBase64 } from "../../src/event/validation"; +import { BinaryHTTPReceiver } from "../../src/transport/http/binary_receiver"; +import CONSTANTS from "../../src/constants"; + +const receiver = new BinaryHTTPReceiver(Version.V1); + +describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => { + describe("Check", () => { + it("Throw error when attributes arg is null or undefined", () => { + // setup + const payload = {}; + const attributes = undefined; + + expect(receiver.parse.bind(receiver, payload, (attributes as unknown) as string)).to.throw( + ValidationError, + "headers is null or undefined", + ); + }); + + it("Throw error when payload is not an object or string", () => { + // setup + const payload = 1.2; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "payload must be an object or a string", + ); + }); + + it("Throw error when headers has no 'ce-type'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-type' not found", + ); + }); + + it("Throw error when headers has no 'ce-specversion'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-specversion' not found", + ); + }); + + it("Throw error when headers has no 'ce-source'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "header 'ce-source' not found", + ); + }); + + it("Throw error when headers has no 'ce-id'", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "header 'ce-id' not found"); + }); + + it("Throw error when spec is not 1.0", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: "0.2", + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid spec version"); + }); + + it("Throw error when the content-type is invalid", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "text/html", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid content type"); + }); + + it("No error when content-type is unspecified", () => { + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + + it("No error when all required headers are in place", () => { + // setup + const payload = {}; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + }); + + describe("Parse", () => { + it("CloudEvent contains 'type'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.type).to.equal("type"); + }); + + it("CloudEvent contains 'specversion'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.specversion).to.equal(Version.V1); + }); + + it("CloudEvent contains 'source'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.source).to.equal("/source"); + }); + + it("CloudEvent contains 'id'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.id).to.equal("id"); + }); + + it("CloudEvent contains 'time'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.time).to.equal("2019-06-16T11:42:00.000Z"); + }); + + it("CloudEvent contains 'dataschema'", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.dataschema).to.equal("http://schema.registry/v1"); + }); + + it("CloudEvent contains 'contenttype' (application/json)", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.datacontenttype).to.equal("application/json"); + }); + + it("CloudEvent contains 'contenttype' (application/octet-stream)", () => { + // setup + const payload = "The payload is binary data"; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/octet-stream", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.datacontenttype).to.equal("application/octet-stream"); + }); + + it("CloudEvent contains 'data' (application/json)", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.data).to.deep.equal(payload); + }); + + it("CloudEvent contains 'data' (application/octet-stream)", () => { + // setup + const payload = "The payload is binary data"; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/octet-stream", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.data).to.deep.equal(payload); + }); + + it("The content of 'data' is base64 for binary", () => { + // setup + const expected = { + data: "dataString", + }; + const bindata = Uint32Array.from(JSON.stringify(expected) as string, (c) => c.codePointAt(0) as number); + const payload = asBase64(bindata); + + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "/source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.data).to.deep.equal(expected); + }); + + it("No error when all attributes are in place", () => { + // setup + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual).to.be.an.instanceof(CloudEvent); + }); + + it("Should accept 'extension1'", () => { + // setup + const extension1 = "mycustom-ext1"; + const payload = { + data: "dataString", + }; + const attributes = { + [CONSTANTS.CE_HEADERS.TYPE]: "type", + [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1, + [CONSTANTS.CE_HEADERS.SOURCE]: "source", + [CONSTANTS.CE_HEADERS.ID]: "id", + [CONSTANTS.CE_HEADERS.TIME]: "2019-06-16T11:42:00Z", + [CONSTANTS.BINARY_HEADERS_1.DATA_SCHEMA]: "http://schema.registry/v1", + [CONSTANTS.HEADER_CONTENT_TYPE]: "application/json", + [`${[CONSTANTS.EXTENSIONS_PREFIX]}extension1`]: extension1, + }; + + // act + const actual = receiver.parse(payload, attributes); + + // assert + expect(actual.extension1).to.equal(extension1); + }); + }); +}); diff --git a/test/integration/receiver_structured_0_3_test.ts b/test/integration/receiver_structured_0_3_test.ts new file mode 100644 index 00000000..f83e11f9 --- /dev/null +++ b/test/integration/receiver_structured_0_3_test.ts @@ -0,0 +1,205 @@ +import "mocha"; +import { expect } from "chai"; + +import { CloudEvent, ValidationError, Version } from "../../src"; +import { StructuredHTTPReceiver } from "../../src/transport/http/structured_receiver"; + +const receiver = new StructuredHTTPReceiver(Version.V03); +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resourse/123"; +const time = new Date(); +const schemaurl = "http://cloudevents.io/schema.json"; + +const ceContentType = "application/json"; + +const data = { + foo: "bar", +}; + +describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => { + describe("Check", () => { + it("Throw error when payload arg is null or undefined", () => { + // setup + const payload = null; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, (payload as unknown) as string, attributes)).to.throw( + ValidationError, + "payload is null or undefined", + ); + }); + + it("Throw error when attributes arg is null or undefined", () => { + // setup + const payload = {}; + const attributes = null; + + expect(receiver.parse.bind(receiver, payload, (attributes as unknown) as string)).to.throw( + ValidationError, + "headers is null or undefined", + ); + }); + + it("Throw error when payload is not an object or string", () => { + // setup + const payload = 1.0; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "payload must be an object or a string", + ); + }); + + it("Throw error when the content-type is invalid", () => { + // setup + const payload = {}; + const attributes = { + "Content-Type": "text/html", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid content type"); + }); + + it("Throw error data content encoding is base64, but 'data' is not", () => { + // setup + const event = { + specversion: Version.V03, + type, + source, + time, + datacontenttype: "text/plain", + datacontentencoding: "base64", + schemaurl, + data: "No base 64 value", + }; + + const attributes = { + "Content-Type": "application/cloudevents+json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, event, attributes)).to.throw(ValidationError, "invalid payload"); + }); + + it("No error when all required stuff are in place", () => { + // setup + const payload = { + specversion: Version.V03, + source, + type, + }; + const attributes = { + "Content-Type": "application/cloudevents+json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + }); + + describe("Parse", () => { + it("Throw error when the event does not follow the spec", () => { + // setup + const payload = {}; + const attributes = { + "Content-Type": "application/cloudevents+json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(); + }); + }); + + describe("Parse", () => { + it("Throw error when the event does not follow the spec", () => { + const payload = { + type, + source, + time, + schemaurl, + data, + }; + + const headers = { + "Content-Type": "application/cloudevents+xml", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, headers)).to.throw(ValidationError, "invalid content type"); + }); + + it("Should accept event that follows the spec", () => { + // setup + const id = "id-x0dk"; + const payload = { + specversion: Version.V03, + id, + type, + source, + time, + schemaurl, + datacontenttype: ceContentType, + data, + }; + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + + // assert + expect(actual).to.be.an.instanceof(CloudEvent); + expect(actual.id).to.equal(id); + }); + + it("Should accept 'extension1'", () => { + // setup + const extension1 = "mycuston-ext1"; + const payload = { + specversion: Version.V03, + type, + source, + time, + schemaurl, + data, + datacontenttype: ceContentType, + extension1: extension1, + }; + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + + // assert + expect(actual.extension1).to.equal(extension1); + }); + + it("Should parse 'data' stringfied json to json object", () => { + const payload = { + specversion: Version.V03, + type, + source, + time, + schemaurl, + datacontenttype: ceContentType, + data: JSON.stringify(data), + }; + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + + // assert + expect(actual.data).to.deep.equal(data); + }); + }); +}); diff --git a/test/integration/receiver_structured_1_test.ts b/test/integration/receiver_structured_1_test.ts new file mode 100644 index 00000000..250dab9c --- /dev/null +++ b/test/integration/receiver_structured_1_test.ts @@ -0,0 +1,182 @@ +import "mocha"; +import { expect } from "chai"; + +import { CloudEvent, ValidationError, Version } from "../../src"; +import { asBase64 } from "../../src/event/validation"; +import { StructuredHTTPReceiver } from "../../src/transport/http/structured_receiver"; + +const receiver = new StructuredHTTPReceiver(Version.V1); +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resourse/123"; +const time = new Date(); +const dataschema = "http://cloudevents.io/schema.json"; + +const data = { + foo: "bar", +}; + +describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", () => { + describe("Check", () => { + it("Throw error when payload arg is null or undefined", () => { + // setup + const payload = null; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, (payload as unknown) as string, attributes)).to.throw( + ValidationError, + "payload is null or undefined", + ); + }); + + it("Throw error when attributes arg is null or undefined", () => { + // setup + const payload = {}; + const attributes = null; + + expect(receiver.parse.bind(receiver, payload, (attributes as unknown) as string)).to.throw( + ValidationError, + "headers is null or undefined", + ); + }); + + it("Throw error when payload is not an object or string", () => { + // setup + const payload = 1.0; + const attributes = {}; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw( + ValidationError, + "payload must be an object or a string", + ); + }); + + it("Throw error when the content-type is invalid", () => { + // setup + const payload = {}; + const attributes = { + "Content-Type": "text/html", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.throw(ValidationError, "invalid content type"); + }); + + it("No error when all required stuff are in place", () => { + // setup + const payload = { + source, + type, + }; + const attributes = { + "Content-Type": "application/cloudevents+json", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)).to.not.throw(); + }); + }); + + describe("Parse", () => { + it("Throw error when the event does not follow the spec", () => { + // setup + const payload = { + type, + source, + time, + data, + }; + + const headers = { + "Content-Type": "application/cloudevents+xml", + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, headers)).to.throw(ValidationError, "invalid content type"); + }); + + it("Should accept event that follows the spec", () => { + // setup + const id = "id-x0dk"; + const payload = { + id, + type, + source, + time, + data, + dataschema, + }; + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + + // assert + expect(actual).to.be.an.instanceof(CloudEvent); + expect(actual.id).to.equal(id); + }); + + it("Should accept 'extension1'", () => { + // setup + const extension1 = "mycustomext1"; + const event = { + type, + source, + time, + data, + dataschema, + extension1, + }; + + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(event, headers); + expect(actual.extension1).to.equal(extension1); + }); + + it("Should parse 'data' stringified json to json object", () => { + // setup + const payload = { + type, + source, + time, + dataschema, + data: data, + }; + + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + + // assert + expect(actual.data).to.deep.equal(data); + }); + + it("Should maps 'data_base64' to 'data' attribute", () => { + const bindata = Uint32Array.from(JSON.stringify(data), (c) => c.codePointAt(0) as number); + const expected = asBase64(bindata); + const payload = { + type, + source, + data: bindata, + }; + + const headers = { + "content-type": "application/cloudevents+json", + }; + + // act + const actual = receiver.parse(payload, headers); + expect(actual.data_base64).to.equal(expected); + }); + }); +}); diff --git a/test/integration/sdk_test.ts b/test/integration/sdk_test.ts new file mode 100644 index 00000000..a949ed0a --- /dev/null +++ b/test/integration/sdk_test.ts @@ -0,0 +1,44 @@ +import "mocha"; +import { expect } from "chai"; +import { CloudEvent, Receiver, Emitter, Version } from "../../src"; + +const fixture = { + type: "org.cloudevents.test", + source: "http://cloudevents.io", +}; + +describe("The SDK Requirements", () => { + it("should expose a CloudEvent type", () => { + const event = new CloudEvent(fixture); + expect(event instanceof CloudEvent).to.equal(true); + }); + + it("should expose a Receiver type", () => { + const receiver = new Receiver(); + expect(receiver instanceof Receiver).to.equal(true); + }); + + it("should expose an Emitter type", () => { + const emitter = new Emitter({ + url: "http://example.com", + }); + expect(emitter instanceof Emitter).to.equal(true); + }); + + describe("v0.3", () => { + it("should create an event using the right spec version", () => { + expect( + new CloudEvent({ + ...fixture, + specversion: Version.V03, + }).specversion, + ).to.equal(Version.V03); + }); + }); + + describe("v1.0", () => { + it("should create an event using the right spec version", () => { + expect(new CloudEvent(fixture).specversion).to.equal(Version.V1); + }); + }); +}); diff --git a/test/integration/spec_03_tests.ts b/test/integration/spec_03_tests.ts new file mode 100644 index 00000000..c0732758 --- /dev/null +++ b/test/integration/spec_03_tests.ts @@ -0,0 +1,194 @@ +import "mocha"; +import { expect } from "chai"; +import { CloudEvent, Version, ValidationError, Mode } from "../../src"; +import Constants from "../../src/constants"; + +const id = "97699ec2-a8d9-47c1-bfa0-ff7aa526f838"; +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resourse/123"; +const time = new Date(); +const schemaurl = "http://example.com/registry/myschema.json"; +const data = { + much: "wow", +}; +const subject = "subject-x0"; + +let cloudevent = new CloudEvent({ + specversion: Version.V03, + id, + source, + type, + subject, + time, + data, + schemaurl, + datacontenttype: Constants.MIME_JSON, +}); + +describe("CloudEvents Spec v0.3", () => { + describe("REQUIRED Attributes", () => { + it("Should have 'id'", () => { + expect(cloudevent.id).to.equal(id); + }); + + it("Should have 'source'", () => { + expect(cloudevent.source).to.equal(source); + }); + + it("Should have 'specversion'", () => { + expect(cloudevent.specversion).to.equal(Version.V03); + }); + + it("Should have 'type'", () => { + expect(cloudevent.type).to.equal(type); + }); + }); + + describe("OPTIONAL Attributes", () => { + it("Should have 'datacontentencoding'", () => { + cloudevent = cloudevent.cloneWith({ + datacontentencoding: Constants.ENCODING_BASE64, + data: "SSB3YXMgZnVubnkg8J+Ygg==", + }); + expect(cloudevent.datacontentencoding).to.equal(Constants.ENCODING_BASE64); + + cloudevent = cloudevent.cloneWith({ datacontentencoding: undefined, data: data }); + }); + + it("Should have 'datacontenttype'", () => { + expect(cloudevent.datacontenttype).to.equal(Constants.MIME_JSON); + }); + + it("Should have 'schemaurl'", () => { + expect(cloudevent.schemaurl).to.equal(schemaurl); + }); + + it("Should have 'subject'", () => { + expect(cloudevent.subject).to.equal(subject); + }); + + it("Should have 'time'", () => { + expect(cloudevent.time).to.equal(time.toISOString()); + }); + + it("Should have 'data'", () => { + expect(cloudevent.data).to.deep.equal(data); + }); + + it("Should have the 'extension1'", () => { + cloudevent = cloudevent.cloneWith({ extension1: "value1" }); + expect(cloudevent.extension1).to.equal("value1"); + }); + }); + + describe("The Constraints check", () => { + describe("'id'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.id; + }).to.throw(TypeError); + }); + + it("defaut ID create when an empty string", () => { + cloudevent = cloudevent.cloneWith({ id: "" }); + expect(cloudevent.id.length).to.be.greaterThan(0); + }); + }); + + describe("'source'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.source; + }).to.throw(TypeError); + }); + }); + + describe("'specversion'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.specversion; + }).to.throw(TypeError); + }); + }); + + describe("'type'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.type; + }).to.throw(TypeError); + }); + + it("should throw an error when is an empty string", () => { + expect(() => { + cloudevent.cloneWith({ type: "" }); + }).to.throw(ValidationError, "invalid payload"); + }); + + it("must be a non-empty string", () => { + cloudevent.cloneWith({ type: type }); + expect(cloudevent.type).to.equal(type); + }); + }); + + describe("'datacontentencoding'", () => { + it("should throw an error when is a unsupported encoding", () => { + expect(() => { + cloudevent.cloneWith({ data: "Y2xvdWRldmVudHMK", datacontentencoding: Mode.BINARY }); + }).to.throw(ValidationError, "invalid payload"); + + cloudevent.cloneWith({ data: data, datacontentencoding: undefined }); + }); + + it("should throw an error when 'data' does not carry base64", () => { + expect(() => { + cloudevent.cloneWith({ + data: "no base 64 value", + datacontentencoding: Constants.ENCODING_BASE64, + datacontenttype: "text/plain", + }); + }).to.throw(ValidationError, "invalid payload"); + + cloudevent.cloneWith({ + data: data, + datacontentencoding: undefined, + }); + }); + + it("should accept when 'data' is a string", () => { + cloudevent.cloneWith({ data: "Y2xvdWRldmVudHMK", datacontentencoding: Constants.ENCODING_BASE64 }); + expect(cloudevent.validate()).to.be.true; + cloudevent.cloneWith({ data: data, datacontentencoding: undefined }); + }); + }); + + describe("'data'", () => { + it("should maintain the type of data when no data content type", () => { + cloudevent = cloudevent.cloneWith({ datacontenttype: undefined }); + cloudevent.data = JSON.stringify(data); + + expect(typeof cloudevent.data).to.equal("string"); + }); + + it("should convert data with stringified json to a json object", () => { + cloudevent = cloudevent.cloneWith({ datacontenttype: Constants.MIME_JSON }); + cloudevent.data = JSON.stringify(data); + expect(cloudevent.data).to.deep.equal(data); + }); + }); + + describe("'subject'", () => { + it("should throw an error when is an empty string", () => { + expect(() => { + cloudevent.cloneWith({ subject: "" }); + }).to.throw(ValidationError); + }); + }); + + describe("'time'", () => { + it("must adhere to the format specified in RFC 3339", () => { + cloudevent = cloudevent.cloneWith({ time: time }); + expect(cloudevent.time).to.equal(time.toISOString()); + }); + }); + }); +}); diff --git a/test/integration/spec_1_tests.ts b/test/integration/spec_1_tests.ts new file mode 100644 index 00000000..d5802832 --- /dev/null +++ b/test/integration/spec_1_tests.ts @@ -0,0 +1,183 @@ +import "mocha"; +import { expect } from "chai"; +import { CloudEvent, Version, ValidationError } from "../../src"; +import { asBase64 } from "../../src/event/validation"; +import Constants from "../../src/constants"; + +const id = "97699ec2-a8d9-47c1-bfa0-ff7aa526f838"; +const type = "com.github.pull.create"; +const source = "urn:event:from:myapi/resourse/123"; +const time = new Date(); +const dataschema = "http://example.com/registry/myschema.json"; +const data = { + much: "wow", +}; +const subject = "subject-x0"; + +let cloudevent = new CloudEvent({ + specversion: Version.V1, + id, + source, + type, + subject, + time, + data, + dataschema, + datacontenttype: Constants.MIME_JSON, +}); + +describe("CloudEvents Spec v1.0", () => { + describe("REQUIRED Attributes", () => { + it("Should have 'id'", () => { + expect(cloudevent.id).to.equal(id); + }); + + it("Should have 'source'", () => { + expect(cloudevent.source).to.equal(source); + }); + + it("Should have 'specversion'", () => { + expect(cloudevent.specversion).to.equal("1.0"); + }); + + it("Should have 'type'", () => { + expect(cloudevent.type).to.equal(type); + }); + }); + + describe("OPTIONAL Attributes", () => { + it("Should have 'datacontenttype'", () => { + expect(cloudevent.datacontenttype).to.equal(Constants.MIME_JSON); + }); + + it("Should have 'dataschema'", () => { + expect(cloudevent.dataschema).to.equal(dataschema); + }); + + it("Should have 'subject'", () => { + expect(cloudevent.subject).to.equal(subject); + }); + + it("Should have 'time'", () => { + expect(cloudevent.time).to.equal(time.toISOString()); + }); + }); + + describe("Extensions Constraints", () => { + it("should be ok when type is 'boolean'", () => { + expect(cloudevent.cloneWith({ extboolean: true }).validate()).to.equal(true); + }); + + it("should be ok when type is 'integer'", () => { + expect(cloudevent.cloneWith({ extinteger: 2019 }).validate()).to.equal(true); + }); + + it("should be ok when type is 'string'", () => { + expect(cloudevent.cloneWith({ extstring: "an-string" }).validate()).to.equal(true); + }); + + it("should be ok when type is 'Uint32Array' for 'Binary'", () => { + const myBinary = new Uint32Array(2019); + expect(cloudevent.cloneWith({ extbinary: myBinary }).validate()).to.equal(true); + }); + + // URI + it("should be ok when type is 'Date' for 'Timestamp'", () => { + const myDate = new Date(); + expect(cloudevent.cloneWith({ extdate: myDate }).validate()).to.equal(true); + }); + + // even though the spec doesn't allow object types for + // extensions, it could be JSON. And before a JS CE + // is transmitted across the wire, this value will be + // converted to JSON + it("should be ok when the type is an object", () => { + expect(cloudevent.cloneWith({ objectextension: { some: "object" } }).validate()).to.equal(true); + }); + }); + + describe("The Constraints check", () => { + describe("'id'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.id; + }).to.throw(TypeError); + }); + + it("defaut ID create when an empty string", () => { + cloudevent = cloudevent.cloneWith({ id: "" }); + expect(cloudevent.id.length).to.be.greaterThan(0); + }); + }); + + describe("'source'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.source; + }).to.throw(TypeError); + }); + }); + + describe("'specversion'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.specversion; + }).to.throw(TypeError); + }); + }); + + describe("'type'", () => { + it("should throw an error when trying to remove", () => { + expect(() => { + delete cloudevent.type; + }).to.throw(TypeError); + }); + }); + + describe("'subject'", () => { + it("should throw an error when is an empty string", () => { + expect(() => { + cloudevent.cloneWith({ subject: "" }); + }).to.throw(ValidationError, "invalid payload"); + }); + }); + + describe("'time'", () => { + it("must adhere to the format specified in RFC 3339", () => { + cloudevent = cloudevent.cloneWith({ time: time }); + expect(cloudevent.time).to.equal(time.toISOString()); + }); + }); + }); + + describe("Event data constraints", () => { + it("Should have 'data'", () => { + expect(cloudevent.data).to.deep.equal(data); + }); + + it("should maintain the type of data when no data content type", () => { + const dct = cloudevent.datacontenttype; + cloudevent = cloudevent.cloneWith({ datacontenttype: undefined }); + cloudevent.data = JSON.stringify(data); + + expect(typeof cloudevent.data).to.equal("string"); + cloudevent = cloudevent.cloneWith({ datacontenttype: dct }); + }); + + it("should convert data with stringified json to a json object", () => { + cloudevent = cloudevent.cloneWith({ datacontenttype: Constants.MIME_JSON, data: JSON.stringify(data) }); + expect(cloudevent.data).to.deep.equal(data); + }); + + it("should be ok when type is 'Uint32Array' for 'Binary'", () => { + const dataString = ")(*~^my data for ce#@#$%"; + + const dataBinary = Uint32Array.from(dataString, (c) => c.codePointAt(0) as number); + const expected = asBase64(dataBinary); + + cloudevent = cloudevent.cloneWith({ datacontenttype: "text/plain", data: dataBinary }); + + expect(cloudevent.data_base64).to.equal(expected); + }); + }); +}); diff --git a/test/fun_tests.js b/test/integration/utilities_test.ts similarity index 52% rename from test/fun_tests.js rename to test/integration/utilities_test.ts index 3a042a56..4895b68c 100644 --- a/test/fun_tests.js +++ b/test/integration/utilities_test.ts @@ -1,44 +1,37 @@ -const expect = require("chai").expect; -const fun = require("../lib/utils/fun.js"); +import "mocha"; +import { expect } from "chai"; +import { isStringOrThrow, equalsOrThrow, isBase64, asData } from "../../src/event/validation/is"; -describe("Functional approach", () => { +describe("Utilities", () => { describe("isStringOrThrow", () => { it("should throw when is not a string", () => { - expect(fun.isStringOrThrow.bind(fun, 3.6, { message: "works!" })) - .to - .throw("works!"); + expect(isStringOrThrow.bind({}, 3.6, new Error("works!"))).to.throw("works!"); }); it("should return true when is a string", () => { - expect(fun.isStringOrThrow("cool", { message: "not throws!" })) - .to - .equals(true); + expect(isStringOrThrow("cool", new Error("not throws!"))).to.equal(true); }); }); describe("equalsOrThrow", () => { it("should throw when they are not equals", () => { - expect(fun.equalsOrThrow.bind(fun, "z", "a", { message: "works!" })) - .to - .throw("works!"); + expect(equalsOrThrow.bind({}, "z", "a", new Error("works!"))).to.throw("works!"); }); it("should return true when they are equals", () => { - expect(fun.equalsOrThrow("z", "z", { message: "not throws!" })) - .to - .equals(true); + expect(equalsOrThrow("z", "z", new Error())).to.equal(true); }); }); describe("isBase64", () => { it("should return false when is not base64 string", () => { - const actual = fun.isBase64("non base 64"); + const actual = isBase64("non base 64"); expect(actual).to.equal(false); }); it("should return true when is a base64 string", () => { - const actual = fun.isBase64("Y2xvdWRldmVudHMK"); + const actual = isBase64("Y2xvdWRldmVudHMK"); expect(actual).to.equal(true); }); @@ -48,17 +41,15 @@ describe("Functional approach", () => { it("should throw error when data is not a valid json", () => { const data = "not a json"; - expect(fun.asData.bind(fun, data, "application/json")) - .to - .throws(); + expect(asData.bind({}, data, "application/json")).to.throw(); }); it("should parse string content type as string", () => { const expected = "a string"; - const actual = fun.asData(expected, "text/plain"); + const actual = asData(expected, "text/plain"); - expect((typeof actual)).to.equal("string"); + expect(typeof actual).to.equal("string"); expect(actual).to.equal(expected); }); @@ -66,13 +57,13 @@ describe("Functional approach", () => { const expected = { much: "wow", myext: { - ext: "x04" - } + ext: "x04", + }, }; - const actual = fun.asData(JSON.stringify(expected), "application/json"); + const actual = asData(JSON.stringify(expected), "application/json"); - expect((typeof actual)).to.equal("object"); + expect(typeof actual).to.equal("object"); expect(actual).to.deep.equal(expected); }); @@ -80,14 +71,13 @@ describe("Functional approach", () => { const expected = { much: "wow", myext: { - ext: "x04" - } + ext: "x04", + }, }; - const actual = fun.asData(JSON.stringify(expected), - "application/cloudevents+json"); + const actual = asData(JSON.stringify(expected), "application/cloudevents+json"); - expect((typeof actual)).to.equal("object"); + expect(typeof actual).to.equal("object"); expect(actual).to.deep.equal(expected); }); @@ -95,14 +85,13 @@ describe("Functional approach", () => { const expected = { much: "wow", myext: { - ext: "x04" - } + ext: "x04", + }, }; - const actual = fun.asData(JSON.stringify(expected), - "text/json"); + const actual = asData(JSON.stringify(expected), "text/json"); - expect((typeof actual)).to.equal("object"); + expect(typeof actual).to.equal("object"); expect(actual).to.deep.equal(expected); }); }); diff --git a/test/sdk_test.js b/test/sdk_test.js deleted file mode 100644 index 90e03870..00000000 --- a/test/sdk_test.js +++ /dev/null @@ -1,69 +0,0 @@ -const expect = require("chai").expect; -const v03 = require("../v03/index.js"); -const v1 = require("../v1/index.js"); - -describe("The SDK Requirements", () => { - describe("v0.3", () => { - it("should create an event using the right spec version", () => { - expect(v03.event().spec.payload.specversion).to.equal("0.3"); - }); - - it("should exports 'Spec'", () => { - expect(v03).to.have.property("Spec"); - }); - - it("should exports 'StructuredHTTPEmitter'", () => { - expect(v03).to.have.property("StructuredHTTPEmitter"); - }); - - it("should exports 'StructuredHTTPReceiver'", () => { - expect(v03).to.have.property("StructuredHTTPReceiver"); - }); - - it("should exports 'BinaryHTTPEmitter'", () => { - expect(v03).to.have.property("BinaryHTTPEmitter"); - }); - - it("should exports 'BinaryHTTPReceiver'", () => { - expect(v03).to.have.property("BinaryHTTPReceiver"); - }); - - it("should exports 'HTTPUnmarshaller'", () => { - expect(v03).to.have.property("HTTPUnmarshaller"); - }); - - it("should exports 'event'", () => { - expect(v03).to.have.property("event"); - }); - }); - - describe("v1.0", () => { - it("should create an event using the right spec version", () => { - expect(v1.event().spec.payload.specversion).to.equal("1.0"); - }); - - it("should exports 'Spec'", () => { - expect(v1).to.have.property("Spec"); - }); - - it("should exports 'StructuredHTTPEmitter'", () => { - expect(v1).to.have.property("StructuredHTTPEmitter"); - }); - - it("should exports 'StructuredHTTPReceiver'", () => { - expect(v1).to.have.property("StructuredHTTPReceiver"); - }); - - it("should exports 'BinaryHTTPEmitter'", () => { - expect(v1).to.have.property("BinaryHTTPEmitter"); - }); - - it("should exports 'BinaryHTTPReceiver'", () => { - expect(v1).to.have.property("BinaryHTTPReceiver"); - }); - - it("should exports 'event'", () => { - expect(v1).to.have.property("event"); - }); - }); -}); diff --git a/test/spec_0_3_tests.js b/test/spec_0_3_tests.js deleted file mode 100644 index 2f96acce..00000000 --- a/test/spec_0_3_tests.js +++ /dev/null @@ -1,230 +0,0 @@ -const expect = require("chai").expect; -const Spec03 = require("../lib/specs/spec_0_3.js"); -const { CloudEvent } = require("../index.js"); -const { v4: uuidv4 } = require("uuid"); - -const id = uuidv4(); -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resourse/123"; -const time = new Date(); -const schemaurl = "http://example.com/registry/myschema.json"; -const dataContentEncoding = "base64"; -const dataContentType = "application/json"; -const data = { - much: "wow" -}; -const subject = "subject-x0"; - -const cloudevent = - new CloudEvent(Spec03) - .id(id) - .source(source) - .type(type) - .dataContentType(dataContentType) - .schemaurl(schemaurl) - .subject(subject) - .time(time) - .data(data); - -describe("CloudEvents Spec v0.3", () => { - describe("REQUIRED Attributes", () => { - it("Should have 'id'", () => { - expect(cloudevent.getId()).to.equal(id); - }); - - it("Should have 'source'", () => { - expect(cloudevent.getSource()).to.equal(source); - }); - - it("Should have 'specversion'", () => { - expect(cloudevent.getSpecversion()).to.equal("0.3"); - }); - - it("Should have 'type'", () => { - expect(cloudevent.getType()).to.equal(type); - }); - }); - - describe("OPTIONAL Attributes", () => { - it("Should have 'datacontentencoding'", () => { - cloudevent.dataContentEncoding(dataContentEncoding); - expect(cloudevent.spec.payload.datacontentencoding) - .to.equal(dataContentEncoding); - delete cloudevent.spec.payload.datacontentencoding; - }); - - it("Should have 'datacontenttype'", () => { - expect(cloudevent.getDataContentType()).to.equal(dataContentType); - }); - - it("Should have 'schemaurl'", () => { - expect(cloudevent.getSchemaurl()).to.equal(schemaurl); - }); - - it("Should have 'subject'", () => { - expect(cloudevent.getSubject()).to.equal(subject); - }); - - it("Should have 'time'", () => { - expect(cloudevent.getTime()).to.equal(time.toISOString()); - }); - - it("Should have 'data'", () => { - expect(cloudevent.getData()).to.deep.equal(data); - }); - - it("Should have the 'extension1'", () => { - cloudevent.addExtension("extension1", "value1"); - expect(cloudevent.spec.payload.extension1) - .to.equal("value1"); - }); - - it("should throw an error when use a reserved name as extension", () => { - expect(cloudevent.addExtension.bind(cloudevent, "id")) - .to.throw("Reserved attribute name: 'id'"); - }); - }); - - describe("The Constraints check", () => { - describe("'id'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.id; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.id = id; - }); - - it("should throw an erro when is empty", () => { - cloudevent.spec.payload.id = ""; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.id = id; - }); - }); - - describe("'source'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.source; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.source = source; - }); - }); - - describe("'specversion'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.specversion; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.specversion = "0.3"; - }); - - it("should throw an error when is empty", () => { - cloudevent.spec.payload.specversion = ""; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.specversion = "0.3"; - }); - }); - - describe("'type'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.type; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.type = type; - }); - - it("should throw an error when is an empty string", () => { - cloudevent.type(""); - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.type(type); - }); - - it("must be a non-empty string", () => { - cloudevent.type(type); - expect(cloudevent.spec.payload.type).to.equal(type); - }); - }); - - describe("'datacontentencoding'", () => { - it("should throw an error when is a unsupported encoding", () => { - cloudevent - .data("Y2xvdWRldmVudHMK") - .dataContentEncoding("binary"); - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - delete cloudevent.spec.payload.datacontentencoding; - cloudevent.data(data); - }); - - it("should throw an error when 'data' does not carry base64", - () => { - cloudevent - .data("no base 64 value") - .dataContentEncoding("base64") - .dataContentType("text/plain"); - - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - - delete cloudevent.spec.payload.datacontentencoding; - cloudevent.data(data); - }); - - it("should accept when 'data' is a string", () => { - cloudevent - .data("Y2xvdWRldmVudHMK") - .dataContentEncoding("base64"); - expect(cloudevent.format()).to.have.property("datacontentencoding"); - delete cloudevent.spec.payload.datacontentencoding; - cloudevent.data(data); - }); - }); - - describe("'data'", () => { - it("should maintain the type of data when no data content type", () => { - delete cloudevent.spec.payload.datacontenttype; - cloudevent - .data(JSON.stringify(data)); - - expect(typeof cloudevent.getData()).to.equal("string"); - cloudevent.dataContentType(dataContentType); - }); - - it("should convert data with stringified json to a json object", () => { - cloudevent - .dataContentType(dataContentType) - .data(JSON.stringify(data)); - expect(cloudevent.getData()).to.deep.equal(data); - }); - }); - - describe("'subject'", () => { - it("should throw an error when is an empty string", () => { - cloudevent.subject(""); - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.subject(type); - }); - }); - - describe("'time'", () => { - it("must adhere to the format specified in RFC 3339", () => { - cloudevent.time(time); - expect(cloudevent.format().time).to.equal(time.toISOString()); - }); - }); - }); -}); diff --git a/test/spec_1_tests.js b/test/spec_1_tests.js deleted file mode 100644 index af211f2a..00000000 --- a/test/spec_1_tests.js +++ /dev/null @@ -1,243 +0,0 @@ -const expect = require("chai").expect; -const Spec1 = require("../lib/specs/spec_1.js"); -const { CloudEvent } = require("../index.js"); -const { v4: uuidv4 } = require("uuid"); -const { asBase64 } = require("../lib/utils/fun.js"); - -const id = uuidv4(); -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resource/123"; -const time = new Date(); -const dataschema = "http://example.com/registry/myschema.json"; -const dataContentType = "application/json"; -const data = { - much: "wow" -}; -const subject = "subject-x0"; - -const cloudevent = - new CloudEvent(Spec1) - .id(id) - .source(source) - .type(type) - .dataContentType(dataContentType) - .dataschema(dataschema) - .subject(subject) - .time(time) - .data(data); - -describe("CloudEvents Spec v1.0", () => { - describe("REQUIRED Attributes", () => { - it("Should have 'id'", () => { - expect(cloudevent.getId()).to.equal(id); - }); - - it("Should have 'source'", () => { - expect(cloudevent.getSource()).to.equal(source); - }); - - it("Should have 'specversion'", () => { - expect(cloudevent.getSpecversion()).to.equal("1.0"); - }); - - it("Should have 'type'", () => { - expect(cloudevent.getType()).to.equal(type); - }); - }); - - describe("OPTIONAL Attributes", () => { - it("Should have 'datacontenttype'", () => { - expect(cloudevent.getDataContentType()).to.equal(dataContentType); - }); - - it("Should have 'dataschema'", () => { - expect(cloudevent.getDataschema()).to.equal(dataschema); - }); - - it("Should have 'subject'", () => { - expect(cloudevent.getSubject()).to.equal(subject); - }); - - it("Should have 'time'", () => { - expect(cloudevent.getTime()).to.equal(time.toISOString()); - }); - }); - - describe("Extensions Constraints", () => { - it("should be ok when type is 'boolean'", () => { - cloudevent.addExtension("ext-boolean", true); - expect(cloudevent.spec.payload["ext-boolean"]) - .to.equal(true); - }); - - it("should be ok when type is 'integer'", () => { - cloudevent.addExtension("ext-integer", 2019); - expect(cloudevent.spec.payload["ext-integer"]) - .to.equal(2019); - }); - - it("should be ok when type is 'string'", () => { - cloudevent.addExtension("ext-string", "an-string"); - expect(cloudevent.spec.payload["ext-string"]) - .to.equal("an-string"); - }); - - it("should be ok when type is 'Uint32Array' for 'Binary'", () => { - const myBinary = new Uint32Array(2019); - cloudevent.addExtension("ext-binary", myBinary); - expect(cloudevent.spec.payload["ext-binary"]) - .to.equal(myBinary); - }); - - // URI - - it("should be ok when type is 'Date' for 'Timestamp'", () => { - const myDate = new Date(); - cloudevent.addExtension("ext-date", myDate); - expect(cloudevent.spec.payload["ext-date"]) - .to.equal(myDate); - }); - - it("Should have the 'extension1'", () => { - cloudevent.addExtension("extension1", "value1"); - expect(cloudevent.spec.payload.extension1) - .to.equal("value1"); - }); - - it("should throw an error when use a reserved name as extension", () => { - expect(cloudevent.addExtension.bind(cloudevent, "id")) - .to.throw("Reserved attribute name: 'id'"); - }); - - it("should throw an error when use an invalid type", () => { - expect(cloudevent - .addExtension.bind(cloudevent, "invalid-val", { cool: "nice" })) - .to.throw("Invalid type of extension value"); - }); - }); - - describe("The Constraints check", () => { - describe("'id'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.id; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.id = id; - }); - - it("should throw an error when is empty", () => { - cloudevent.spec.payload.id = ""; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.id = id; - }); - }); - - describe("'source'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.source; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.source = source; - }); - }); - - describe("'specversion'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.specversion; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.specversion = "1.0"; - }); - - it("should throw an error when is empty", () => { - cloudevent.spec.payload.specversion = ""; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.specversion = "1.0"; - }); - }); - - describe("'type'", () => { - it("should throw an error when is absent", () => { - delete cloudevent.spec.payload.type; - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.spec.payload.type = type; - }); - - it("should throw an error when is an empty string", () => { - cloudevent.type(""); - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.type(type); - }); - - it("must be a non-empty string", () => { - cloudevent.type(type); - expect(cloudevent.spec.payload.type).to.equal(type); - }); - }); - - describe("'subject'", () => { - it("should throw an error when is an empty string", () => { - cloudevent.subject(""); - expect(cloudevent.format.bind(cloudevent)) - .to - .throw("invalid payload"); - cloudevent.subject(type); - }); - }); - - describe("'time'", () => { - it("must adhere to the format specified in RFC 3339", () => { - cloudevent.time(time); - expect(cloudevent.format().time).to.equal(time.toISOString()); - }); - }); - }); - - describe("Event data constraints", () => { - it("Should have 'data'", () => { - expect(cloudevent.getData()).to.deep.equal(data); - }); - - it("should maintain the type of data when no data content type", () => { - delete cloudevent.spec.payload.datacontenttype; - cloudevent - .data(JSON.stringify(data)); - - expect(typeof cloudevent.getData()).to.equal("string"); - cloudevent.dataContentType(dataContentType); - }); - - it("should convert data with stringified json to a json object", () => { - cloudevent - .dataContentType(dataContentType) - .data(JSON.stringify(data)); - expect(cloudevent.getData()).to.deep.equal(data); - }); - - it("should be ok when type is 'Uint32Array' for 'Binary'", () => { - const dataString = ")(*~^my data for ce#@#$%"; - - const dataBinary = Uint32Array.from(dataString, (c) => c.codePointAt(0)); - const expected = asBase64(dataBinary); - const olddct = cloudevent.getDataContentType(); - - cloudevent - .dataContentType("text/plain") - .data(dataBinary); - expect(cloudevent.getData()).to.deep.equal(expected); - - cloudevent.dataContentType(olddct); - }); - }); -}); diff --git a/tsconfig.browser.json b/tsconfig.browser.json new file mode 100644 index 00000000..23d99a44 --- /dev/null +++ b/tsconfig.browser.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "allowJs": true, /* Allow javascript files to be compiled. */ + "checkJs": false, /* Report errors in .js files. */ + "strict": true, /* Enable all strict type-checking options. */ + "baseUrl": ".", + "outDir": "./browser", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "lib": ["es2016", "dom", "es5"] + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..4f9f4200 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "allowJs": true, /* Allow javascript files to be compiled. */ + "checkJs": false, /* Report errors in .js files. */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ + "outDir": "./dist", + "declaration": true, + "experimentalDecorators": true + }, + "compileOnSave": true, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules" + ], + "typedocOptions": { + "out": "docs", + "mode": "file", + "theme": "node_modules/typedoc-clarity-theme/bin" + } +} diff --git a/v03/index.js b/v03/index.js deleted file mode 100644 index 0567070e..00000000 --- a/v03/index.js +++ /dev/null @@ -1,28 +0,0 @@ -const CloudEvent = require("../lib/cloudevent.js"); -const Spec = require("../lib/specs/spec_0_3.js"); -const StructuredHTTPEmitter = - require("../lib/bindings/http/emitter_structured.js"); -const BinaryHTTPEmitter = require("../lib/bindings/http/emitter_binary_0_3.js"); - -const StructuredHTTPReceiver = - require("../lib/bindings/http/receiver_structured_0_3.js"); - -const BinaryHTTPReceiver = - require("../lib/bindings/http/receiver_binary_0_3.js"); - -const HTTPUnmarshaller = require("../lib/bindings/http/unmarshaller_0_3.js"); - -function newEvent() { - return new CloudEvent(Spec); -} - -module.exports = { - Spec, - StructuredHTTPEmitter, - StructuredHTTPReceiver, - BinaryHTTPEmitter, - BinaryHTTPReceiver, - HTTPUnmarshaller, - CloudEvent: newEvent, - event: newEvent -}; diff --git a/v1/index.js b/v1/index.js deleted file mode 100644 index 3197dab5..00000000 --- a/v1/index.js +++ /dev/null @@ -1,27 +0,0 @@ -const CloudEvent = require("../lib/cloudevent.js"); -const Spec = require("../lib/specs/spec_1.js"); - -const StructuredHTTPEmitter = - require("../lib/bindings/http/emitter_structured.js"); - -const BinaryHTTPEmitter = require("../lib/bindings/http/emitter_binary_1.js"); - -const StructuredHTTPReceiver = - require("../lib/bindings/http/receiver_structured_1.js"); - -const BinaryHTTPReceiver = - require("../lib/bindings/http/receiver_binary_1.js"); - -function newEvent() { - return new CloudEvent(Spec); -} - -module.exports = { - Spec, - StructuredHTTPEmitter, - BinaryHTTPEmitter, - StructuredHTTPReceiver, - BinaryHTTPReceiver, - CloudEvent: newEvent, - event: newEvent -}; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..17e664cf --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,16 @@ +const path = require("path"); + +module.exports = { + entry: { + "cloudevents-sdk": "./browser/index.js" + }, + output: { + path: path.resolve(__dirname, "bundles"), + filename: "[name].js", + libraryTarget: "umd", + library: "cloudevents-sdk", + umdNamedDefine: true + }, + devtool: "source-map", + mode: "production" +};