diff --git a/.github/workflows/pull-request-integration-testing.yml b/.github/workflows/pull-request-integration-testing.yml new file mode 100644 index 000000000..72b20423a --- /dev/null +++ b/.github/workflows/pull-request-integration-testing.yml @@ -0,0 +1,32 @@ +name: Pull request integration testing + +on: + pull_request: + types: [synchronize] + +jobs: + test: + if: github.event.pull_request.draft == false + name: 'Run linter and tests' + runs-on: ubuntu-latest + services: + nats: + image: nats + ports: + - 4222 + restart: unless-stopped + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 13 + - name: Install dependencies + run: npm ci + - name: Generate and build examples + run: npm run test:examples:integration + env: + NATS_HOST: nats + NATS_PORT: ${{ job.services.redis.ports['6379'] }} + \ No newline at end of file diff --git a/.github/workflows/pull-request-testing.yml b/.github/workflows/pull-request-testing.yml new file mode 100644 index 000000000..fd0eadc95 --- /dev/null +++ b/.github/workflows/pull-request-testing.yml @@ -0,0 +1,23 @@ +name: Pull request testing + +on: + pull_request + +jobs: + release: + name: 'Run linter and tests' + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 13 + - name: Install dependencies + run: npm ci + - name: Run linter + run: npm run lint + - name: Run tests + run: npm test + \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..24117d005 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,60 @@ +name: Release + +on: + push: + branches: + - master + +jobs: + release: + name: 'Release NPM, GitHub' + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 13 + - name: Install dependencies + run: npm ci + - name: Run tests + run: npm test + - name: Re-generate examples + run: npm generate:examples + - name: Get version from package.json before release step + id: initversion + run: echo "::set-output name=version::$(npm run get-version --silent)" + - name: Release to NPM and GitHub + id: release + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_AUTHOR_NAME: asyncapi-bot + GIT_AUTHOR_EMAIL: info@asyncapi.io + GIT_COMMITTER_NAME: asyncapi-bot + GIT_COMMITTER_EMAIL: info@asyncapi.io + run: npm run release + - name: Get version from package.json after release step + id: extractver + run: echo "::set-output name=version::$(npm run get-version --silent)" + - name: Create Pull Request with updated package files + if: steps.initversion.outputs.version != steps.extractver.outputs.version + uses: peter-evans/create-pull-request@v2.4.4 + with: + token: ${{ secrets.GH_TOKEN }} + commit-message: 'chore(release): ${{ steps.extractver.outputs.version }}' + committer: asyncapi-bot + author: asyncapi-bot + title: 'chore(release): ${{ steps.extractver.outputs.version }}' + body: 'Version bump in package.json and package-lock.json for release [${{ steps.extractver.outputs.version }}](https://github.com/${{github.repository}}/releases/tag/v${{ steps.extractver.outputs.version }})' + branch: version-bump/${{ steps.extractver.outputs.version }} + - name: Publish information about the release to Twitter + if: steps.initversion.outputs.version != steps.extractver.outputs.version + uses: m1ner79/Github-Twittction@v1.0.1 + with: + twitter_status: "Release ${{ steps.extractver.outputs.version }} for ${{github.repository}} is out in the wild 😱πŸ’ͺπŸΎπŸŽ‚\n\nThank you for the contribution ${{ github.event.commits[0].author.name }} https://github.com/${{github.repository}}/releases/tag/v${{ steps.extractver.outputs.version }}" + twitter_consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }} + twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }} + twitter_access_token_key: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }} + twitter_access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} diff --git a/.github/workflows/sentiment-analysis.yml b/.github/workflows/sentiment-analysis.yml deleted file mode 100644 index 90607cfe6..000000000 --- a/.github/workflows/sentiment-analysis.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: 'Sentiment Analysis' - -on: - issue_comment: - types: - - created - - edited - issues: - types: - - opened - - edited - pull_request: - types: - - opened - - edited - pull_request_review: - types: - - submitted - - edited - pull_request_review_comment: - types: - - created - - edited -jobs: - test: - name: Checking sentiments - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Check sentiment - uses: derberg/code-of-conduct-sentiment-analysis-github-action@v1 - id: sentiments - with: - gcp_key: ${{ secrets.GCP_KEY_SENTIMENT }} - - uses: someimportantcompany/github-actions-slack-message@v1 - # this step runs only if sentiment is a negative number - if: steps.sentiments.outputs.sentiment < -0.6 - with: - webhook-url: ${{ secrets.SLACK_SENTIMENTS }} - text: Here ${{steps.sentiments.outputs.source}} you can find a potential negative text that requires your attention as the sentiment analysis score is ${{steps.sentiments.outputs.sentiment}} - color: orange \ No newline at end of file diff --git a/.github/workflows/stale-issues-prs.yml b/.github/workflows/stale-issues-prs.yml new file mode 100644 index 000000000..4cb32bf98 --- /dev/null +++ b/.github/workflows/stale-issues-prs.yml @@ -0,0 +1,27 @@ +name: Manage stale issues and PRs + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v1.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: | + This issue has been automatically marked as stale because it has not had recent activity :sleeping: + It will be closed in 30 days if no further activity occurs. To unstale this issue, add a comment with detailed explanation. + Thank you for your contributions :heart: + stale-pr-message: | + This pull request has been automatically marked as stale because it has not had recent activity :sleeping: + It will be closed in 30 days if no further activity occurs. To unstale this pull request, add a comment with detailed explanation. + Thank you for your contributions :heart: + days-before-stale: 60 + days-before-close: 30 + stale-issue-label: stale + stale-pr-label: stale + exempt-issue-label: keep-open + exempt-pr-label: keep-open \ No newline at end of file diff --git a/.github/workflows/welcome-first-time-contrib.yml b/.github/workflows/welcome-first-time-contrib.yml deleted file mode 100644 index 554300ba8..000000000 --- a/.github/workflows/welcome-first-time-contrib.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Welcome first time contributors - -on: - pull_request_target: - types: - - opened - issues: - types: - - opened - -jobs: - welcome: - runs-on: ubuntu-latest - steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: | - Welcome to AsyncAPI. Thanks a lot for reporting your first issue. - - Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115). - pr-message: | - Welcome to AsyncAPI. Thanks a lot for creating your first pull request. - - Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115). diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1d077b3a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +test/actual_comparators/* +dist \ No newline at end of file diff --git a/README.md b/README.md index 2a1f5f1d6..4061e0cd0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,257 @@ -# ts-nats-template -Typescript template for NATS +

TypeScript/Node.js NATS template

+

+ This is a TypeScript/Node.js NATS template for the AsyncAPI generator. +

+ +This template is for generating a TypeScript/Node.js NATS client based on an AsyncAPI document. The template is based on the [nats-ts](https://github.com/nats-io/nats.ts) library and can be used as both a TypeScript and Node.js library. + +# How to use +Example generations can be found under [examples](./examples) which includes [publish and subscribe](./examples/publish%20subscribe) example as well as [request and reply](./examples/request%20reply). +## Requirements +* @asyncapi/generator < v2.0.0 >v1.0.0 + +Install the generator through [npm or run it from docker official installer](https://github.com/asyncapi/generator#install). + +## Example usage +The leading examples are both in TypeScript and in Node.js since this template can be used for both. The example code will be used later in the documentation for to explain the different features. + +Given any AsyncAPI file (`AsyncAPI.yml`) first generate the client with the [AsyncAPI generator](https://github.com/asyncapi/generator) such as +```bash +ag --install --output ./nats-client ./AsyncAPI.yml @asyncapi/ts-nats-template --param "generateTestClient=true" --param "promisifyReplyCallback=true" +``` + +Afterward, go into the generated folder `nats-client` and run the commands `npm i` and `npm run build`. The generated NATS client is now ready to be used in either TypeScript or Node.js. + +### TypeScript + +```js +import * as GeneratedClient from "./nats-client"; +const natsClient = new GeneratedClient.NatsAsyncApiClient(); +async function connect(){ + try{ + await natsClient.connect({url: "nats://demo.nats.io:4222", reconnectTimeWait: 1000, reconnect: true, maxReconnectAttempts: -1}); + }catch(e){ + console.log(e); + } +} +connect(); +``` + +### Node.js +```js +const GeneratedClient = require("./nats-client"); +const natsClient = new GeneratedClient.NatsAsyncApiClient(); +async function connect(){ + try{ + await natsClient.connect({url: "nats://demo.nats.io:4222", reconnectTimeWait: 1000, reconnect: true, maxReconnectAttempts: -1}); + }catch(e){ + console.log(e); + } +} +connect(); +``` + +# Features +* Supports wildcard channels. AsyncAPI describes the channel path to be defined as [RFC 6570 URI](https://www.asyncapi.com/docs/specifications/2.0.0/#a-name-channelsobject-a-channels-object). So a channel containing a wildcard needs to be defined with parameters such as `smartylighting/streetlights/{wildcard}`. +* Supports [test/mirror client](#test-client) for testing or other useful scenarios. +* This template can be used as a NodeJS library. +* This template uses [quicktype](https://quicktype.io/) to generate the corresponding message payloads. + +# Restrictions +* Empty objects are not supported, use `null` types instead. +* Recursive objects are not currently supported. + +# Connection options +Currently the generated client offers 4 standard methods of connecting to your NATS server `connectWithUserCreds`, `connectWithUserPass`, `connectToHost` and `connectWithNkey`. If you need something customized use the standard `connect` method with your custom options. Currently, the template does not care which security details you have defined in your AsyncAPI document. + +# Available events +The generated client can emit multiple events, all of these are directly from the [nats-ts](https://github.com/nats-io/nats.ts#notifications) library. Where the errors are wrapped in a custom `NatsTypescriptTemplateError` type. + +## TypeScript example +```js +import {AvailableEvents, NatsAsyncApiClient, NatsTypescriptTemplateError, Client, ServerInfo, ServersChangedEvent, SubEvent} from "nats-client"; +const natsClient = new NatsAsyncApiClient(); + +natsClient.on(AvailableEvents.permissionError, (e: NatsTypescriptTemplateError) => { + console.log("NatsAsyncApiClient permissionError"); + console.log(e); +}); +natsClient.on(AvailableEvents.close, (e: NatsTypescriptTemplateError) => { + console.log("NatsAsyncApiClient close"); + console.log(e); +}); +natsClient.on(AvailableEvents.connect, (connection: Client, serverURL: string, info: ServerInfo) => { + console.log("NatsAsyncApiTestClient connect"); + console.log({connection, serverURL, info}); +}); +natsClient.on(AvailableEvents.connecting, (serverURL: string) => { + console.log("NatsAsyncApiClient connecting"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.disconnect, (serverURL: string) => { + console.log("NatsAsyncApiClient disconnect"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.error, (e: NatsTypescriptTemplateError) => { + console.log("NatsAsyncApiClient error"); + console.log(e); +}); +natsClient.on(AvailableEvents.pingcount, () => { + console.log("NatsAsyncApiClient pingcount"); +}); +natsClient.on(AvailableEvents.pingtimer, () => { + console.log("NatsAsyncApiClient pingtimer"); +}); +natsClient.on(AvailableEvents.reconnect, (connection: Client, serverURL: string, info: ServerInfo) => { + console.log("NatsAsyncApiClient reconnect"); + console.log({connection, serverURL, info}); +}); +natsClient.on(AvailableEvents.reconnecting, (serverURL: string) => { + console.log("NatsAsyncApiClient reconnecting"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.serversChanged, (e: ServersChangedEvent) => { + console.log("NatsAsyncApiClient serversChanged"); + console.log(e); +}); +natsClient.on(AvailableEvents.subscribe, (e: SubEvent) => { + console.log("NatsAsyncApiClient subscribe"); + console.log(e); +}); +natsClient.on(AvailableEvents.unsubscribe, (e: SubEvent) => { + console.log("NatsAsyncApiClient unsubscribe"); + console.log(e); +}); +natsClient.on(AvailableEvents.yield, () => { + console.log("NatsAsyncApiClient yield"); +}); +``` +## Node.js example +```js +const {AvailableEvents, NatsAsyncApiClient} = require("nats-client"); +const natsClient = new NatsAsyncApiClient(); +natsClient.on(AvailableEvents.permissionError, (e) => { + console.log("NatsAsyncApiClient permissionError"); + console.log(e); +}); +natsClient.on(AvailableEvents.close, (e) => { + console.log("NatsAsyncApiClient close"); + console.log(e); +}); +natsTestClient.on(AvailableEvents.connect, async (connection, serverURL, info) => { + console.log("NatsAsyncApiTestClient connect"); + console.log({connection, serverURL, info}); +}); +natsClient.on(AvailableEvents.connect, (connection, serverURL, info) => { + console.log("NatsAsyncApiClient connect"); + console.log({connection, serverURL, info}); +}); +natsClient.on(AvailableEvents.connecting, (serverURL) => { + console.log("NatsAsyncApiClient connecting"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.disconnect, (serverURL) => { + console.log("NatsAsyncApiClient disconnect"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.error, (e) => { + console.log("NatsAsyncApiClient error"); + console.log(e); +}); +natsClient.on(AvailableEvents.pingcount, () => { + console.log("NatsAsyncApiClient pingcount"); +}); +natsClient.on(AvailableEvents.pingtimer, () => { + console.log("NatsAsyncApiClient pingtimer"); +}); +natsClient.on(AvailableEvents.reconnect, (connection, serverURL, info) => { + console.log("NatsAsyncApiClient reconnect"); + console.log({connection, serverURL, info}); +}); +natsClient.on(AvailableEvents.reconnecting, (serverURL) => { + console.log("NatsAsyncApiClient reconnecting"); + console.log(serverURL); +}); +natsClient.on(AvailableEvents.serversChanged, (e) => { + console.log("NatsAsyncApiClient serversChanged"); + console.log(e); +}); +natsClient.on(AvailableEvents.subscribe, (e) => { + console.log("NatsAsyncApiClient subscribe"); + console.log(e); +}); +natsClient.on(AvailableEvents.unsubscribe, (e) => { + console.log("NatsAsyncApiClient unsubscribe"); + console.log(e); +}); +natsClient.on(AvailableEvents.yield, () => { + console.log("NatsAsyncApiClient yield"); +}); +``` + +# Template Parameters +These are the available template parameters: +|Parameter|Type|Description| +|---|---|---| +| generateTestClient | Boolean | Use this parameter to generate the [test client](#test-client). Add the following to the CLI when generating your code `--param "generateTestClient=true"` +| promisifyReplyCallback | Boolean | Use this parameter to change from the default regular callback when using the request operation. Add the following to the CLI when generating your code `--param "promisifyReplyCallback=true"` + +# Test Client +The test client is like a mirror client. It does everything the opposite, when you define a subscription operation it will generate a subscription operation in the test client. This is opposite to what the specification dictates. This client can be used to create integration tests or in other useful scenarios. + +# Supported Content Types +The following payload types are supported, this is limited to the underlying NATS TypeScript library: + +* For binary payloads use: `binary` content type +* For json payloads use: `json` content type +* For string payloads use: `string` content type + +# Client Hooks + +Sometimes to you want to change the data before sending or reciving it. For this purpose hooks has been added to control the flow of information outside the generated code. The hooks can be used to alter the payload before sending or after recieving any data i.e. encrypt, compress data, etc. It is possible to register as many hooks as you want however there are certain restrictions, see [hook restrictions](#Hook-restrictions). + + +These are the available hooks: +|Hookname|Callback type|Description| +|---|---|---| +| BeforeSendingData | (messageToSend: any) => any | Called before sending any data. +| receivedData | (receivedData: any) => any | Hook is called after data is received before the client tries to peace the message back together. + +## Node.js example +This example uses the msgpack library to encode and decode the message before sending and receiving data. +```js +const {AvailableEvents, NatsAsyncApiClient, Hooks} = require("nats-client"); +const natsClient = new NatsAsyncApiClient(); +const msgpack = require("msgpack-lite"); +function encode(msg){ + console.log("encode"); + console.log(msg); + // encode from JS Object to MessagePack (Buffer) + return msgpack.encode(msg); +} +function decode(msg){ + // decode from MessagePack (Buffer) to JS Object + console.log("Decoding"); + console.log(msg); + return msgpack.decode(msg.data); // => {"foo": "bar"} +} +Hooks.getInstance().registerBeforeSendingData(encode); +Hooks.getInstance().registerreceivedData(decode); +``` +## Hook restrictions +There are different hook restrictions based on the payload type. + +### Binary payloads +If you only have 1 hook then you must ensure that it returns a buffer. + +If you have multiple hooks then the following applies: The first hook always receives the message type as is. Any intermediary hooks receives what the last hook returned and can return any type of your choosing. The last hook is required to return a buffer to transmit. + +### JSON payloads +If you only have 1 hook then you must ensure that it returns a JSON object. + +If you have multiple hooks then the following applies: The first hook always receives the message type as is. Any intermediary hooks can return any type of your choosing. The last hook is required to return a JSON object. + +### String payloads +If you only have 1 hook then you must ensure that it returns a string. + +If you have multiple hooks then the following applies: The first hook always receives the message type as is. Any intermediary hooks can return any type of your choosing. The last hook is required to return a string representation of the message. diff --git a/examples/GenerateAndTest.sh b/examples/GenerateAndTest.sh new file mode 100755 index 000000000..808091fc9 --- /dev/null +++ b/examples/GenerateAndTest.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -x + +cd ./publish\ subscribe +sh ./GenerateAndBuild.sh +sh ./Test.sh + +cd ../../request\ reply +sh ./GenerateAndBuild.sh +sh ./Test.sh + +cd ../../ \ No newline at end of file diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml new file mode 100644 index 000000000..a452dd335 --- /dev/null +++ b/examples/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3.0' +services: + nats: + image: nats + ports: + - 4222:4222 + restart: unless-stopped diff --git a/examples/publish subscribe/GenerateAndBuild.sh b/examples/publish subscribe/GenerateAndBuild.sh new file mode 100755 index 000000000..26222ece6 --- /dev/null +++ b/examples/publish subscribe/GenerateAndBuild.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ag --install --output "./streetlight" "./streetlight.json" "../../" --force-write --param "generateTestClient=true" --param "promisifyReplyCallback=true" && cd ./streetlight && npm i && npm run build && cd .. \ No newline at end of file diff --git a/examples/publish subscribe/Test.sh b/examples/publish subscribe/Test.sh new file mode 100755 index 000000000..3bcad8e5f --- /dev/null +++ b/examples/publish subscribe/Test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cd ./streetlight && npm run test:integration \ No newline at end of file diff --git a/examples/publish subscribe/streetlight.json b/examples/publish subscribe/streetlight.json new file mode 100644 index 000000000..b619ce0cb --- /dev/null +++ b/examples/publish subscribe/streetlight.json @@ -0,0 +1,63 @@ +{ + "asyncapi": "2.0.0", + "info": { + "title": "Streetlight", + "version": "1.0.0" + }, + "defaultContentType": "json", + "channels": { + "streetlight/{streetlight_id}/command/turnon": { + "description": "Channel for the turn on command which should turn on the streetlight", + "parameters": { + "streetlight_id": { + "description": "The ID of the streetlight", + "schema": { + "type": "string" + } + } + }, + "publish": { + "operationId": "Listen when to turn on the streetlight", + "message": { + "name": "TurnonCommand", + "payload": { + "type": "object", + "required": ["lumen"], + "properties": { + "lumen": { + "type": "integer", + "description": "How bright should the light be." + } + } + } + } + } + }, + "streetlight/{streetlight_id}/event/turnon": { + "description": "Channel for when the streetlight is turned on", + "parameters": { + "streetlight_id": { + "description": "The ID of the streetlight", + "schema": { + "type": "string" + } + } + }, + "subscribe": { + "operationId": "Publish when the streetlight gets turned on", + "message": { + "payload": { + "type": "object", + "required": ["lumen"], + "properties": { + "lumen": { + "type": "integer", + "description": "How bright should the light be." + } + } + } + } + } + } + } +} diff --git a/examples/publish subscribe/streetlight/README.md b/examples/publish subscribe/streetlight/README.md new file mode 100644 index 000000000..8efb38d46 --- /dev/null +++ b/examples/publish subscribe/streetlight/README.md @@ -0,0 +1,7 @@ +# Streetlight + + + + +Available nats encodings: +https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings diff --git a/examples/publish subscribe/streetlight/package-lock.json b/examples/publish subscribe/streetlight/package-lock.json new file mode 100644 index 000000000..612ff2124 --- /dev/null +++ b/examples/publish subscribe/streetlight/package-lock.json @@ -0,0 +1,1011 @@ +{ + "name": "streetlight", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chai": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz", + "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==", + "dev": true + }, + "@types/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-Ibfb2jgpjYUxnl7RSVvUzOrv/vhkTVKEfPwQf9ZlDDsSyWVDp/2JtTBxO4eRrKBYtxc3cZQabdR38i8R0o1uww==", + "requires": { + "@types/node": "*" + } + }, + "@types/mocha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.4.tgz", + "integrity": "sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ==", + "dev": true + }, + "@types/node": { + "version": "13.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.5.tgz", + "integrity": "sha512-hkzMMD3xu6BrJpGVLeQ3htQQNAcOrJjX7WFmtK8zWQpz2UJf13LCFF2ALA7c9OVdvc2vQJeDdjfR35M0sBCxvw==" + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "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", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "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 + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "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 + }, + "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 + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "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" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "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 + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "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 + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "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 + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + } + }, + "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 + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nuid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/nuid/-/nuid-1.1.4.tgz", + "integrity": "sha512-PXiYyHhGfrq8H4g5HyC8enO1lz6SBe5z6x1yx/JG4tmADzDGJVQy3l1sRf3VtEvPsN8dGn9hRFRwDKWL62x0BA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-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 + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "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" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "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 + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "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 + }, + "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-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" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "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" + } + }, + "ts-nats": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ts-nats/-/ts-nats-1.2.4.tgz", + "integrity": "sha512-bIC+PlwHplRqhooa9kE+QPcQ9RPGUXD2ruvdf6LoFpP6MjE6exVoRhYSydm0e5wk7VfuXpTbH1NoopTKHwlOKA==", + "requires": { + "nuid": "^1.1.0", + "ts-nkeys": "^1.0.12" + } + }, + "ts-nkeys": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/ts-nkeys/-/ts-nkeys-1.0.16.tgz", + "integrity": "sha512-1qrhAlavbm36wtW+7NtKOgxpzl+70NTF8xlz9mEhiA5zHMlMxjj3sEVKWm3pGZhHXE0Q3ykjrj+OSRVaYw+Dqg==", + "requires": { + "tweetnacl": "^1.0.3" + } + }, + "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 + } + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "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 + }, + "typescript": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz", + "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "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" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "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 + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "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/examples/publish subscribe/streetlight/package.json b/examples/publish subscribe/streetlight/package.json new file mode 100644 index 000000000..776edc8e7 --- /dev/null +++ b/examples/publish subscribe/streetlight/package.json @@ -0,0 +1,26 @@ +{ + "name": "streetlight", + "description": "", + "version": "1.0.0", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "watch": "tsc --watch", + "build": "tsc", + "test:integration": "./node_modules/.bin/mocha -r ts-node/register src/tests/**/*.spec.ts" + }, + "dependencies": { + "@types/klaw-sync": "^6.0.0", + "@types/node": "13.9.5", + "ts-nats": "1.2.4", + "typescript": "3.4.3", + "ts-nkeys": "1.0.16" + }, + "devDependencies": { + "ts-node": "^8.10.2", + "@types/mocha": "^8.0.4", + "@types/chai": "^4.2.14", + "chai": "^4.2.0", + "mocha": "^8.2.1" + } +} diff --git a/examples/publish subscribe/streetlight/src/NatsTypescriptTemplateError.ts b/examples/publish subscribe/streetlight/src/NatsTypescriptTemplateError.ts new file mode 100644 index 000000000..07ad37c3e --- /dev/null +++ b/examples/publish subscribe/streetlight/src/NatsTypescriptTemplateError.ts @@ -0,0 +1,70 @@ + +import * as util from 'util'; + +export enum ErrorCode { + NOT_CONNECTED = 'NOT_CONNECTED', + INTERNAL_NATS_TS_ERROR = 'INTERNAL_NATS_TS_ERROR', + HOOK_ERROR = 'HOOK_ERROR' +} + +/** @internal **/ +export class Messages { + static messages = new Messages(); + messages: { [key: string]: string } = {}; + + private constructor() { + this.messages[ErrorCode.NOT_CONNECTED] = 'The client is not connected'; + this.messages[ErrorCode.INTERNAL_NATS_TS_ERROR] = 'An error occured while trying to use the Nats Typescript library'; + this.messages[ErrorCode.HOOK_ERROR] = 'An error occured while trying to call one of the hooks.'; + } + + static getMessage(s: string): string { + return Messages.messages.getMessage(s); + } + + getMessage(s: string): string { + let v = this.messages[s]; + if (!v) { + v = s; + } + return v; + } +} +export class NatsTypescriptTemplateError implements Error { + + name: string; + message: string; + code: string; + chainedError?: Error; + + /** + * @param {String} message + * @param {String} code + * @param {Error} [chainedError] + * @constructor + * + * @api private + * @internal + */ + constructor(message: string, code: string, chainedError?: Error) { + Error.captureStackTrace(this, this.constructor); + this.name = 'NatsTypescriptTemplateError'; + this.message = message; + this.code = code; + this.chainedError = chainedError; + + util.inherits(NatsTypescriptTemplateError, Error); + } + + /** + * @param code + * @param chainedError + * @api private + * @internal + */ + static errorForCode(code: string, chainedError?: Error): NatsTypescriptTemplateError { + let m = Messages.getMessage(code); + return new NatsTypescriptTemplateError(m, code, chainedError); + } +} + diff --git a/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts b/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts new file mode 100644 index 000000000..de1497c19 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts @@ -0,0 +1,60 @@ + +import * as TurnonCommandMessage from '../messages/TurnonCommand' +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../NatsTypescriptTemplateError'; +import { Hooks } from '../hooks'; + +export function subscribe( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: TurnonCommandMessage.TurnonCommand, streetlight_id?: string) => void, + nc: Client + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + let subscribeOptions: SubscriptionOptions = {... options}; + + try{ + let subscription = nc.subscribe(`streetlight.${streetlight_id}.command.turnon`, (err, msg) => { + if(err){ + onDataCallback(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, err)); + }else{ + +var unmodifiedChannel = `streetlight.{streetlight_id}.command.turnon`; +var channel = msg.subject; + var streetlightIdSplit = unmodifiedChannel.split("{streetlight_id}"); + +const splits = [ + streetlightIdSplit[0], + streetlightIdSplit[1] +]; +channel = channel.substring(splits[0].length); +var streetlightIdEnd = channel.indexOf(splits[1]); +var streetlightIdParam = "" + channel.substring(0, streetlightIdEnd); + + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + onDataCallback(undefined, receivedData, + streetlightIdParam); + } + }, subscribeOptions); + resolve(subscription); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + + diff --git a/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts b/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts new file mode 100644 index 000000000..b53c775e0 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts @@ -0,0 +1,36 @@ + +import * as AnonymousMessage2Message from '../messages/AnonymousMessage2' +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../NatsTypescriptTemplateError'; +import { Hooks } from '../hooks'; + +export function publish( + message: AnonymousMessage2Message.AnonymousMessage2, + nc: Client + + ,streetlight_id: string + + ): Promise { + return new Promise(async (resolve, reject) => { + try{ + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + await nc.publish(`streetlight.${streetlight_id}.event.turnon`, dataToSend); + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }); +}; + diff --git a/examples/publish subscribe/streetlight/src/hooks.ts b/examples/publish subscribe/streetlight/src/hooks.ts new file mode 100644 index 000000000..d4528c513 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/hooks.ts @@ -0,0 +1,57 @@ +export enum AvailableHooks { + receivedData = 'receivedData', + BeforeSendingData = 'BeforeSendingData' +} +export type receivedDataHook = (receivedData: any) => string; +export type BeforeSendingDataHook = (messageToSend: any) => string; +export class Hooks { + private static instance: Hooks; + + private hooks: { + BeforeSendingData: BeforeSendingDataHook[]; + receivedData: receivedDataHook[]; + }; + private constructor() { + this.hooks = { + BeforeSendingData: [], + receivedData: [] + } + } + public static getInstance(): Hooks { + if (!Hooks.instance) { + Hooks.instance = new Hooks(); + } + return Hooks.instance; + } + + + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerBeforeSendingData(hook: BeforeSendingDataHook) { + this.hooks[AvailableHooks.BeforeSendingData] + ? this.hooks[AvailableHooks.BeforeSendingData].push(hook) + : [hook]; + } + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerreceivedData(hook: receivedDataHook) { + this.hooks[AvailableHooks.receivedData] + ? this.hooks[AvailableHooks.receivedData].push(hook) + : [hook]; + } + + + public getreceivedDataHook(): receivedDataHook[] { + return this.hooks[AvailableHooks.receivedData]; + } + + public getBeforeSendingDataHook(): BeforeSendingDataHook[] { + return this.hooks[AvailableHooks.BeforeSendingData]; + } +} \ No newline at end of file diff --git a/examples/publish subscribe/streetlight/src/index.ts b/examples/publish subscribe/streetlight/src/index.ts new file mode 100644 index 000000000..81d72ffbd --- /dev/null +++ b/examples/publish subscribe/streetlight/src/index.ts @@ -0,0 +1,260 @@ + + + + +import {fromSeed} from 'ts-nkeys'; +import {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} from './hooks'; +export {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} +import * as TestClient from './tests/testclient/'; +export { TestClient }; +import {ErrorCode, NatsTypescriptTemplateError} from './NatsTypescriptTemplateError'; +export {ErrorCode, NatsTypescriptTemplateError} +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; + +export {Client, ServerInfo, ServersChangedEvent, SubEvent} +import * as streetlightStreetlightIdCommandTurnonChannel from "./channels/StreetlightStreetlightIdCommandTurnon"; +export {streetlightStreetlightIdCommandTurnonChannel}; +import * as streetlightStreetlightIdEventTurnonChannel from "./channels/StreetlightStreetlightIdEventTurnon"; +export {streetlightStreetlightIdEventTurnonChannel}; +import * as TurnonCommandMessage from "./messages/TurnonCommand"; +export {TurnonCommandMessage}; +import * as AnonymousMessage2Message from "./messages/AnonymousMessage2"; +export {AnonymousMessage2Message}; + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiClient extends events.EventEmitter{ + + + private jsonClient?: Client; + private stringClient?: Client; + private binaryClient?: Client; + private options?: NatsConnectionOptions; + + /** + * + * @param options options to use, payload is omitted if sat in the AsyncAPI document. + */ + constructor() { + super(); + } + /** + * Try to connect to the NATS server with the different payloads. + */ + connect(options : NatsConnectionOptions): Promise{ + return new Promise(async (resolve: () => void, reject: (error: any) => void) => { + this.options = options; + try{ + if(!this.jsonClient || this.jsonClient!.isClosed()){ + this.options.payload = Payload.JSON; + this.jsonClient = await connect(this.options); + this.chainEvents(this.jsonClient); + } + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) + } + + /** + * Returns whether or not any of the clients are closed + */ + isClosed(){ + if (!this.jsonClient || this.jsonClient!.isClosed()){ + return true; + } + return false; + } + + /** + * Disconnect all clients from the server + */ + async disconnect(){ + if(this.jsonClient && !this.jsonClient!.isClosed()){ + this.jsonClient!.close(); + } + } + + private chainEvents(ns: Client){ + ns.on('permissionError', (e: NatsError) => { + this.emit(AvailableEvents.permissionError, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('close', (e: NatsError) => { + this.emit(AvailableEvents.close, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('connect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.connect, connection, serverURL, info) + }); + ns.on('connecting', (serverURL: string) => { + this.emit(AvailableEvents.connecting, serverURL) + }); + ns.on('disconnect', (serverURL: string) => { + this.emit(AvailableEvents.disconnect, serverURL) + }); + ns.on('error', (e: NatsError) => { + this.emit(AvailableEvents.error, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('pingcount', () => { + this.emit(AvailableEvents.pingcount) + }); + ns.on('pingtimer', () => { + this.emit(AvailableEvents.pingtimer) + }); + ns.on('reconnect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.reconnect, connection, serverURL, info) + }); + ns.on('reconnecting', (serverURL: string) => { + this.emit(AvailableEvents.reconnecting, serverURL) + }); + ns.on('serversChanged', (e: ServersChangedEvent) => { + this.emit(AvailableEvents.serversChanged, e) + }); + ns.on('subscribe', (e: SubEvent) => { + this.emit(AvailableEvents.subscribe, e) + }); + ns.on('unsubscribe', (e: SubEvent) => { + this.emit(AvailableEvents.unsubscribe, e) + }); + ns.on('yield', () => { + this.emit(AvailableEvents.yield) + }); + } + + /** + * Try to connect to the NATS server with user credentials + */ + async connectWithUserCreds(userCreds: string, options?: NatsConnectionOptions){ + await this.connect({ + userCreds: userCreds, + ... options + }); + } + /** + * Try to connect to the NATS server with user and password + */ + async connectWithUserPass(user: string, pass: string, options?: NatsConnectionOptions){ + await this.connect({ + user: user, + pass: pass, + ... options + }); + } + + /** + * Try to connect to the NATS server which has no authentication + */ + async connectToHost(host: string, options?: NatsConnectionOptions){ + await this.connect({ + servers: [host], + ... options + }); + } + + /** + * Try to connect to the NATS server with nkey authentication + */ + async connectWithNkey(publicNkey: string, seed: string, options?: NatsConnectionOptions){ + await this.connect({ + nkey: publicNkey, + nonceSigner: (nonce: string): Buffer => { + const sk = fromSeed(Buffer.from(seed)); + return sk.sign(Buffer.from(nonce)); + }, + ... options + }); + } + + + + /** + * Channel for the turn on command which should turn on the streetlight + * @param onDataCallback Called when message received. + */ + public subscribeToStreetlightStreetlightIdCommandTurnon( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: TurnonCommandMessage.TurnonCommand, streetlight_id?: string) => void + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdCommandTurnonChannel.subscribe( + onDataCallback, nc + + ,streetlight_id + , + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + + /** + * Channel for when the streetlight is turned on + * @param requestMessage The message to publish. + */ + public publishToStreetlightStreetlightIdEventTurnon( + requestMessage: AnonymousMessage2Message.AnonymousMessage2 + + ,streetlight_id: string + + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdEventTurnonChannel.publish(requestMessage, nc + + ,streetlight_id + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + +} diff --git a/examples/publish subscribe/streetlight/src/messages/AnonymousMessage1.ts b/examples/publish subscribe/streetlight/src/messages/AnonymousMessage1.ts new file mode 100644 index 000000000..bc9ef82eb --- /dev/null +++ b/examples/publish subscribe/streetlight/src/messages/AnonymousMessage1.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, AnonymousMessage1 } from "./file"; +// +// const anonymousMessage1 = Convert.toAnonymousMessage1(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface AnonymousMessage1 { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toAnonymousMessage1(json: string): AnonymousMessage1 { + return cast(JSON.parse(json), r("AnonymousMessage1")); + } + + public static anonymousMessage1ToJson(value: AnonymousMessage1): string { + return JSON.stringify(uncast(value, r("AnonymousMessage1")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "AnonymousMessage1": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/publish subscribe/streetlight/src/messages/AnonymousMessage2.ts b/examples/publish subscribe/streetlight/src/messages/AnonymousMessage2.ts new file mode 100644 index 000000000..5d9e8b6a4 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/messages/AnonymousMessage2.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, AnonymousMessage2 } from "./file"; +// +// const anonymousMessage2 = Convert.toAnonymousMessage2(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface AnonymousMessage2 { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toAnonymousMessage2(json: string): AnonymousMessage2 { + return cast(JSON.parse(json), r("AnonymousMessage2")); + } + + public static anonymousMessage2ToJson(value: AnonymousMessage2): string { + return JSON.stringify(uncast(value, r("AnonymousMessage2")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "AnonymousMessage2": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/publish subscribe/streetlight/src/messages/SubscribeToTurnonCommand.ts b/examples/publish subscribe/streetlight/src/messages/SubscribeToTurnonCommand.ts new file mode 100644 index 000000000..1cafd79de --- /dev/null +++ b/examples/publish subscribe/streetlight/src/messages/SubscribeToTurnonCommand.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, SubscribeToTurnonCommand } from "./file"; +// +// const subscribeToTurnonCommand = Convert.toSubscribeToTurnonCommand(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface SubscribeToTurnonCommand { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toSubscribeToTurnonCommand(json: string): SubscribeToTurnonCommand { + return cast(JSON.parse(json), r("SubscribeToTurnonCommand")); + } + + public static subscribeToTurnonCommandToJson(value: SubscribeToTurnonCommand): string { + return JSON.stringify(uncast(value, r("SubscribeToTurnonCommand")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "SubscribeToTurnonCommand": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/publish subscribe/streetlight/src/messages/TurnonCommand.ts b/examples/publish subscribe/streetlight/src/messages/TurnonCommand.ts new file mode 100644 index 000000000..27c30978c --- /dev/null +++ b/examples/publish subscribe/streetlight/src/messages/TurnonCommand.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, TurnonCommand } from "./file"; +// +// const turnonCommand = Convert.toTurnonCommand(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface TurnonCommand { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toTurnonCommand(json: string): TurnonCommand { + return cast(JSON.parse(json), r("TurnonCommand")); + } + + public static turnonCommandToJson(value: TurnonCommand): string { + return JSON.stringify(uncast(value, r("TurnonCommand")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "TurnonCommand": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts b/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts new file mode 100644 index 000000000..56ca949de --- /dev/null +++ b/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts @@ -0,0 +1,75 @@ + + +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import * as Client from '../index' +import * as TestClient from './testclient/index' +import { NatsTypescriptTemplateError } from '../NatsTypescriptTemplateError'; + +describe('streetlight/{streetlight_id}/command/turnon can talk to it self', () => { + var client: Client.NatsAsyncApiClient; + var testClient: TestClient.NatsAsyncApiTestClient; + before(async () => { + client = new Client.NatsAsyncApiClient(); + testClient = new TestClient.NatsAsyncApiTestClient(); + const natsHost = process.env.NATS_HOST || "0.0.0.0" + const natsPort = process.env.NATS_PORT || "4222" + const natsUrl = `${natsHost}:${natsPort}` + await client.connectToHost(natsUrl); + await testClient.connectToHost(natsUrl); + }); + + it('Clients can connect', () => { + expect(client.isClosed()).to.be.false; + expect(testClient.isClosed()).to.be.false; + }); + + it('can send message', async () => { + + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: Client.TurnonCommandMessage.TurnonCommand | undefined = undefined; +var recievedStreetlightId : string | undefined = undefined + + +var publishMessage: Client.TurnonCommandMessage.TurnonCommand = { + "lumen": 0 +}; +var StreetlightIdToSend: string = "string" + + +const tryAndWaitForResponse = new Promise(resolve => { + setTimeout(resolve, 100); +}); + +const replySubscription = await client.subscribeToStreetlightStreetlightIdCommandTurnon((err, msg + + ,streetlight_id + ) => { + receivedError = err; + receivedMsg = msg; + recievedStreetlightId = streetlight_id + + } + , StreetlightIdToSend + +); +await testClient.publishToStreetlightStreetlightIdCommandTurnon(publishMessage + , StreetlightIdToSend + ); +await tryAndWaitForResponse; +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(publishMessage); +expect(recievedStreetlightId).to.be.equal(StreetlightIdToSend); + + + }); + + it('Can shutdown', async () => { + await client.disconnect() + await testClient.disconnect() + expect(client.isClosed()).to.be.true; + expect(testClient.isClosed()).to.be.true; + }); + +}); \ No newline at end of file diff --git a/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts b/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts new file mode 100644 index 000000000..2b21deb4b --- /dev/null +++ b/examples/publish subscribe/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts @@ -0,0 +1,76 @@ + + +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import * as Client from '../index' +import * as TestClient from './testclient/index' +import { NatsTypescriptTemplateError } from '../NatsTypescriptTemplateError'; + +describe('streetlight/{streetlight_id}/event/turnon can talk to it self', () => { + var client: Client.NatsAsyncApiClient; + var testClient: TestClient.NatsAsyncApiTestClient; + before(async () => { + client = new Client.NatsAsyncApiClient(); + testClient = new TestClient.NatsAsyncApiTestClient(); + const natsHost = process.env.NATS_HOST || "0.0.0.0" + const natsPort = process.env.NATS_PORT || "4222" + const natsUrl = `${natsHost}:${natsPort}` + await client.connectToHost(natsUrl); + await testClient.connectToHost(natsUrl); + }); + + it('Clients can connect', () => { + expect(client.isClosed()).to.be.false; + expect(testClient.isClosed()).to.be.false; + }); + + it('can send message', async () => { + + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: TestClient.AnonymousMessage2Message.AnonymousMessage2 | undefined = undefined; +var recievedStreetlightId : string | undefined = undefined + + +var publishMessage: TestClient.AnonymousMessage2Message.AnonymousMessage2 = { + "lumen": 0 +}; +var StreetlightIdToSend: string = "string" + + +const tryAndWaitForResponse = new Promise(resolve => { + setTimeout(resolve, 100); +}); + + +const replySubscription = await testClient.subscribeToStreetlightStreetlightIdEventTurnon((err, msg + + ,streetlight_id + ) => { + receivedError = err; + receivedMsg = msg; + recievedStreetlightId = streetlight_id + + } + , StreetlightIdToSend + +); +await client.publishToStreetlightStreetlightIdEventTurnon(publishMessage + , StreetlightIdToSend + ); +await tryAndWaitForResponse; +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(publishMessage); +expect(recievedStreetlightId).to.be.equal(StreetlightIdToSend); + + + }); + + it('Can shutdown', async () => { + await client.disconnect() + await testClient.disconnect() + expect(client.isClosed()).to.be.true; + expect(testClient.isClosed()).to.be.true; + }); + +}); \ No newline at end of file diff --git a/examples/publish subscribe/streetlight/src/tests/testclient/index.ts b/examples/publish subscribe/streetlight/src/tests/testclient/index.ts new file mode 100644 index 000000000..127735208 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/tests/testclient/index.ts @@ -0,0 +1,253 @@ + + +import {fromSeed} from 'ts-nkeys'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../NatsTypescriptTemplateError'; +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; +import * as streetlightStreetlightIdCommandTurnonChannel from "./testchannels/StreetlightStreetlightIdCommandTurnon"; +export {streetlightStreetlightIdCommandTurnonChannel}; +import * as streetlightStreetlightIdEventTurnonChannel from "./testchannels/StreetlightStreetlightIdEventTurnon"; +export {streetlightStreetlightIdEventTurnonChannel}; +import * as TurnonCommandMessage from "../../messages/TurnonCommand"; +export {TurnonCommandMessage}; +import * as AnonymousMessage2Message from "../../messages/AnonymousMessage2"; +export {AnonymousMessage2Message}; + + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiTestClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiTestClient extends events.EventEmitter{ + + + private jsonClient?: Client; + private stringClient?: Client; + private binaryClient?: Client; + private options?: NatsConnectionOptions; + + /** + * + * @param options options to use, payload is omitted if sat in the AsyncAPI document. + */ + constructor() { + super(); + } + /** + * Try to connect to the NATS server with the different payloads. + */ + connect(options : NatsConnectionOptions): Promise{ + return new Promise(async (resolve: () => void, reject: (error: any) => void) => { + this.options = options; + try{ + if(!this.jsonClient || this.jsonClient!.isClosed()){ + this.options.payload = Payload.JSON; + this.jsonClient = await connect(this.options); + this.chainEvents(this.jsonClient); + } + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) + } + + /** + * Returns whether or not any of the clients are closed + */ + isClosed(){ + if (!this.jsonClient || this.jsonClient!.isClosed()){ + return true; + } + return false; + } + + /** + * Disconnect all clients from the server + */ + async disconnect(){ + if(this.jsonClient && !this.jsonClient!.isClosed()){ + this.jsonClient!.close(); + } + } + + private chainEvents(ns: Client){ + ns.on('permissionError', (e: NatsError) => { + this.emit(AvailableEvents.permissionError, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('close', (e: NatsError) => { + this.emit(AvailableEvents.close, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('connect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.connect, connection, serverURL, info) + }); + ns.on('connecting', (serverURL: string) => { + this.emit(AvailableEvents.connecting, serverURL) + }); + ns.on('disconnect', (serverURL: string) => { + this.emit(AvailableEvents.disconnect, serverURL) + }); + ns.on('error', (e: NatsError) => { + this.emit(AvailableEvents.error, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('pingcount', () => { + this.emit(AvailableEvents.pingcount) + }); + ns.on('pingtimer', () => { + this.emit(AvailableEvents.pingtimer) + }); + ns.on('reconnect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.reconnect, connection, serverURL, info) + }); + ns.on('reconnecting', (serverURL: string) => { + this.emit(AvailableEvents.reconnecting, serverURL) + }); + ns.on('serversChanged', (e: ServersChangedEvent) => { + this.emit(AvailableEvents.serversChanged, e) + }); + ns.on('subscribe', (e: SubEvent) => { + this.emit(AvailableEvents.subscribe, e) + }); + ns.on('unsubscribe', (e: SubEvent) => { + this.emit(AvailableEvents.unsubscribe, e) + }); + ns.on('yield', () => { + this.emit(AvailableEvents.yield) + }); + } + + /** + * Try to connect to the NATS server with user credentials + */ + async connectWithUserCreds(userCreds: string, options?: NatsConnectionOptions){ + await this.connect({ + userCreds: userCreds, + ... options + }); + } + /** + * Try to connect to the NATS server with user and password + */ + async connectWithUserPass(user: string, pass: string, options?: NatsConnectionOptions){ + await this.connect({ + user: user, + pass: pass, + ... options + }); + } + + /** + * Try to connect to the NATS server which has no authentication + */ + async connectToHost(host: string, options?: NatsConnectionOptions){ + await this.connect({ + servers: [host], + ... options + }); + } + + /** + * Try to connect to the NATS server with nkey authentication + */ + async connectWithNkey(publicNkey: string, seed: string, options?: NatsConnectionOptions){ + await this.connect({ + nkey: publicNkey, + nonceSigner: (nonce: string): Buffer => { + const sk = fromSeed(Buffer.from(seed)); + return sk.sign(Buffer.from(nonce)); + }, + ... options + }); + } + + + + /** + * Channel for the turn on command which should turn on the streetlight + * @param requestMessage The message to publish. + */ + public publishToStreetlightStreetlightIdCommandTurnon( + requestMessage: TurnonCommandMessage.TurnonCommand + + ,streetlight_id: string + + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdCommandTurnonChannel.publish(requestMessage, nc + + ,streetlight_id + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + + /** + * Channel for when the streetlight is turned on + * @param onDataCallback Called when message received. + */ + public subscribeToStreetlightStreetlightIdEventTurnon( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: AnonymousMessage2Message.AnonymousMessage2, streetlight_id?: string) => void + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdEventTurnonChannel.subscribe( + onDataCallback, nc + + ,streetlight_id + , + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + +} \ No newline at end of file diff --git a/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts b/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts new file mode 100644 index 000000000..646636ffe --- /dev/null +++ b/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts @@ -0,0 +1,36 @@ + +import * as TurnonCommandMessage from '../../../messages/TurnonCommand'; +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../../NatsTypescriptTemplateError'; +import { Hooks } from '../../../hooks'; + +export function publish( + message: TurnonCommandMessage.TurnonCommand, + nc: Client + + ,streetlight_id: string + + ): Promise { + return new Promise(async (resolve, reject) => { + try{ + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + await nc.publish(`streetlight.${streetlight_id}.command.turnon`, dataToSend); + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }); +}; + diff --git a/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts b/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts new file mode 100644 index 000000000..b20360301 --- /dev/null +++ b/examples/publish subscribe/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts @@ -0,0 +1,60 @@ + +import * as AnonymousMessage2Message from '../../../messages/AnonymousMessage2'; +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../../NatsTypescriptTemplateError'; +import { Hooks } from '../../../hooks'; + +export function subscribe( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: AnonymousMessage2Message.AnonymousMessage2, streetlight_id?: string) => void, + nc: Client + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + let subscribeOptions: SubscriptionOptions = {... options}; + + try{ + let subscription = nc.subscribe(`streetlight.${streetlight_id}.event.turnon`, (err, msg) => { + if(err){ + onDataCallback(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, err)); + }else{ + +var unmodifiedChannel = `streetlight.{streetlight_id}.event.turnon`; +var channel = msg.subject; + var streetlightIdSplit = unmodifiedChannel.split("{streetlight_id}"); + +const splits = [ + streetlightIdSplit[0], + streetlightIdSplit[1] +]; +channel = channel.substring(splits[0].length); +var streetlightIdEnd = channel.indexOf(splits[1]); +var streetlightIdParam = "" + channel.substring(0, streetlightIdEnd); + + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + onDataCallback(undefined, receivedData, + streetlightIdParam); + } + }, subscribeOptions); + resolve(subscription); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + + diff --git a/examples/publish subscribe/streetlight/tsconfig.json b/examples/publish subscribe/streetlight/tsconfig.json new file mode 100644 index 000000000..75097457a --- /dev/null +++ b/examples/publish subscribe/streetlight/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "declaration": true, + "strict": true, + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "outDir": "dist/", + "baseUrl": "./src" + }, + "include": ["src"], + "exclude": ["node_modules", "**/*.spec.ts"] +} diff --git a/examples/request reply/GenerateAndBuild.sh b/examples/request reply/GenerateAndBuild.sh new file mode 100755 index 000000000..26222ece6 --- /dev/null +++ b/examples/request reply/GenerateAndBuild.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ag --install --output "./streetlight" "./streetlight.json" "../../" --force-write --param "generateTestClient=true" --param "promisifyReplyCallback=true" && cd ./streetlight && npm i && npm run build && cd .. \ No newline at end of file diff --git a/examples/request reply/Test.sh b/examples/request reply/Test.sh new file mode 100755 index 000000000..3bcad8e5f --- /dev/null +++ b/examples/request reply/Test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cd ./streetlight && npm run test:integration \ No newline at end of file diff --git a/examples/request reply/streetlight.json b/examples/request reply/streetlight.json new file mode 100644 index 000000000..101711a36 --- /dev/null +++ b/examples/request reply/streetlight.json @@ -0,0 +1,109 @@ +{ + "asyncapi": "2.0.0", + "info": { + "title": "Streetlight", + "version": "1.0.0" + }, + "defaultContentType": "json", + "channels": { + "streetlight/{streetlight_id}/command/turnon": { + "description": "Channel for the turn on command which should turn on the streetlight", + "parameters": { + "streetlight_id": { + "description": "The ID of the streetlight", + "schema": { + "type": "string" + } + } + }, + "subscribe": { + "message": { + "$ref": "#/components/messages/generalReply" + } + }, + "publish": { + "operationId": "Listen when to turn on the streetlight", + "message": { + "name": "turnonCommand", + "payload": { + "type": "object", + "required": ["lumen"], + "properties": { + "lumen": { + "type": "integer", + "description": "How bright should the light be." + } + } + } + } + }, + "bindings": { + "nats": { + "is": "requestReply", + "requestReply": { + "is": "replier" + }, + "bindingVersion": "0.1.0" + } + } + }, + "streetlight/{streetlight_id}/event/turnon": { + "description": "Channel for when the streetlight is turned on", + "parameters": { + "streetlight_id": { + "description": "The ID of the streetlight", + "schema": { + "type": "string" + } + } + }, + "subscribe": { + "operationId": "Publish when the streetlight gets turned on", + "message": { + "payload": { + "type": "object", + "required": ["lumen"], + "properties": { + "lumen": { + "type": "integer", + "description": "How bright should the light be." + } + } + } + } + }, + "publish": { + "message": { + "$ref": "#/components/messages/generalReply" + } + }, + "bindings": { + "nats": { + "is": "requestReply", + "requestReply": { + "is": "requester" + }, + "bindingVersion": "0.1.0" + } + } + } + }, + "components": { + "messages": { + "generalReply": { + "payload": { + "type": "object", + "$id": "GeneralReply", + "properties": { + "status_code": { + "type": "integer" + }, + "status_message": { + "type": "string" + } + } + } + } + } + } +} diff --git a/examples/request reply/streetlight/README.md b/examples/request reply/streetlight/README.md new file mode 100644 index 000000000..8efb38d46 --- /dev/null +++ b/examples/request reply/streetlight/README.md @@ -0,0 +1,7 @@ +# Streetlight + + + + +Available nats encodings: +https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings diff --git a/examples/request reply/streetlight/package-lock.json b/examples/request reply/streetlight/package-lock.json new file mode 100644 index 000000000..612ff2124 --- /dev/null +++ b/examples/request reply/streetlight/package-lock.json @@ -0,0 +1,1011 @@ +{ + "name": "streetlight", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chai": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz", + "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==", + "dev": true + }, + "@types/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-Ibfb2jgpjYUxnl7RSVvUzOrv/vhkTVKEfPwQf9ZlDDsSyWVDp/2JtTBxO4eRrKBYtxc3cZQabdR38i8R0o1uww==", + "requires": { + "@types/node": "*" + } + }, + "@types/mocha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.4.tgz", + "integrity": "sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ==", + "dev": true + }, + "@types/node": { + "version": "13.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.5.tgz", + "integrity": "sha512-hkzMMD3xu6BrJpGVLeQ3htQQNAcOrJjX7WFmtK8zWQpz2UJf13LCFF2ALA7c9OVdvc2vQJeDdjfR35M0sBCxvw==" + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "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", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "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 + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "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 + }, + "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 + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "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" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "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 + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "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 + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "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 + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mocha": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", + "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + } + }, + "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 + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nuid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/nuid/-/nuid-1.1.4.tgz", + "integrity": "sha512-PXiYyHhGfrq8H4g5HyC8enO1lz6SBe5z6x1yx/JG4tmADzDGJVQy3l1sRf3VtEvPsN8dGn9hRFRwDKWL62x0BA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-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 + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "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" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "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 + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "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 + }, + "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-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" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "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" + } + }, + "ts-nats": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/ts-nats/-/ts-nats-1.2.4.tgz", + "integrity": "sha512-bIC+PlwHplRqhooa9kE+QPcQ9RPGUXD2ruvdf6LoFpP6MjE6exVoRhYSydm0e5wk7VfuXpTbH1NoopTKHwlOKA==", + "requires": { + "nuid": "^1.1.0", + "ts-nkeys": "^1.0.12" + } + }, + "ts-nkeys": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/ts-nkeys/-/ts-nkeys-1.0.16.tgz", + "integrity": "sha512-1qrhAlavbm36wtW+7NtKOgxpzl+70NTF8xlz9mEhiA5zHMlMxjj3sEVKWm3pGZhHXE0Q3ykjrj+OSRVaYw+Dqg==", + "requires": { + "tweetnacl": "^1.0.3" + } + }, + "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 + } + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "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 + }, + "typescript": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz", + "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "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" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "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 + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "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/examples/request reply/streetlight/package.json b/examples/request reply/streetlight/package.json new file mode 100644 index 000000000..776edc8e7 --- /dev/null +++ b/examples/request reply/streetlight/package.json @@ -0,0 +1,26 @@ +{ + "name": "streetlight", + "description": "", + "version": "1.0.0", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "watch": "tsc --watch", + "build": "tsc", + "test:integration": "./node_modules/.bin/mocha -r ts-node/register src/tests/**/*.spec.ts" + }, + "dependencies": { + "@types/klaw-sync": "^6.0.0", + "@types/node": "13.9.5", + "ts-nats": "1.2.4", + "typescript": "3.4.3", + "ts-nkeys": "1.0.16" + }, + "devDependencies": { + "ts-node": "^8.10.2", + "@types/mocha": "^8.0.4", + "@types/chai": "^4.2.14", + "chai": "^4.2.0", + "mocha": "^8.2.1" + } +} diff --git a/examples/request reply/streetlight/src/NatsTypescriptTemplateError.ts b/examples/request reply/streetlight/src/NatsTypescriptTemplateError.ts new file mode 100644 index 000000000..07ad37c3e --- /dev/null +++ b/examples/request reply/streetlight/src/NatsTypescriptTemplateError.ts @@ -0,0 +1,70 @@ + +import * as util from 'util'; + +export enum ErrorCode { + NOT_CONNECTED = 'NOT_CONNECTED', + INTERNAL_NATS_TS_ERROR = 'INTERNAL_NATS_TS_ERROR', + HOOK_ERROR = 'HOOK_ERROR' +} + +/** @internal **/ +export class Messages { + static messages = new Messages(); + messages: { [key: string]: string } = {}; + + private constructor() { + this.messages[ErrorCode.NOT_CONNECTED] = 'The client is not connected'; + this.messages[ErrorCode.INTERNAL_NATS_TS_ERROR] = 'An error occured while trying to use the Nats Typescript library'; + this.messages[ErrorCode.HOOK_ERROR] = 'An error occured while trying to call one of the hooks.'; + } + + static getMessage(s: string): string { + return Messages.messages.getMessage(s); + } + + getMessage(s: string): string { + let v = this.messages[s]; + if (!v) { + v = s; + } + return v; + } +} +export class NatsTypescriptTemplateError implements Error { + + name: string; + message: string; + code: string; + chainedError?: Error; + + /** + * @param {String} message + * @param {String} code + * @param {Error} [chainedError] + * @constructor + * + * @api private + * @internal + */ + constructor(message: string, code: string, chainedError?: Error) { + Error.captureStackTrace(this, this.constructor); + this.name = 'NatsTypescriptTemplateError'; + this.message = message; + this.code = code; + this.chainedError = chainedError; + + util.inherits(NatsTypescriptTemplateError, Error); + } + + /** + * @param code + * @param chainedError + * @api private + * @internal + */ + static errorForCode(code: string, chainedError?: Error): NatsTypescriptTemplateError { + let m = Messages.getMessage(code); + return new NatsTypescriptTemplateError(m, code, chainedError); + } +} + diff --git a/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts b/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts new file mode 100644 index 000000000..3e75fdd9a --- /dev/null +++ b/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdCommandTurnon.ts @@ -0,0 +1,85 @@ + +import * as TurnonCommandMessage from '../messages/TurnonCommand' +import * as GeneralReplyMessage from '../messages/GeneralReply' +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../NatsTypescriptTemplateError'; +import { Hooks } from '../hooks'; + +export function reply( + onRequest: (err?: NatsTypescriptTemplateError, msg?: TurnonCommandMessage.TurnonCommand, streetlight_id?: string) =>Promise, + onReplyError: (err: NatsTypescriptTemplateError) => void, + nc: Client + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + try { + let subscribeOptions: SubscriptionOptions = {... options}; + + let subscription = nc.subscribe(`streetlight.${streetlight_id}.command.turnon`,async (err, msg) => { + if (err) { + onRequest(err); + } else { + +var unmodifiedChannel = `streetlight.{streetlight_id}.command.turnon`; +var channel = msg.subject; + var streetlightIdSplit = unmodifiedChannel.split("{streetlight_id}"); + +const splits = [ + streetlightIdSplit[0], + streetlightIdSplit[1] +]; +channel = channel.substring(splits[0].length); +var streetlightIdEnd = channel.indexOf(splits[1]); +var streetlightIdParam = "" + channel.substring(0, streetlightIdEnd); + + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + onReplyError(error); + return; +} + + + let message =await onRequest(undefined, receivedData, + streetlightIdParam); + + if (msg.reply) { + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + onReplyError(error) + return; +} + + + await nc.publish(msg.reply, dataToSend); + } else { + let error = new NatsTypescriptTemplateError('Expected request to need a reply, did not..', '000'); + onReplyError(error) + return; + } + } + }, subscribeOptions); + resolve(subscription); + } catch (e) { + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + + diff --git a/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts b/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts new file mode 100644 index 000000000..a89f8bba8 --- /dev/null +++ b/examples/request reply/streetlight/src/channels/StreetlightStreetlightIdEventTurnon.ts @@ -0,0 +1,54 @@ + +import * as GeneralReplyMessage from '../messages/GeneralReply' +import * as AnonymousMessage4Message from '../messages/AnonymousMessage4' +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../NatsTypescriptTemplateError'; +import { Hooks } from '../hooks'; + +export function request( + message: AnonymousMessage4Message.AnonymousMessage4, + nc: Client + + ,streetlight_id: string + + ): Promise { + return new Promise(async (resolve, reject) => { + var timeout = undefined; + let msg; + try { + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + msg = await nc.request(`streetlight.${streetlight_id}.event.turnon`, timeout, dataToSend) + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + return; + } + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + resolve(receivedData); + }) +} + + diff --git a/examples/request reply/streetlight/src/hooks.ts b/examples/request reply/streetlight/src/hooks.ts new file mode 100644 index 000000000..d4528c513 --- /dev/null +++ b/examples/request reply/streetlight/src/hooks.ts @@ -0,0 +1,57 @@ +export enum AvailableHooks { + receivedData = 'receivedData', + BeforeSendingData = 'BeforeSendingData' +} +export type receivedDataHook = (receivedData: any) => string; +export type BeforeSendingDataHook = (messageToSend: any) => string; +export class Hooks { + private static instance: Hooks; + + private hooks: { + BeforeSendingData: BeforeSendingDataHook[]; + receivedData: receivedDataHook[]; + }; + private constructor() { + this.hooks = { + BeforeSendingData: [], + receivedData: [] + } + } + public static getInstance(): Hooks { + if (!Hooks.instance) { + Hooks.instance = new Hooks(); + } + return Hooks.instance; + } + + + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerBeforeSendingData(hook: BeforeSendingDataHook) { + this.hooks[AvailableHooks.BeforeSendingData] + ? this.hooks[AvailableHooks.BeforeSendingData].push(hook) + : [hook]; + } + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerreceivedData(hook: receivedDataHook) { + this.hooks[AvailableHooks.receivedData] + ? this.hooks[AvailableHooks.receivedData].push(hook) + : [hook]; + } + + + public getreceivedDataHook(): receivedDataHook[] { + return this.hooks[AvailableHooks.receivedData]; + } + + public getBeforeSendingDataHook(): BeforeSendingDataHook[] { + return this.hooks[AvailableHooks.BeforeSendingData]; + } +} \ No newline at end of file diff --git a/examples/request reply/streetlight/src/index.ts b/examples/request reply/streetlight/src/index.ts new file mode 100644 index 000000000..709f082e1 --- /dev/null +++ b/examples/request reply/streetlight/src/index.ts @@ -0,0 +1,273 @@ + + + + +import {fromSeed} from 'ts-nkeys'; +import {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} from './hooks'; +export {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} +import * as TestClient from './tests/testclient/'; +export { TestClient }; +import {ErrorCode, NatsTypescriptTemplateError} from './NatsTypescriptTemplateError'; +export {ErrorCode, NatsTypescriptTemplateError} +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; + +export {Client, ServerInfo, ServersChangedEvent, SubEvent} +import * as streetlightStreetlightIdCommandTurnonChannel from "./channels/StreetlightStreetlightIdCommandTurnon"; +export {streetlightStreetlightIdCommandTurnonChannel}; +import * as streetlightStreetlightIdEventTurnonChannel from "./channels/StreetlightStreetlightIdEventTurnon"; +export {streetlightStreetlightIdEventTurnonChannel}; +import * as TurnonCommandMessage from "./messages/TurnonCommand"; +export {TurnonCommandMessage}; +import * as GeneralReplyMessage from "./messages/GeneralReply"; +export {GeneralReplyMessage}; +import * as AnonymousMessage4Message from "./messages/AnonymousMessage4"; +export {AnonymousMessage4Message}; + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiClient extends events.EventEmitter{ + + + private jsonClient?: Client; + private stringClient?: Client; + private binaryClient?: Client; + private options?: NatsConnectionOptions; + + /** + * + * @param options options to use, payload is omitted if sat in the AsyncAPI document. + */ + constructor() { + super(); + } + /** + * Try to connect to the NATS server with the different payloads. + */ + connect(options : NatsConnectionOptions): Promise{ + return new Promise(async (resolve: () => void, reject: (error: any) => void) => { + this.options = options; + try{ + if(!this.jsonClient || this.jsonClient!.isClosed()){ + this.options.payload = Payload.JSON; + this.jsonClient = await connect(this.options); + this.chainEvents(this.jsonClient); + } + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) + } + + /** + * Returns whether or not any of the clients are closed + */ + isClosed(){ + if (!this.jsonClient || this.jsonClient!.isClosed()){ + return true; + } + return false; + } + + /** + * Disconnect all clients from the server + */ + async disconnect(){ + if(this.jsonClient && !this.jsonClient!.isClosed()){ + this.jsonClient!.close(); + } + } + + private chainEvents(ns: Client){ + ns.on('permissionError', (e: NatsError) => { + this.emit(AvailableEvents.permissionError, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('close', (e: NatsError) => { + this.emit(AvailableEvents.close, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('connect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.connect, connection, serverURL, info) + }); + ns.on('connecting', (serverURL: string) => { + this.emit(AvailableEvents.connecting, serverURL) + }); + ns.on('disconnect', (serverURL: string) => { + this.emit(AvailableEvents.disconnect, serverURL) + }); + ns.on('error', (e: NatsError) => { + this.emit(AvailableEvents.error, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('pingcount', () => { + this.emit(AvailableEvents.pingcount) + }); + ns.on('pingtimer', () => { + this.emit(AvailableEvents.pingtimer) + }); + ns.on('reconnect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.reconnect, connection, serverURL, info) + }); + ns.on('reconnecting', (serverURL: string) => { + this.emit(AvailableEvents.reconnecting, serverURL) + }); + ns.on('serversChanged', (e: ServersChangedEvent) => { + this.emit(AvailableEvents.serversChanged, e) + }); + ns.on('subscribe', (e: SubEvent) => { + this.emit(AvailableEvents.subscribe, e) + }); + ns.on('unsubscribe', (e: SubEvent) => { + this.emit(AvailableEvents.unsubscribe, e) + }); + ns.on('yield', () => { + this.emit(AvailableEvents.yield) + }); + } + + /** + * Try to connect to the NATS server with user credentials + */ + async connectWithUserCreds(userCreds: string, options?: NatsConnectionOptions){ + await this.connect({ + userCreds: userCreds, + ... options + }); + } + /** + * Try to connect to the NATS server with user and password + */ + async connectWithUserPass(user: string, pass: string, options?: NatsConnectionOptions){ + await this.connect({ + user: user, + pass: pass, + ... options + }); + } + + /** + * Try to connect to the NATS server which has no authentication + */ + async connectToHost(host: string, options?: NatsConnectionOptions){ + await this.connect({ + servers: [host], + ... options + }); + } + + /** + * Try to connect to the NATS server with nkey authentication + */ + async connectWithNkey(publicNkey: string, seed: string, options?: NatsConnectionOptions){ + await this.connect({ + nkey: publicNkey, + nonceSigner: (nonce: string): Buffer => { + const sk = fromSeed(Buffer.from(seed)); + return sk.sign(Buffer.from(nonce)); + }, + ... options + }); + } + + + + /** + * Channel for the turn on command which should turn on the streetlight + * @param onRequest Called when request received. + * @param onReplyError Called when it was not possible to send the reply. + */ + public replyToStreetlightStreetlightIdCommandTurnon( + onRequest : ( + err?: NatsTypescriptTemplateError, + msg?: TurnonCommandMessage.TurnonCommand,streetlight_id?: string + ) =>Promise, + onReplyError : (err: NatsTypescriptTemplateError) => void + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + const nc: Client = this.jsonClient!; + + if(nc){ + return streetlightStreetlightIdCommandTurnonChannel.reply( + onRequest, + onReplyError, + nc + + ,streetlight_id + , + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + + /** + * Channel for when the streetlight is turned on + * @param requestMessage The request message to send. + */ + public requestStreetlightStreetlightIdEventTurnon( + requestMessage:AnonymousMessage4Message.AnonymousMessage4 + + ,streetlight_id: string + + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdEventTurnonChannel.request( + requestMessage, + nc + + ,streetlight_id + + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + +} diff --git a/examples/request reply/streetlight/src/messages/AnonymousMessage3.ts b/examples/request reply/streetlight/src/messages/AnonymousMessage3.ts new file mode 100644 index 000000000..d28aa3985 --- /dev/null +++ b/examples/request reply/streetlight/src/messages/AnonymousMessage3.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, AnonymousMessage3 } from "./file"; +// +// const anonymousMessage3 = Convert.toAnonymousMessage3(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface AnonymousMessage3 { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toAnonymousMessage3(json: string): AnonymousMessage3 { + return cast(JSON.parse(json), r("AnonymousMessage3")); + } + + public static anonymousMessage3ToJson(value: AnonymousMessage3): string { + return JSON.stringify(uncast(value, r("AnonymousMessage3")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "AnonymousMessage3": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/request reply/streetlight/src/messages/AnonymousMessage4.ts b/examples/request reply/streetlight/src/messages/AnonymousMessage4.ts new file mode 100644 index 000000000..286b473a7 --- /dev/null +++ b/examples/request reply/streetlight/src/messages/AnonymousMessage4.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, AnonymousMessage4 } from "./file"; +// +// const anonymousMessage4 = Convert.toAnonymousMessage4(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface AnonymousMessage4 { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toAnonymousMessage4(json: string): AnonymousMessage4 { + return cast(JSON.parse(json), r("AnonymousMessage4")); + } + + public static anonymousMessage4ToJson(value: AnonymousMessage4): string { + return JSON.stringify(uncast(value, r("AnonymousMessage4")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "AnonymousMessage4": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/request reply/streetlight/src/messages/GeneralReply.ts b/examples/request reply/streetlight/src/messages/GeneralReply.ts new file mode 100644 index 000000000..a705e3755 --- /dev/null +++ b/examples/request reply/streetlight/src/messages/GeneralReply.ts @@ -0,0 +1,161 @@ +// To parse this data: +// +// import { Convert, GeneralReply } from "./file"; +// +// const generalReply = Convert.toGeneralReply(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface GeneralReply { + status_code?: number; + status_message?: string; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toGeneralReply(json: string): GeneralReply { + return cast(JSON.parse(json), r("GeneralReply")); + } + + public static generalReplyToJson(value: GeneralReply): string { + return JSON.stringify(uncast(value, r("GeneralReply")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "GeneralReply": o([ + { json: "status_code", js: "status_code", typ: u(undefined, 0) }, + { json: "status_message", js: "status_message", typ: u(undefined, "") }, + ], "any"), +}; diff --git a/examples/request reply/streetlight/src/messages/SubscribeToTurnonCommand.ts b/examples/request reply/streetlight/src/messages/SubscribeToTurnonCommand.ts new file mode 100644 index 000000000..1cafd79de --- /dev/null +++ b/examples/request reply/streetlight/src/messages/SubscribeToTurnonCommand.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, SubscribeToTurnonCommand } from "./file"; +// +// const subscribeToTurnonCommand = Convert.toSubscribeToTurnonCommand(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface SubscribeToTurnonCommand { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toSubscribeToTurnonCommand(json: string): SubscribeToTurnonCommand { + return cast(JSON.parse(json), r("SubscribeToTurnonCommand")); + } + + public static subscribeToTurnonCommandToJson(value: SubscribeToTurnonCommand): string { + return JSON.stringify(uncast(value, r("SubscribeToTurnonCommand")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "SubscribeToTurnonCommand": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/request reply/streetlight/src/messages/TurnonCommand.ts b/examples/request reply/streetlight/src/messages/TurnonCommand.ts new file mode 100644 index 000000000..27c30978c --- /dev/null +++ b/examples/request reply/streetlight/src/messages/TurnonCommand.ts @@ -0,0 +1,162 @@ +// To parse this data: +// +// import { Convert, TurnonCommand } from "./file"; +// +// const turnonCommand = Convert.toTurnonCommand(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface TurnonCommand { + /** + * How bright should the light be. + */ + lumen: number; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toTurnonCommand(json: string): TurnonCommand { + return cast(JSON.parse(json), r("TurnonCommand")); + } + + public static turnonCommandToJson(value: TurnonCommand): string { + return JSON.stringify(uncast(value, r("TurnonCommand")), null, 2); + } +} + +function invalidValue(typ: any, val: any): never { + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) {} + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "TurnonCommand": o([ + { json: "lumen", js: "lumen", typ: 0 }, + ], "any"), +}; diff --git a/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts b/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts new file mode 100644 index 000000000..f76244e14 --- /dev/null +++ b/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdCommandTurnon.spec.ts @@ -0,0 +1,77 @@ + + +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import * as Client from '../index' +import * as TestClient from './testclient/index' +import { NatsTypescriptTemplateError } from '../NatsTypescriptTemplateError'; + +describe('streetlight/{streetlight_id}/command/turnon can talk to it self', () => { + var client: Client.NatsAsyncApiClient; + var testClient: TestClient.NatsAsyncApiTestClient; + before(async () => { + client = new Client.NatsAsyncApiClient(); + testClient = new TestClient.NatsAsyncApiTestClient(); + const natsHost = process.env.NATS_HOST || "0.0.0.0" + const natsPort = process.env.NATS_PORT || "4222" + const natsUrl = `${natsHost}:${natsPort}` + await client.connectToHost(natsUrl); + await testClient.connectToHost(natsUrl); + }); + + it('Clients can connect', () => { + expect(client.isClosed()).to.be.false; + expect(testClient.isClosed()).to.be.false; + }); + + it('can send message', async () => { + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: TestClient.TurnonCommandMessage.TurnonCommand | undefined = undefined; +var recievedStreetlightId : string | undefined = undefined + + +var replyMessage: Client.GeneralReplyMessage.GeneralReply = { + "status_code": 0, + "status_message": "string" +}; +var receiveMessage: TestClient.TurnonCommandMessage.TurnonCommand = { + "lumen": 0 +}; +var StreetlightIdToSend: string = "string" + + +const replySubscription = await client.replyToStreetlightStreetlightIdCommandTurnon((err, msg + + ,streetlight_id + ) => { + return new Promise((resolve, reject) => { + receivedError = err; + receivedMsg = msg; + recievedStreetlightId = streetlight_id + + resolve(replyMessage); + })}, + (err) => {console.log(err)} + , StreetlightIdToSend + +); +var reply = await testClient.requestStreetlightStreetlightIdCommandTurnon(receiveMessage + , StreetlightIdToSend + ); +expect(reply).to.be.deep.equal(replyMessage) +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(receiveMessage); +expect(recievedStreetlightId).to.be.equal(StreetlightIdToSend); + + + }); + + it('Can shutdown', async () => { + await client.disconnect() + await testClient.disconnect() + expect(client.isClosed()).to.be.true; + expect(testClient.isClosed()).to.be.true; + }); + +}); \ No newline at end of file diff --git a/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts b/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts new file mode 100644 index 000000000..42e0cb88d --- /dev/null +++ b/examples/request reply/streetlight/src/tests/StreetlightStreetlightIdEventTurnon.spec.ts @@ -0,0 +1,78 @@ + + +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import * as Client from '../index' +import * as TestClient from './testclient/index' +import { NatsTypescriptTemplateError } from '../NatsTypescriptTemplateError'; + +describe('streetlight/{streetlight_id}/event/turnon can talk to it self', () => { + var client: Client.NatsAsyncApiClient; + var testClient: TestClient.NatsAsyncApiTestClient; + before(async () => { + client = new Client.NatsAsyncApiClient(); + testClient = new TestClient.NatsAsyncApiTestClient(); + const natsHost = process.env.NATS_HOST || "0.0.0.0" + const natsPort = process.env.NATS_PORT || "4222" + const natsUrl = `${natsHost}:${natsPort}` + await client.connectToHost(natsUrl); + await testClient.connectToHost(natsUrl); + }); + + it('Clients can connect', () => { + expect(client.isClosed()).to.be.false; + expect(testClient.isClosed()).to.be.false; + }); + + it('can send message', async () => { + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: Client.AnonymousMessage4Message.AnonymousMessage4 | undefined = undefined; +var recievedStreetlightId : string | undefined = undefined + + + +var replyMessage: TestClient.GeneralReplyMessage.GeneralReply = { + "status_code": 0, + "status_message": "string" +}; +var requestMessage: Client.AnonymousMessage4Message.AnonymousMessage4 = { + "lumen": 0 +}; +var StreetlightIdToSend: string = "string" + + +const replySubscription = await testClient.replyToStreetlightStreetlightIdEventTurnon((err, msg + + ,streetlight_id + ) => { + return new Promise((resolve, reject) => { + receivedError = err; + receivedMsg = msg; + recievedStreetlightId = streetlight_id + + resolve(replyMessage); + })}, + (err) => {console.log(err)} + , StreetlightIdToSend + +); +var reply = await client.requestStreetlightStreetlightIdEventTurnon(requestMessage + , StreetlightIdToSend + ); +expect(reply).to.be.deep.equal(replyMessage) +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(requestMessage); +expect(recievedStreetlightId).to.be.equal(StreetlightIdToSend); + + + }); + + it('Can shutdown', async () => { + await client.disconnect() + await testClient.disconnect() + expect(client.isClosed()).to.be.true; + expect(testClient.isClosed()).to.be.true; + }); + +}); \ No newline at end of file diff --git a/examples/request reply/streetlight/src/tests/testclient/index.ts b/examples/request reply/streetlight/src/tests/testclient/index.ts new file mode 100644 index 000000000..5833c14a8 --- /dev/null +++ b/examples/request reply/streetlight/src/tests/testclient/index.ts @@ -0,0 +1,266 @@ + + +import {fromSeed} from 'ts-nkeys'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../NatsTypescriptTemplateError'; +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; +import * as streetlightStreetlightIdCommandTurnonChannel from "./testchannels/StreetlightStreetlightIdCommandTurnon"; +export {streetlightStreetlightIdCommandTurnonChannel}; +import * as streetlightStreetlightIdEventTurnonChannel from "./testchannels/StreetlightStreetlightIdEventTurnon"; +export {streetlightStreetlightIdEventTurnonChannel}; +import * as TurnonCommandMessage from "../../messages/TurnonCommand"; +export {TurnonCommandMessage}; +import * as GeneralReplyMessage from "../../messages/GeneralReply"; +export {GeneralReplyMessage}; +import * as AnonymousMessage4Message from "../../messages/AnonymousMessage4"; +export {AnonymousMessage4Message}; + + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiTestClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiTestClient extends events.EventEmitter{ + + + private jsonClient?: Client; + private stringClient?: Client; + private binaryClient?: Client; + private options?: NatsConnectionOptions; + + /** + * + * @param options options to use, payload is omitted if sat in the AsyncAPI document. + */ + constructor() { + super(); + } + /** + * Try to connect to the NATS server with the different payloads. + */ + connect(options : NatsConnectionOptions): Promise{ + return new Promise(async (resolve: () => void, reject: (error: any) => void) => { + this.options = options; + try{ + if(!this.jsonClient || this.jsonClient!.isClosed()){ + this.options.payload = Payload.JSON; + this.jsonClient = await connect(this.options); + this.chainEvents(this.jsonClient); + } + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) + } + + /** + * Returns whether or not any of the clients are closed + */ + isClosed(){ + if (!this.jsonClient || this.jsonClient!.isClosed()){ + return true; + } + return false; + } + + /** + * Disconnect all clients from the server + */ + async disconnect(){ + if(this.jsonClient && !this.jsonClient!.isClosed()){ + this.jsonClient!.close(); + } + } + + private chainEvents(ns: Client){ + ns.on('permissionError', (e: NatsError) => { + this.emit(AvailableEvents.permissionError, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('close', (e: NatsError) => { + this.emit(AvailableEvents.close, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('connect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.connect, connection, serverURL, info) + }); + ns.on('connecting', (serverURL: string) => { + this.emit(AvailableEvents.connecting, serverURL) + }); + ns.on('disconnect', (serverURL: string) => { + this.emit(AvailableEvents.disconnect, serverURL) + }); + ns.on('error', (e: NatsError) => { + this.emit(AvailableEvents.error, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('pingcount', () => { + this.emit(AvailableEvents.pingcount) + }); + ns.on('pingtimer', () => { + this.emit(AvailableEvents.pingtimer) + }); + ns.on('reconnect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.reconnect, connection, serverURL, info) + }); + ns.on('reconnecting', (serverURL: string) => { + this.emit(AvailableEvents.reconnecting, serverURL) + }); + ns.on('serversChanged', (e: ServersChangedEvent) => { + this.emit(AvailableEvents.serversChanged, e) + }); + ns.on('subscribe', (e: SubEvent) => { + this.emit(AvailableEvents.subscribe, e) + }); + ns.on('unsubscribe', (e: SubEvent) => { + this.emit(AvailableEvents.unsubscribe, e) + }); + ns.on('yield', () => { + this.emit(AvailableEvents.yield) + }); + } + + /** + * Try to connect to the NATS server with user credentials + */ + async connectWithUserCreds(userCreds: string, options?: NatsConnectionOptions){ + await this.connect({ + userCreds: userCreds, + ... options + }); + } + /** + * Try to connect to the NATS server with user and password + */ + async connectWithUserPass(user: string, pass: string, options?: NatsConnectionOptions){ + await this.connect({ + user: user, + pass: pass, + ... options + }); + } + + /** + * Try to connect to the NATS server which has no authentication + */ + async connectToHost(host: string, options?: NatsConnectionOptions){ + await this.connect({ + servers: [host], + ... options + }); + } + + /** + * Try to connect to the NATS server with nkey authentication + */ + async connectWithNkey(publicNkey: string, seed: string, options?: NatsConnectionOptions){ + await this.connect({ + nkey: publicNkey, + nonceSigner: (nonce: string): Buffer => { + const sk = fromSeed(Buffer.from(seed)); + return sk.sign(Buffer.from(nonce)); + }, + ... options + }); + } + + + + /** + * Channel for the turn on command which should turn on the streetlight + * @param requestMessage The request message to send. + */ + public requestStreetlightStreetlightIdCommandTurnon( + requestMessage:TurnonCommandMessage.TurnonCommand + + ,streetlight_id: string + + ): Promise { + const nc: Client = this.jsonClient!; + if(nc){ + return streetlightStreetlightIdCommandTurnonChannel.request( + requestMessage, + nc + + ,streetlight_id + + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + + /** + * Channel for when the streetlight is turned on + * @param onRequest Called when request received. + * @param onReplyError Called when it was not possible to send the reply. + */ + public replyToStreetlightStreetlightIdEventTurnon( + onRequest : ( + err?: NatsTypescriptTemplateError, + msg?: AnonymousMessage4Message.AnonymousMessage4,streetlight_id?: string + ) =>Promise, + onReplyError : (err: NatsTypescriptTemplateError) => void + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + const nc: Client = this.jsonClient!; + + if(nc){ + return streetlightStreetlightIdEventTurnonChannel.reply( + onRequest, + onReplyError, + nc + + ,streetlight_id + , + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } + + +} \ No newline at end of file diff --git a/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts b/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts new file mode 100644 index 000000000..e89cf465a --- /dev/null +++ b/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdCommandTurnon.ts @@ -0,0 +1,54 @@ + +import * as TurnonCommandMessage from '../../../messages/TurnonCommand'; +import * as GeneralReplyMessage from '../../../messages/GeneralReply'; +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../../NatsTypescriptTemplateError'; +import { Hooks } from '../../../hooks'; + +export function request( + message: TurnonCommandMessage.TurnonCommand, + nc: Client + + ,streetlight_id: string + + ): Promise { + return new Promise(async (resolve, reject) => { + var timeout = undefined; + let msg; + try { + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + msg = await nc.request(`streetlight.${streetlight_id}.command.turnon`, timeout, dataToSend) + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + return; + } + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + reject(error); + return; +} + + resolve(receivedData); + }) +} + + diff --git a/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts b/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts new file mode 100644 index 000000000..43159bcd9 --- /dev/null +++ b/examples/request reply/streetlight/src/tests/testclient/testchannels/StreetlightStreetlightIdEventTurnon.ts @@ -0,0 +1,85 @@ + +import * as GeneralReplyMessage from '../../../messages/GeneralReply'; +import * as AnonymousMessage4Message from '../../../messages/AnonymousMessage4'; +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../../NatsTypescriptTemplateError'; +import { Hooks } from '../../../hooks'; + +export function reply( + onRequest: (err?: NatsTypescriptTemplateError, msg?: AnonymousMessage4Message.AnonymousMessage4, streetlight_id?: string) =>Promise, + onReplyError: (err: NatsTypescriptTemplateError) => void, + nc: Client + + ,streetlight_id: string + , + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + try { + let subscribeOptions: SubscriptionOptions = {... options}; + + let subscription = nc.subscribe(`streetlight.${streetlight_id}.event.turnon`,async (err, msg) => { + if (err) { + onRequest(err); + } else { + +var unmodifiedChannel = `streetlight.{streetlight_id}.event.turnon`; +var channel = msg.subject; + var streetlightIdSplit = unmodifiedChannel.split("{streetlight_id}"); + +const splits = [ + streetlightIdSplit[0], + streetlightIdSplit[1] +]; +channel = channel.substring(splits[0].length); +var streetlightIdEnd = channel.indexOf(splits[1]); +var streetlightIdParam = "" + channel.substring(0, streetlightIdEnd); + + +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + onReplyError(error); + return; +} + + + let message =await onRequest(undefined, receivedData, + streetlightIdParam); + + if (msg.reply) { + +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + onReplyError(error) + return; +} + + + await nc.publish(msg.reply, dataToSend); + } else { + let error = new NatsTypescriptTemplateError('Expected request to need a reply, did not..', '000'); + onReplyError(error) + return; + } + } + }, subscribeOptions); + resolve(subscription); + } catch (e) { + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + + diff --git a/examples/request reply/streetlight/tsconfig.json b/examples/request reply/streetlight/tsconfig.json new file mode 100644 index 000000000..75097457a --- /dev/null +++ b/examples/request reply/streetlight/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "declaration": true, + "strict": true, + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "outDir": "dist/", + "baseUrl": "./src" + }, + "include": ["src"], + "exclude": ["node_modules", "**/*.spec.ts"] +} diff --git a/filters/all.js b/filters/all.js new file mode 100644 index 000000000..ac0803d5b --- /dev/null +++ b/filters/all.js @@ -0,0 +1,289 @@ +const filter = module.exports; +const _ = require('lodash'); + + +/** + * Figure out if our message content type or default content type matches a given payload. + * @param {*} messageContentType to check + * @param {*} defaultContentType to check + * @param {*} payload to find + */ +function containsPayload(messageContentType, defaultContentType, payload) { + if ( + (messageContentType != null && + messageContentType.toLowerCase() == payload) || + (defaultContentType != null && defaultContentType == payload) + ) { + return true; + } + return false; +} +filter.isBinaryPayload = (messageContentType, defaultContentType) => { + return containsPayload(messageContentType, defaultContentType, 'binary'); +} +filter.isStringPayload = (messageContentType, defaultContentType) => { + return containsPayload(messageContentType, defaultContentType, 'string'); +} +filter.isJsonPayload = (messageContentType, defaultContentType) => { + return containsPayload(messageContentType, defaultContentType, 'json'); +} + +filter.messageHasNotNullPayload = (messagePayload) => { + return messagePayload.type()+"" != "null"; +} + +/** + * Because quicktype cant handle null types we have to ensure if it is null thats + */ +filter.getMessageType = (message) => { + if(message.payload().type()+"" == "null"){ + return "null"; + }else{ + return `${this.pascalCase(message.uid())}Message.${this.pascalCase(message.uid())}`; + } +} + +/** + * Figure out if a content type is located in the document. + * @param {*} document to look through + * @param {*} payload to find + */ +function containsPayloadInDocument(document, payload) { + if ( + document.defaultContentType() != null && + document.defaultContentType().toLowerCase() == payload + ) { + return true; + } + if (document.channels() != null) { + for (let channelName in document.channels()) { + let channel = document.channels()[channelName]; + if ( + (channel.hasPublish() && + channel + .publish() + .message() + .contentType() != null && + channel + .publish() + .message() + .contentType() + .toLowerCase() == payload) || + (channel.hasSubscribe() && + channel + .subscribe() + .message() + .contentType() != null && + channel + .subscribe() + .message() + .contentType() + .toLowerCase() == payload) + ) { + return true; + } + } + } + return false; +} +filter.containsBinaryPayload = document => { + return containsPayloadInDocument(document, 'binary'); +} +filter.containsStringPayload = document => { + return containsPayloadInDocument(document, 'string'); +} +filter.containsJsonPayload = document => { + return containsPayloadInDocument(document, 'json'); +} + +function camelCase(string) { + return _.camelCase(string); +} +function pascalCase(string) { + string = _.camelCase(string); + return string.charAt(0).toUpperCase() + string.slice(1); +} + +filter.firstUpperCase = string => { + return string.charAt(0).toUpperCase() + string.slice(1); +} +filter.pascalCase = string => { + return pascalCase(string); +} +filter.kebabCase = string => { + return _.kebabCase(string); +} + +filter.camelCase = string => { + return camelCase(string); +} + +/** + * Convert JSON schema draft 7 types to typescript types + * @param {*} jsonSchemaType + * @param {*} property + */ +function toTsType(jsonSchemaType, property) { + switch (jsonSchemaType.toLowerCase()) { + case 'string': + return 'string'; + case 'integer': + case 'number': + return 'Number'; + case 'boolean': + return 'Boolean'; + case 'object': + if(property){ + return property.uid() + 'Schema'; + }else{ + return 'any'; + } + default: return 'any'; + } +} +filter.toTsType = toTsType; + + +/** + * Cast JSON schema variable to typescript type + * + * @param {*} jsonSchemaType + * @param {*} variableToCast + */ +function castToTsType(jsonSchemaType, variableToCast) { + switch (jsonSchemaType.toLowerCase()) { + case 'string': + return `"" + ${variableToCast}`; + case 'integer': + case 'number': + return `Number(${variableToCast})`; + case 'boolean': + return `Boolean(${variableToCast})`; + default: throw new Error("Parameter type not supported - " + jsonSchemaType); + } +} +filter.castToTsType = castToTsType; + +/** + * Convert RFC 6570 URI with parameters to NATS topic. + */ +function realizeChannelName(parameters, channelName){ + let returnString = '\`' + channelName + '\`'; + returnString = returnString.replace(/\//g, `.`); + for (paramName in parameters) { + returnString = returnString.replace(`{${paramName}}`, `\${${paramName}}`); + } + return returnString; +} + +filter.realizeChannelName = realizeChannelName; + +filter.realizeChannelNameWithoutParameters = (channelName) => { + return realizeChannelName(null, channelName); +} + +/** + * Realize parameters without using types and without trailing comma + */ +filter.realizeParametersForChannelWithoutType = (parameters) => { + let returnString = ''; + for (paramName in parameters) { + returnString += `${filter.realizeParameterForChannelWithoutType(paramName)},`; + } + if (returnString.length >= 1) { + returnString = returnString.slice(0, -1); + } + return returnString; +} + +filter.realizeParameterForChannelWithoutType = (parameterName) => { + return `${parameterName}`; +} +filter.realizeParameterForChannelWithType = (parameterName, parameter, required = true) => { + const requiredType = !required ? '?' : '' + return `${parameterName}${requiredType}: ${toTsType( + parameter.schema().type() + )}`; +} + +/** + * Realize parameters using types without trailing comma + */ +filter.realizeParametersForChannel = (parameters, required = true) => { + let returnString = ''; + for (paramName in parameters) { + returnString += filter.realizeParameterForChannelWithType(paramName, parameters[paramName], required) + ","; + } + if (returnString.length >= 1) { + returnString = returnString.slice(0, -1); + } + return returnString; +} + +/** + * Does an object have bindings + */ +filter.hasNatsBindings = obj => { + return obj.bindings && obj.bindings.nats; +} + +/** + * is the channel a publish and subscribe type if nothing is specified default to being pubsub type + */ +filter.isPubsub = channel => { + const tempChannel = channel._json; + if ( + !tempChannel.bindings || + !tempChannel.bindings.nats || + !tempChannel.bindings.nats.is || + tempChannel.bindings.nats.is == 'pubsub') { + return true; + } + return false; +} + +/** + * is the channel a request and reply + */ +function isRequestReply(channel){ + let tempChannel = channel._json; + if ( + tempChannel.bindings && + tempChannel.bindings.nats && + tempChannel.bindings.nats.is == 'requestReply' + ) { + return true; + } + return false; +} +filter.isRequestReply = isRequestReply; + +/** + * Is the request reply a requester + */ +filter.isRequester = channel => { + let tempChannel = channel._json; + if ( + isRequestReply(channel) && + tempChannel.bindings.nats.requestReply && + tempChannel.bindings.nats.requestReply.is == 'requester' + ) { + return true; + } + return false; +} + +/** + * Is the request reply a replier + */ +filter.isReplier = channel => { + let tempChannel = channel._json; + if ( + isRequestReply(channel) && + tempChannel.bindings.nats.requestReply && + tempChannel.bindings.nats.requestReply.is == 'replier' + ) { + return true; + } + return false; +} diff --git a/hooks/filename-change.js b/hooks/filename-change.js new file mode 100644 index 000000000..187daa0a2 --- /dev/null +++ b/hooks/filename-change.js @@ -0,0 +1,12 @@ +const filters = require("../filters/all") + +/** + * Change the filenames of templates files to match the rest. + */ +module.exports = { + 'setFileTemplateName': (generator, hookArguments) => { + const currentFilename = hookArguments.originalFilename; + let newFilename = filters.pascalCase(currentFilename) + return newFilename + } +}; \ No newline at end of file diff --git a/hooks/quicktype-schema.js b/hooks/quicktype-schema.js new file mode 100644 index 000000000..150dc3eed --- /dev/null +++ b/hooks/quicktype-schema.js @@ -0,0 +1,18 @@ +const quicktypeFilter = require('@lagoni/asyncapi-quicktype-filter'); + +/** + * Use quicktype to generate messages with their payload. + */ +module.exports = { + 'generate:after': async (generator) => { + const allMessages = generator.asyncapi.allMessages(); + await quicktypeFilter.generateAllMessagePayloads( + generator.targetDir, + { + quicktypeLanguage: "typescript", + subTargetDir: "src/messages/" + }, + allMessages + ); + } +}; diff --git a/hooks/remove-test-files.js b/hooks/remove-test-files.js new file mode 100644 index 000000000..cafb7fec8 --- /dev/null +++ b/hooks/remove-test-files.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const Path = require('path'); + +/** + * Remove a folder recursively. + * + * @param {string} path to recursively remove + */ +const deleteFolderRecursive = function(path) { + if (fs.existsSync(path) && path !== "/") { + fs.readdirSync(path).forEach((file, index) => { + const curPath = Path.join(path, file); + if (fs.lstatSync(curPath).isDirectory()) { // recurse + deleteFolderRecursive(curPath); + } else { // delete file + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(path); + } +}; + +/** + * Since we cannot have a condition on a template whether to generate something + * or not we have to remove the test client if its not specified. + */ +module.exports = { + 'generate:after': (generator) => { + if(generator.targetDir && generator.templateParams && !generator.templateParams.generateTestClient){ + pathToTests = Path.resolve(generator.targetDir, "src/tests/") + deleteFolderRecursive(pathToTests) + } + } +}; diff --git a/hooks/rename-njk.js b/hooks/rename-njk.js new file mode 100644 index 000000000..ffcb4a641 --- /dev/null +++ b/hooks/rename-njk.js @@ -0,0 +1,33 @@ +const fs = require('fs'); +const path = require('path'); + +/** + * Rename all the generated files whos extension is .njk + * + * @param {string} dir to recursively rename files with njk extension + */ +var renameAllSync = function(dir) { + files = fs.readdirSync(dir); + files.forEach(function(file) { + let filepath = path.resolve(dir, file); + if (fs.statSync(filepath).isDirectory()) { + renameAllSync(filepath); + } else if ( + path.extname(filepath) === '.njk' && + !dir.includes('node_modules') + ) { + let newName = path.basename(filepath, '.njk'); + let newPath = path.resolve(dir, newName); + fs.renameSync(filepath, newPath); + } + }); +}; + +/** + * Rename all the njk files to get the correct extensions + */ +module.exports = { + 'generate:after': (generator) => { + renameAllSync(path.resolve(generator.targetDir)); + } +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..368d0d8c5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6675 @@ +{ + "name": "@asyncapi/ts-nats-template", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@asyncapi/generator-filters": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@asyncapi/generator-filters/-/generator-filters-1.0.0.tgz", + "integrity": "sha512-LcqLwUh/PqcHzIyEWxPT3pIehzif8d7aVq/CBWx0Hni7x/jsEbQhvtgT8LQpwHFLTZrNAKuxGivzOk3Ero+SQQ==", + "requires": { + "lodash": "^4.17.15", + "markdown-it": "^10.0.0", + "openapi-sampler": "^1.0.0-beta.15" + } + }, + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@lagoni/asyncapi-quicktype-filter": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lagoni/asyncapi-quicktype-filter/-/asyncapi-quicktype-filter-1.2.3.tgz", + "integrity": "sha512-v8vsK2IhvJP0MhYPF9YAF+YLfbQrlcS6Qa9G3g7aFNgh2PMLIrf1uiD9ZzPpyF94vaRZCMlli3iaTKhZYkpYYA==", + "requires": { + "is-url": "^1.2.4", + "lodash": "^4.17.15", + "quicktype-core": "6.0.66" + } + }, + "@mark.probst/unicode-properties": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mark.probst/unicode-properties/-/unicode-properties-1.1.0.tgz", + "integrity": "sha512-7AQsO0hMmpqDledV7AhBuSYqYPFsKP9PaltMecX9nlnsyFxqtsqUg9/pvB2L/jxvskrDrNkdKYz2KTbQznCtng==", + "requires": { + "brfs": "^1.4.0", + "unicode-trie": "^0.3.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@octokit/auth-token": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.3.tgz", + "integrity": "sha512-fdGoOQ3kQJh+hrilc0Plg50xSfaCKOeYN9t6dpJKXN9BxhhfquL0OzoQXg3spLYymL5rm29uPeI3KEXRaZQ9zg==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.0" + } + }, + "@octokit/core": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.1.tgz", + "integrity": "sha512-XfFSDDwv6tclUenS0EmB6iA7u+4aOHBT1Lz4PtQNQQg3hBbNaR/+Uv5URU+egeIuuGAiMRiDyY92G4GBOWOqDA==", + "dev": true, + "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/graphql": "^4.3.1", + "@octokit/request": "^5.4.0", + "@octokit/types": "^5.0.0", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.9.tgz", + "integrity": "sha512-3VPLbcCuqji4IFTclNUtGdp9v7g+nspWdiCUbK3+iPMjJCZ6LEhn1ts626bWLOn0GiDb6j+uqGvPpqLnY7pBgw==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.7.tgz", + "integrity": "sha512-Gk0AR+DcwIK/lK/GX+OQ99UqtenQhcbrhHHfOYlrCQe17ADnX3EKAOKRsAZ9qZvpi5MuwWm/Nm+9aO2kTDSdyA==", + "dev": true, + "requires": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/plugin-paginate-rest": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.6.0.tgz", + "integrity": "sha512-o+O8c1PqsC5++BHXfMZabRRsBIVb34tXPWyQLyp2IXq5MmkxdipS7TXM4Y9ldL1PzY9CTrCsn/lzFFJGM3oRRA==", + "dev": true, + "requires": { + "@octokit/types": "^5.5.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz", + "integrity": "sha512-oTJSNAmBqyDR41uSMunLQKMX0jmEXbwD1fpz8FG27lScV3RhtGfBa1/BBLym+PxcC16IBlF7KH9vP1BUYxA+Eg==", + "dev": true + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.2.1.tgz", + "integrity": "sha512-QyFr4Bv807Pt1DXZOC5a7L5aFdrwz71UHTYoHVajYV5hsqffWm8FUl9+O7nxRu5PDMtB/IKrhFqTmdBTK5cx+A==", + "dev": true, + "requires": { + "@octokit/types": "^5.5.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.4.10", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.10.tgz", + "integrity": "sha512-egA49HkqEORVGDZGav1mh+VD+7uLgOxtn5oODj6guJk0HCy+YBSYapFkSLFgeYj3Fr18ZULKGURkjyhkAChylw==", + "dev": true, + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^5.0.0", + "deprecation": "^2.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", + "once": "^1.4.0", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + } + } + }, + "@octokit/request-error": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.3.tgz", + "integrity": "sha512-GgD5z8Btm301i2zfvJLk/mkhvGCdjQ7wT8xF9ov5noQY8WbKZDH9cOBqXzoeKd1mLr1xH2FwbtGso135zGBgTA==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.1", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.0.9", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.9.tgz", + "integrity": "sha512-CC5+cIx974Ygx9lQNfUn7/oXDQ9kqGiKUC6j1A9bAVZZ7aoTF8K6yxu0pQhQrLBwSl92J6Z3iVDhGhGFgISCZg==", + "dev": true, + "requires": { + "@octokit/core": "^3.0.0", + "@octokit/plugin-paginate-rest": "^2.2.0", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "4.2.1" + } + }, + "@octokit/types": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", + "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + }, + "@semantic-release/commit-analyzer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", + "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.7", + "debug": "^4.0.0", + "import-from": "^3.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.2" + } + }, + "@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, + "@semantic-release/github": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.2.0.tgz", + "integrity": "sha512-tMRnWiiWb43whRHvbDGXq4DGEbKRi56glDpXDJZit4PIiwDPX7Kx3QzmwRtDOcG+8lcpGjpdPabYZ9NBxoI2mw==", + "dev": true, + "requires": { + "@octokit/rest": "^18.0.0", + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "bottleneck": "^2.18.1", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "issue-parser": "^6.0.0", + "lodash": "^4.17.4", + "mime": "^2.4.3", + "p-filter": "^2.0.0", + "p-retry": "^4.0.0", + "url-join": "^4.0.0" + } + }, + "@semantic-release/npm": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.8.tgz", + "integrity": "sha512-8c1TLwKB/xT5E1FNs5l4GFtaNTznHesJk7tw3pGSlVxRqDXa1EZI+DfziZlO58Wk3PpS2ecu661kvBdz9aMgYQ==", + "dev": true, + "requires": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "execa": "^4.0.0", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "nerf-dart": "^1.0.0", + "normalize-url": "^5.0.0", + "npm": "^6.14.8", + "rc": "^1.2.8", + "read-pkg": "^5.0.0", + "registry-auth-token": "^4.0.0", + "semver": "^7.1.2", + "tempy": "^1.0.0" + } + }, + "@semantic-release/release-notes-generator": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz", + "integrity": "sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ==", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-changelog-writer": "^4.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.0", + "debug": "^4.0.0", + "get-stream": "^5.0.0", + "import-from": "^3.0.0", + "into-stream": "^5.0.0", + "lodash": "^4.17.4", + "read-pkg-up": "^7.0.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", + "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "dev": true + }, + "@types/node": { + "version": "14.14.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.8.tgz", + "integrity": "sha512-z/5Yd59dCKI5kbxauAJgw6dLPzW+TNOItNE00PkpzNwUIEwdj/Lsqwq94H5DdYBX7C13aRA0CY32BK76+neEUA==", + "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/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "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": "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": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "before-after-hook": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "dev": true + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", + "requires": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^2.2.0", + "through2": "^2.0.0" + } + }, + "browser-or-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz", + "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==" + }, + "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==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "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": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "conventional-changelog-angular": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", + "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", + "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-changelog-writer": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.18.tgz", + "integrity": "sha512-mAQDCKyB9HsE8Ko5cCM1Jn1AWxXPYV0v8dFPabZRkvsiWUul2YyAqbIaoMKF88Zf2ffnOPSvKhboLf3fnjo5/A==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, + "conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.0.tgz", + "integrity": "sha512-XmJiXPxsF0JhAKyfA2Nn+rZwYKJ60nanlbSWwwkGwLQFbugsc0gv1rzc7VbbUWAzJfR1qR87/pNgv9NgmxtBMQ==", + "dev": true, + "requires": { + "JSONStream": "^1.0.4", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^2.0.0", + "through2": "^4.0.0", + "trim-off-newlines": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "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=" + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "cross-env": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", + "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "del": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "dev": true, + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "dependencies": { + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + } + } + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "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 + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "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" + } + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "env-ci": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.2.tgz", + "integrity": "sha512-Xc41mKvjouTXD3Oy9AqySz1IeyvJvHZ20Twf5ZLYbNpPPIuCnL/qHCmNlD01LoNy0JTunw9HPYVptD19Ac7Mbw==", + "dev": true, + "requires": { + "execa": "^4.0.0", + "java-properties": "^1.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "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=" + }, + "escodegen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", + "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + } + } + }, + "falafel": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", + "requires": { + "acorn": "^7.1.1", + "foreach": "^2.0.5", + "isarray": "^2.0.1", + "object-keys": "^1.0.6" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fastq": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", + "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "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=" + }, + "filenamify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.1.0.tgz", + "integrity": "sha512-KQV/uJDI9VQgN7sHH1Zbk6+42cD6mnQ2HONzkXUfPJ+K2FC8GZ1dpewbbHw0Sz8Tf5k3EVdHVayM4DoAwWlmtg==", + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, + "requires": { + "semver-regex": "^2.0.0" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "git-log-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", + "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", + "dev": true, + "requires": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + }, + "dependencies": { + "split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", + "dev": true, + "requires": { + "through2": "~2.0.0" + } + } + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "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 + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "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", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hook-std": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", + "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", + "dev": true + }, + "hosted-git-info": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", + "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "into-stream": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", + "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", + "dev": true, + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "dev": true, + "requires": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + } + }, + "java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true + }, + "js-base64": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.3.tgz", + "integrity": "sha512-fiUvdfCaAXoQTHdKMgTvg6IkecXDcVz6V5rlftUTclF9IKBjMizvSdQaCl/z/6TApDeby5NL+axYou3i0mu1Pg==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-pointer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.0.tgz", + "integrity": "sha1-jlAFUKaqxUZKRzN32leqbMIoKNc=", + "requires": { + "foreach": "^2.0.4" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "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 + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "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 + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", + "dev": true + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true + }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "requires": { + "vlq": "^0.2.2" + } + }, + "map-obj": { + "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 + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "marked": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.4.tgz", + "integrity": "sha512-6x5TFGCTKSQBLTZtOburGxCxFEBJEGYVLwCMTBCxzvyuisGcC20UNzDSJhCr/cJ/Kmh6ulfJm10g6WWEAJ3kvg==", + "dev": true + }, + "marked-terminal": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.1.0.tgz", + "integrity": "sha512-5KllfAOW02WS6hLRQ7cNvGOxvKW1BKuXELH4EtbWfyWgxQhROoMxEvuQ/3fTgkNjledR0J48F4HbapvYp1zWkQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.1", + "cardinal": "^2.1.1", + "chalk": "^4.0.0", + "cli-table": "^0.3.1", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "meow": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", + "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + } + }, + "merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "requires": { + "source-map": "^0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true + }, + "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 + }, + "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 + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minimist-options": { + "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", + "kind-of": "^6.0.3" + } + }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", + "dev": true + }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dev": true, + "requires": { + "lodash.toarray": "^4.4.0" + } + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-url": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.3.0.tgz", + "integrity": "sha512-9/nOVLYYe/dO/eJeQUNaGUF4m4Z5E7cb9oNTKabH+bNf19mqj60txTcveQxL0GlcWLXCxkOu2/LwL8oW0idIDA==", + "dev": true + }, + "npm": { + "version": "6.14.8", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz", + "integrity": "sha512-HBZVBMYs5blsj94GTeQZel7s9odVuuSUHy1+AlZh7rPVux1os2ashvEGLy/STNK7vUjbrCg5Kq9/GXisJgdf6A==", + "dev": true, + "requires": { + "JSONStream": "^1.3.5", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.8", + "bluebird": "^3.5.5", + "byte-size": "^5.0.1", + "cacache": "^12.0.3", + "call-limit": "^1.1.1", + "chownr": "^1.1.4", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.12", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.1", + "glob": "^7.1.6", + "graceful-fs": "^4.2.4", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.8", + "iferr": "^1.0.2", + "imurmurhash": "*", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^3.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.8", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.4", + "lock-verify": "^2.1.0", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "^1.0.2", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.5", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.1.0", + "nopt": "^4.0.3", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.3", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.5", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.8", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.4", + "npm-registry-fetch": "^4.0.7", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.1", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.8.2", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.1", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.6.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "^2.7.1", + "safe-buffer": "^5.1.2", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.1", + "stringify-package": "^1.0.1", + "tar": "^4.4.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.3", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "bundled": true, + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "asap": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true, + "dev": true + }, + "aws4": { + "version": "1.8.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "1.1.8", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cmd-shim": "^3.0.0", + "gentle-fs": "^2.3.0", + "graceful-fs": "^4.1.15", + "npm-normalize-package-bin": "^1.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "bluebird": { + "version": "3.5.5", + "bundled": true, + "dev": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "builtins": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "byline": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "byte-size": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "cacache": { + "version": "12.0.3", + "bundled": true, + "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" + } + }, + "call-limit": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "2.0.10", + "bundled": true, + "dev": true, + "requires": { + "ip-regex": "^2.1.0" + } + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "colors": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "config-chain": { + "version": "1.1.12", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.5", + "bundled": true, + "dev": true, + "requires": { + "dot-prop": "^4.2.1", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "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": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + } + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cyclist": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dot-prop": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "duplexify": { + "version": "3.6.0", + "bundled": true, + "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.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.12", + "bundled": true, + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-paths": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "err-code": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "errno": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "bundled": true, + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "bundled": true, + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "bundled": true, + "dev": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "flush-write-stream": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.6.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "gentle-fs": { + "version": "2.3.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2", + "chownr": "^1.1.2", + "cmd-shim": "^3.0.3", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "infer-owner": "^1.0.4", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "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" + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.4", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "har-validator": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "bundled": true, + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ci-info": "^1.5.0" + }, + "dependencies": { + "ci-info": { + "version": "1.6.0", + "bundled": true, + "dev": true + } + } + }, + "is-cidr": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "cidr-regex": "^2.0.10" + } + }, + "is-date-object": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true, + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "libcipm": { + "version": "4.0.8", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "ini": "^1.3.5", + "lock-verify": "^2.1.0", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^9.1.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "libnpm": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "find-npm-prefix": "^1.0.2", + "libnpmaccess": "^3.0.2", + "libnpmconfig": "^1.2.1", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmpublish": "^1.1.2", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "lock-verify": "^2.0.2", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "npm-profile": "^4.0.2", + "npm-registry-fetch": "^4.0.0", + "npmlog": "^4.1.2", + "pacote": "^9.5.3", + "read-package-json": "^2.0.13", + "stringify-package": "^1.0.0" + } + }, + "libnpmaccess": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmconfig": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "find-up": "^3.0.0", + "ini": "^1.3.5" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + } + } + }, + "libnpmhook": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmorg": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmpublish": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + } + }, + "libnpmsearch": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmteam": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpx": { + "version": "10.2.4", + "bundled": true, + "dev": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^14.2.3" + } + }, + "lock-verify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "npm-package-arg": "^6.1.0", + "semver": "^5.4.1" + } + }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "bundled": true, + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true, + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true, + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true, + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-fetch-happen": { + "version": "5.0.2", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "meant": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "mime-db": { + "version": "1.35.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "bundled": true, + "dev": true + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.9.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "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" + } + }, + "mkdirp": { + "version": "0.5.5", + "bundled": true, + "dev": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "bundled": true, + "dev": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "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": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true, + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-gyp": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + } + }, + "nopt": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "npm-audit-report": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "requires": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "npm-install-checks": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "3.1.5", + "bundled": true, + "dev": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "npm-package-arg": { + "version": "6.1.1", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.8", + "bundled": true, + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-profile": { + "version": "4.0.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2 || 2", + "figgy-pudding": "^3.4.1", + "npm-registry-fetch": "^4.0.0" + } + }, + "npm-registry-fetch": { + "version": "4.0.7", + "bundled": true, + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "bundled": true, + "dev": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "bundled": true, + "dev": true + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "9.5.12", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-normalize-package-bin": "^1.0.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true, + "dev": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true, + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "prr": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "psl": { + "version": "1.1.29", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "bundled": true, + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "qs": { + "version": "6.5.2", + "bundled": true, + "dev": true + }, + "query-string": { + "version": "6.8.2", + "bundled": true, + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "qw": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + } + }, + "read-package-json": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "bundled": true, + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "request": { + "version": "2.88.0", + "bundled": true, + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "smart-buffer": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "dev": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true, + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "bundled": true, + "dev": true + }, + "split-on-first": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + } + } + }, + "stringify-package": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "through": { + "version": "2.3.8", + "bundled": true, + "dev": true + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "typedarray": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "umask": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "util-extend": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.3.3", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "widest-line": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "bundled": true, + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "14.2.3", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "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", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "15.0.1", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "bundled": true, + "dev": true + } + } + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "openapi-sampler": { + "version": "1.0.0-beta.15", + "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.0.0-beta.15.tgz", + "integrity": "sha512-wUD/vD3iBHKik/sME3uwUu4X3HFA53rDrPcVvLzgEELjHLbnTpSYfm4Jo9qZT1dPfBRowAnrF/VRQfOjL5QRAw==", + "requires": { + "json-pointer": "^0.6.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "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" + } + }, + "p-each-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", + "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", + "dev": true + }, + "p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + } + }, + "p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true + }, + "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": "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-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true + }, + "p-retry": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz", + "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==", + "dev": true, + "requires": { + "@types/retry": "^0.12.0", + "retry": "^0.12.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 + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "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-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-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==" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "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 + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "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" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": 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 + } + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "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" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "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 + }, + "quicktype-core": { + "version": "6.0.66", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-6.0.66.tgz", + "integrity": "sha512-eSvyyqm/zwAdIIzzNlQtc6AwdqvqGtxTDT23idnAG29yCNzU2K2ZXHaKTi5kwxDdbgHn0QBJPNBVWBzKSbryjg==", + "requires": { + "@mark.probst/unicode-properties": "~1.1.0", + "browser-or-node": "^1.2.1", + "collection-utils": "^1.0.1", + "isomorphic-fetch": "^2.2.1", + "js-base64": "^2.4.3", + "pako": "^1.0.6", + "pluralize": "^7.0.0", + "readable-stream": "2.3.0", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^1.5.0" + } + }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", + "requires": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + }, + "dependencies": { + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "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": "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": "^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 + } + } + }, + "readable-stream": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.0.tgz", + "integrity": "sha512-c7KMXGd4b48nN3OJ1U9qOsn6pXNzf6kLd3kdZCkg2sxAcoiufInqF0XckwEnlrcwuaYwonlNK8GQUIOC/WC7sg==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.0", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "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 + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", + "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semantic-release": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.2.3.tgz", + "integrity": "sha512-MY1MlowGQrkOR7+leOD8ICkVOC6i1szbwDODdbJ0UdshtMx8Ms0bhpRQmEEliqYKEb5PLv/dqs6zKKuHT7UxTg==", + "dev": true, + "requires": { + "@semantic-release/commit-analyzer": "^8.0.0", + "@semantic-release/error": "^2.2.0", + "@semantic-release/github": "^7.0.0", + "@semantic-release/npm": "^7.0.0", + "@semantic-release/release-notes-generator": "^9.0.0", + "aggregate-error": "^3.0.0", + "cosmiconfig": "^6.0.0", + "debug": "^4.0.0", + "env-ci": "^5.0.0", + "execa": "^4.0.0", + "figures": "^3.0.0", + "find-versions": "^3.0.0", + "get-stream": "^5.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^2.0.0", + "hosted-git-info": "^3.0.0", + "lodash": "^4.17.15", + "marked": "^1.0.0", + "marked-terminal": "^4.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "p-reduce": "^2.0.0", + "read-pkg-up": "^7.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^3.1.1", + "signale": "^1.2.1", + "yargs": "^15.0.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, + "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 + }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "requires": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "requires": { + "through2": "^2.0.2" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "static-eval": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", + "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", + "requires": { + "escodegen": "^1.11.1" + }, + "dependencies": { + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + } + } + }, + "static-module": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/static-module/-/static-module-2.2.5.tgz", + "integrity": "sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ==", + "requires": { + "concat-stream": "~1.6.0", + "convert-source-map": "^1.5.1", + "duplexer2": "~0.1.4", + "escodegen": "~1.9.0", + "falafel": "^2.1.0", + "has": "^1.0.1", + "magic-string": "^0.22.4", + "merge-source-map": "1.0.4", + "object-inspect": "~1.4.0", + "quote-stream": "~1.0.2", + "readable-stream": "~2.3.3", + "shallow-copy": "~0.0.1", + "static-eval": "^2.0.0", + "through2": "~2.0.3" + }, + "dependencies": { + "object-inspect": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.4.1.tgz", + "integrity": "sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw==" + }, + "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==", + "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" + } + } + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "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" + } + }, + "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==", + "requires": { + "safe-buffer": "~5.1.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" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-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=", + "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==", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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 + }, + "tempy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", + "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", + "dev": true, + "requires": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true + } + } + }, + "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 + }, + "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": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.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==", + "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" + } + } + } + }, + "tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, + "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" + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", + "dev": true + }, + "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=", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "uglify-js": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.11.6.tgz", + "integrity": "sha512-oASI1FOJ7BBFkSCNDZ446EgkSuHkOZBuqRFrwXIKWCoXw8ZXQETooTQjkAcBS03Acab7ubCKsXnwuV2svy061g==", + "dev": true, + "optional": true + }, + "unicode-trie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", + "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", + "requires": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + }, + "dependencies": { + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "urijs": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", + "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "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" + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" + }, + "whatwg-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.2.0.tgz", + "integrity": "sha512-SdGPoQMMnzVYThUbSrEvqTlkvC1Ux27NehaJ/GUHBfNrh5Mjg+1/uRyFMwVnxO2MrikMWvWAqUGgQOfVU4hT7w==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "dependencies": { + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..052f830e7 --- /dev/null +++ b/package.json @@ -0,0 +1,96 @@ +{ + "name": "@asyncapi/ts-nats-template", + "version": "0.1.0", + "description": "NATS TypeScript/Node.js template for the AsyncAPI generator.", + "keywords": [ + "asyncapi", + "generator", + "ts", + "nats", + "template" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/asyncapi/ts-nats-template.git" + }, + "bugs": { + "url": "https://github.com/asyncapi/ts-nats-template/issues" + }, + "homepage": "https://github.com/asyncapi/ts-nats-template#readme", + "author": "Jonas Lagoni (jonas-lt@live.dk)", + "license": "Apache-2.0", + "scripts": { + "generate:examples": "npm run generate:examples:pubSub && npm run generate:examples:requestReply", + "generate:examples:pubSub": "cd \"examples/publish subscribe\" && sh GenerateAndBuild.sh", + "generate:examples:requestReply": "cd \"examples/request reply\" && sh GenerateAndBuild.sh", + "release": "semantic-release", + "lint": "echo \"No linter specified yet\"", + "test": "echo \"No tests specified yet\"", + "test:examples:integration": "npm run test:examples:integration:pubsub && npm run test:examples:integration:requestreply", + "test:examples:integration:pubsub": "cd \"examples/publish subscribe\" && sh ./Test.sh", + "test:examples:integration:requestreply": "cd \"examples/request reply\" && sh ./Test.sh", + "get-version": "echo $npm_package_version" + }, + "dependencies": { + "@asyncapi/generator-filters": "^1.0.0", + "@lagoni/asyncapi-quicktype-filter": "^1.2.3", + "cross-env": "^7.0.2", + "filenamify": "^4.1.0", + "is-url": "1.2.4", + "lodash": "^4.17.20", + "quicktype-core": "6.0.66" + }, + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@semantic-release/commit-analyzer": "^8.0.1", + "@semantic-release/github": "^7.0.4", + "@semantic-release/npm": "^7.0.3", + "@semantic-release/release-notes-generator": "^9.0.1", + "conventional-changelog-conventionalcommits": "^4.2.3", + "semantic-release": "^17.0.4" + }, + "release": { + "branches": [ + "master" + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits" + } + ], + "@semantic-release/npm", + "@semantic-release/github" + ] + }, + "generator": { + "supportedProtocols": [ + "nats" + ], + "parameters": { + "generateTestClient": { + "description": "Generate the test client", + "default": "false", + "required": false + }, + "promisifyReplyCallback": { + "description": "Use promises as callbacks for reply operation", + "default": "false", + "required": false + } + }, + "generator": "<2.0.0 >1.0.0", + "filters": [ + "@asyncapi/generator-filters" + ] + } +} diff --git a/partials/channel/ChannelParameterUnwrap.njk b/partials/channel/ChannelParameterUnwrap.njk new file mode 100644 index 000000000..e37b4f3a1 --- /dev/null +++ b/partials/channel/ChannelParameterUnwrap.njk @@ -0,0 +1,46 @@ + +{% macro unwrap(channelName, channelParameters) %} + +{%- if channelParameters | length %} +var unmodifiedChannel = {{channelName | realizeChannelNameWithoutParameters | safe}}; +var channel = msg.subject; + +{%- for parameterName, parameter in channelParameters %} +{%- if prevParameterName | length %} + var {{parameterName | camelCase}}Split = {{prevParameterName}}Split[1].split("{{'{'+ parameterName + '}'}}"); +{%- else %} + var {{parameterName | camelCase}}Split = unmodifiedChannel.split("{{'{'+ parameterName + '}'}}"); +{%- endif %} +{%- set prevParameterName = (parameterName | camelCase) %} +{%- endfor %} + +const splits = [ + {%- set counter = 1 %} + {%- for parameterName, parameter in channelParameters %} + {%- if counter == (channelParameters | length) %} + {{parameterName | camelCase}}Split[0], + {{parameterName | camelCase}}Split[1] + {%- else %} + {{parameterName | camelCase}}Split[0], + {%- endif %} + {%- set counter = counter + 1 %} + {%- endfor %} +]; + + +{%- set counter = 0 %} +{%- set prevParameterName = null %} +{%- for parameterName, parameter in channelParameters %} +{%- if counter == 0 %} +channel = channel.substring(splits[{{counter}}].length); +{%- else %} +channel = channel.substring({{prevParameterName}}End+splits[{{counter}}].length); +{%- endif %} +var {{parameterName | camelCase}}End = channel.indexOf(splits[{{counter+1}}]); +{%- set paramVarToCast = 'channel.substring(0, ' + (parameterName | camelCase) + 'End)' %} +var {{parameterName | camelCase}}Param = {{parameter.schema().type() | castToTsType(paramVarToCast) | safe}}; +{%- set counter = counter + 1 %} +{%- set prevParameterName = (parameterName | camelCase) %} +{%- endfor %} +{%- endif %} +{% endmacro %} diff --git a/partials/channel/OnReceivingData.njk b/partials/channel/OnReceivingData.njk new file mode 100644 index 000000000..584597326 --- /dev/null +++ b/partials/channel/OnReceivingData.njk @@ -0,0 +1,28 @@ + +{% macro OnReceivingData(promisfyErrors, message, defaultContentType) %} +try { + let receivedDataHooks = Hooks.getInstance().getreceivedDataHook(); + var receivedData : any = msg.data; + for(let hook of receivedDataHooks){ + receivedData = hook(receivedData); + } + {%- if message.contentType() | isBinaryPayload(defaultContentType) %} + if(receivedDataHooks.length == 0){ + receivedData = {{message.uid() | pascalCase}}Message.Convert.to{{message.uid() | pascalCase}}(receivedData.toString()); + } + {%- endif %} + {%- if message.contentType() | isStringPayload(defaultContentType) %} + if(receivedDataHooks.length == 0){ + receivedData = {{message.uid() | pascalCase}}Message.Convert.to{{message.uid() | pascalCase}}(receivedData); + } + {%- endif %} +} catch (e) { + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + {%- if promisfyErrors == true %} + reject(error); + {%- else %} + onReplyError(error); + {%- endif %} + return; +} +{% endmacro %} diff --git a/partials/channel/OnSendingData.njk b/partials/channel/OnSendingData.njk new file mode 100644 index 000000000..f6ee74f5b --- /dev/null +++ b/partials/channel/OnSendingData.njk @@ -0,0 +1,28 @@ + +{% macro OnSendingData(promisfyErrors, message, defaultContentType) %} +try{ + let beforeSendingHooks = Hooks.getInstance().getBeforeSendingDataHook(); + var dataToSend : any = message; + for(let hook of beforeSendingHooks){ + dataToSend = hook(dataToSend); + } + {%- if message.contentType() | isBinaryPayload(defaultContentType) %} + if(beforeSendingHooks.length == 0){ + dataToSend = Buffer.from({{message.uid() | pascalCase}}Message.Convert.{{message.uid() | camelCase}}ToJson(dataToSend)); + } + {%- endif %} + {%- if message.contentType() | isStringPayload(defaultContentType) %} + if(beforeSendingHooks.length == 0 ){ + dataToSend = {{message.uid() | pascalCase}}Message.Convert.{{message.uid() | camelCase}}ToJson(dataToSend); + } + {%- endif %} +}catch(e){ + const error = NatsTypescriptTemplateError.errorForCode(ErrorCode.HOOK_ERROR, e); + {%- if promisfyErrors == true %} + reject(error); + {%- else %} + onReplyError(error) + {%- endif %} + return; +} +{% endmacro %} diff --git a/partials/channel/Publish.njk b/partials/channel/Publish.njk new file mode 100644 index 000000000..83bca2ab2 --- /dev/null +++ b/partials/channel/Publish.njk @@ -0,0 +1,25 @@ + +{%- from "./OnSendingData.njk" import OnSendingData %} +{% macro publish(channelName, channelParameters, publishMessage, server, defaultContentType) %} +export function publish( + message: {{publishMessage | getMessageType}}, + nc: Client + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %} + ): Promise { + return new Promise(async (resolve, reject) => { + try{ + {%- if publishMessage.payload() | messageHasNotNullPayload %} + {{OnSendingData(true, publishMessage, defaultContentType)}} + await nc.publish({{channelParameters | realizeChannelName(channelName)}}, dataToSend); + {%- else %} + await nc.publish({{channelParameters | realizeChannelName(channelName)}}, null); + {%- endif %} + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }); +}; +{% endmacro %} diff --git a/partials/channel/Reply.njk b/partials/channel/Reply.njk new file mode 100644 index 000000000..1d95e2f42 --- /dev/null +++ b/partials/channel/Reply.njk @@ -0,0 +1,80 @@ + +{%- from "./OnSendingData.njk" import OnSendingData %} +{%- from "./OnReceivingData.njk" import OnReceivingData %} +{%- from "./ChannelParameterUnwrap.njk" import unwrap %} +{% macro reply(channelName, channelParameters, replyMessage, receiveMessage, server, params, defaultContentType) %} +export function reply( + onRequest: (err?: NatsTypescriptTemplateError, msg?: {{receiveMessage | getMessageType}}{% if channelParameters | length %}, {{channelParameters | realizeParametersForChannel(false)}}{% endif %}) => + {%- if params.promisifyReplyCallback | length %}Promise<{%- endif %}{{replyMessage | getMessageType}}{%-if params.promisifyReplyCallback | length %}>{%- endif %}, + onReplyError: (err: NatsTypescriptTemplateError) => void, + nc: Client + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %}, + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + try { + let subscribeOptions: SubscriptionOptions = {... options}; + {%- if receiveMessage | hasNatsBindings %} + {%- if receiveMessage.bindings().nats().queue() | length %} + //If queue + subscribeOptions.queue = '{{receiveMessage.bindings().nats().queue()}}'; + {%- endif %} + {%- if receiveMessage.bindings().nats().unsubAfter() | length %} + //If unsubafter + subscribeOptions.max = {{receiveMessage.bindings().nats().unsubAfter()}}; + {%- endif %} + {%- endif %} + + let subscription = nc.subscribe({{channelParameters | realizeChannelName(channelName)}}, {%- if params.promisifyReplyCallback | length %}async{%- endif %} (err, msg) => { + if (err) { + onRequest(err); + } else { + {%- if channelParameters | length %} + {{unwrap(channelName, channelParameters)}} + {%- endif %} + + {%- if receiveMessage.payload() | messageHasNotNullPayload %} + {{OnReceivingData(false, receiveMessage, defaultContentType)}} + + let message = {%-if params.promisifyReplyCallback | length %}await{%- endif %} onRequest(undefined, receivedData{% if channelParameters | length %}, + {%- set counter = 1 %} + {%- for parameterName, parameter in channelParameters %} + {{parameterName | camelCase}}Param{%- if counter < (channelParameters | length) %},{%- endif %} + {%- set counter = counter+1 %} + {%- endfor %} + {%- endif %}); + {%- else %} + let message = {%-if params.promisifyReplyCallback | length %}await{%- endif %} onRequest(undefined, null{% if channelParameters | length %}, + {%- set counter = 1 %} + {%- for parameterName, parameter in channelParameters %} + {{parameterName | camelCase}}Param{%- if counter < (channelParameters | length) %},{%- endif %} + {%- set counter = counter+1 %} + {%- endfor %} + {%- endif %}); + {%- endif %} + + if (msg.reply) { + {%- if replyMessage.payload() | messageHasNotNullPayload %} + {{OnSendingData(false, replyMessage, defaultContentType)}} + + await nc.publish(msg.reply, dataToSend); + {%- else %} + await nc.publish(msg.reply, null); + {%- endif %} + } else { + let error = new NatsTypescriptTemplateError('Expected request to need a reply, did not..', '000'); + onReplyError(error) + return; + } + } + }, subscribeOptions); + resolve(subscription); + } catch (e) { + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + +{% endmacro %} diff --git a/partials/channel/Request.njk b/partials/channel/Request.njk new file mode 100644 index 000000000..8da8b0227 --- /dev/null +++ b/partials/channel/Request.njk @@ -0,0 +1,43 @@ + +{%- from "./OnSendingData.njk" import OnSendingData %} +{%- from "./OnReceivingData.njk" import OnReceivingData %} +{% macro request(channelName, channelParameters, requestMessage, receiveMessage, server, defaultContentType) %} +export function request( + message: {{requestMessage | getMessageType}}, + nc: Client + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %} + ): Promise<{{receiveMessage | getMessageType}}> { + return new Promise(async (resolve, reject) => { + var timeout = undefined; + {%- if requestMessage | hasNatsBindings %} + {%- if requestMessage.bindings().nats().requestReply() | length %} + {%- if requestMessage.bindings().nats().requestReply().timeout() | length %} + timeout = '{{requestMessage.bindings().nats().requestReply().timeout()}}'; + {%- endif %} + {%- endif %} + {%- endif %} + let msg; + try { + {%- if requestMessage.payload() | messageHasNotNullPayload %} + {{OnSendingData(true, requestMessage, defaultContentType)}} + msg = await nc.request({{channelParameters | realizeChannelName(channelName)}}, timeout, dataToSend) + {%- else %} + msg = await nc.request({{channelParameters | realizeChannelName(channelName)}}, timeout, null) + {%- endif %} + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + return; + } + + {%- if receiveMessage.payload() | messageHasNotNullPayload %} + {{OnReceivingData(true, receiveMessage, defaultContentType)}} + resolve(receivedData); + {%- else %} + resolve(null); + {%- endif %} + }) +} + +{% endmacro %} diff --git a/partials/channel/Subscribe.njk b/partials/channel/Subscribe.njk new file mode 100644 index 000000000..8ec52004a --- /dev/null +++ b/partials/channel/Subscribe.njk @@ -0,0 +1,61 @@ + +{%- from "./OnReceivingData.njk" import OnReceivingData %} +{%- from "./ChannelParameterUnwrap.njk" import unwrap %} +{% macro subscribe(channelName, channelParameters, subscribtionMessage, server, defaultContentType) %} +export function subscribe( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: {{subscribtionMessage | getMessageType}}{% if channelParameters | length %}, {{channelParameters | realizeParametersForChannel(false)}}{% endif %}) => void, + nc: Client + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %}, + options?: SubscriptionOptions + ): Promise { + return new Promise(async (resolve, reject) => { + let subscribeOptions: SubscriptionOptions = {... options}; + {%- if subscribtionMessage | hasNatsBindings %} + {%- if subscribtionMessage.bindings().nats().queue() | length %} + //If queue + subscribeOptions.queue = '{{subscribtionMessage.bindings().nats().queue()}}'; + {%- endif %} + {%- if subscribtionMessage.bindings().nats().unsubAfter() | length %} + //If unsubafter + subscribeOptions.max = {{subscribtionMessage.bindings().nats().unsubAfter()}}; + {%- endif %} + {%- endif %} + + try{ + let subscription = nc.subscribe({{channelParameters | realizeChannelName(channelName)}}, (err, msg) => { + if(err){ + onDataCallback(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, err)); + }else{ + {%- if channelParameters | length %} + {{unwrap(channelName, channelParameters)}} + {%- endif %} + {%- if subscribtionMessage.payload() | messageHasNotNullPayload %} + {{OnReceivingData(true, subscribtionMessage, defaultContentType)}} + onDataCallback(undefined, receivedData{% if channelParameters | length %}, + {%- set counter = 1 %} + {%- for parameterName, parameter in channelParameters %} + {{parameterName | camelCase}}Param{%- if counter < (channelParameters | length) %},{%- endif %} + {%- set counter = counter+1 %} + {%- endfor %} + {%- endif %}); + {%- else %} + onDataCallback(undefined, null{% if channelParameters | length %}, + {%- set counter = 1 %} + {%- for parameterName, parameter in channelParameters %} + {{parameterName | camelCase}}Param{%- if counter < (channelParameters | length) %},{%- endif %} + {%- set counter = counter+1 %} + {%- endfor %} + {%- endif %}); + {%- endif %} + } + }, subscribeOptions); + resolve(subscription); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) +} + +{% endmacro %} diff --git a/partials/index/Publish.njk b/partials/index/Publish.njk new file mode 100644 index 000000000..1b92c81a9 --- /dev/null +++ b/partials/index/Publish.njk @@ -0,0 +1,31 @@ + +{% macro publish(defaultContentType, channelName, message, messageDescription, channelParameters) %} + /** + * {{messageDescription}} + * @param requestMessage The message to publish. + */ + public publishTo{{channelName | pascalCase }}( + requestMessage: {{message | getMessageType}} + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %} + ): Promise { + {%- if message.contentType() | isBinaryPayload(defaultContentType) %} + const nc: Client = this.binaryClient!; + {%- endif %} + {%- if message.contentType() | isStringPayload(defaultContentType) %} + const nc: Client = this.stringClient!; + {%- endif %} + {%- if message.contentType() | isJsonPayload(defaultContentType) %} + const nc: Client = this.jsonClient!; + {%- endif %} + if(nc){ + return {{ channelName | camelCase }}Channel.publish(requestMessage, nc + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } +{% endmacro %} diff --git a/partials/index/Reply.njk b/partials/index/Reply.njk new file mode 100644 index 000000000..1a836d8a0 --- /dev/null +++ b/partials/index/Reply.njk @@ -0,0 +1,44 @@ + +{% macro reply(defaultContentType, channelName, replyMessage, receiveMessage, messageDescription, channelParameters, params) %} + /** + * {{messageDescription}} + * @param onRequest Called when request received. + * @param onReplyError Called when it was not possible to send the reply. + */ + public replyTo{{channelName | pascalCase }}( + onRequest : ( + err?: NatsTypescriptTemplateError, + msg?: {{receiveMessage | getMessageType}} + {%- if channelParameters | length %},{{channelParameters | realizeParametersForChannel(false)}}{% endif %} + ) => {%- if params.promisifyReplyCallback | length %}Promise<{%- endif %}{{replyMessage | getMessageType}}{%- if params.promisifyReplyCallback | length %}>{%- endif %}, + onReplyError : (err: NatsTypescriptTemplateError) => void + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %}, + options?: SubscriptionOptions + ): Promise { + {%- if receiveMessage.contentType() | isBinaryPayload(defaultContentType) %} + const nc: Client = this.binaryClient!; + {%- endif %} + {%- if receiveMessage.contentType() | isStringPayload(defaultContentType) %} + const nc: Client = this.stringClient!; + {%- endif %} + {%- if receiveMessage.contentType() | isJsonPayload(defaultContentType) %} + const nc: Client = this.jsonClient!; + {%- endif %} + + if(nc){ + return {{ channelName | camelCase }}Channel.reply( + onRequest, + onReplyError, + nc + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}, + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } +{% endmacro %} diff --git a/partials/index/Request.njk b/partials/index/Request.njk new file mode 100644 index 000000000..2f262fb12 --- /dev/null +++ b/partials/index/Request.njk @@ -0,0 +1,34 @@ + +{% macro request(defaultContentType, channelName, requestMessage, replyMessage, messageDescription, channelParameters) %} + /** + * {{messageDescription}} + * @param requestMessage The request message to send. + */ + public request{{channelName | pascalCase }}( + requestMessage:{{requestMessage | getMessageType}} + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %} + ): Promise<{{replyMessage | getMessageType}}> { + {%- if requestMessage.contentType() | isBinaryPayload(defaultContentType) %} + const nc: Client = this.binaryClient!; + {%- endif %} + {%- if requestMessage.contentType() | isStringPayload(defaultContentType) %} + const nc: Client = this.stringClient!; + {%- endif %} + {%- if requestMessage.contentType() | isJsonPayload(defaultContentType) %} + const nc: Client = this.jsonClient!; + {%- endif %} + if(nc){ + return {{ channelName | camelCase }}Channel.request( + requestMessage, + nc + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %} + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } +{% endmacro %} diff --git a/partials/index/Standard.njk b/partials/index/Standard.njk new file mode 100644 index 000000000..9da799a8d --- /dev/null +++ b/partials/index/Standard.njk @@ -0,0 +1,183 @@ + +{% macro standard(asyncapi) %} + + private jsonClient?: Client; + private stringClient?: Client; + private binaryClient?: Client; + private options?: NatsConnectionOptions; + + /** + * + * @param options options to use, payload is omitted if sat in the AsyncAPI document. + */ + constructor() { + super(); + } + /** + * Try to connect to the NATS server with the different payloads. + */ + connect(options : NatsConnectionOptions): Promise{ + return new Promise(async (resolve: () => void, reject: (error: any) => void) => { + this.options = options; + try{ + {%- if asyncapi | containsBinaryPayload %} + if(!this.binaryClient || this.binaryClient!.isClosed()){ + this.options.payload = Payload.BINARY; + this.binaryClient = await connect(this.options); + this.chainEvents(this.binaryClient); + } + {%- endif %} + {%- if asyncapi | containsStringPayload %} + if(!this.stringClient || this.stringClient!.isClosed()){ + this.options.payload = Payload.STRING; + this.stringClient = await connect(this.options); + this.chainEvents(this.stringClient); + } + {%- endif %} + {%- if asyncapi | containsJsonPayload %} + if(!this.jsonClient || this.jsonClient!.isClosed()){ + this.options.payload = Payload.JSON; + this.jsonClient = await connect(this.options); + this.chainEvents(this.jsonClient); + } + {%- endif %} + resolve(); + }catch(e){ + reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)); + } + }) + } + + /** + * Returns whether or not any of the clients are closed + */ + isClosed(){ + {%- if asyncapi | containsBinaryPayload %} + if (!this.binaryClient || this.binaryClient!.isClosed()){ + return true; + } + {%- endif %} + {%- if asyncapi | containsStringPayload %} + if (!this.stringClient || this.stringClient!.isClosed()){ + return true; + } + {%- endif %} + {%- if asyncapi | containsJsonPayload %} + if (!this.jsonClient || this.jsonClient!.isClosed()){ + return true; + } + {%- endif %} + return false; + } + + /** + * Disconnect all clients from the server + */ + async disconnect(){ + {%- if asyncapi | containsBinaryPayload %} + if(this.binaryClient && !this.binaryClient!.isClosed()){ + this.binaryClient!.close(); + } + {%- endif %} + {%- if asyncapi | containsStringPayload %} + if(this.stringClient && !this.stringClient!.isClosed()){ + this.stringClient!.close(); + } + {%- endif %} + {%- if asyncapi | containsJsonPayload %} + if(this.jsonClient && !this.jsonClient!.isClosed()){ + this.jsonClient!.close(); + } + {%- endif %} + } + + private chainEvents(ns: Client){ + ns.on('permissionError', (e: NatsError) => { + this.emit(AvailableEvents.permissionError, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('close', (e: NatsError) => { + this.emit(AvailableEvents.close, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('connect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.connect, connection, serverURL, info) + }); + ns.on('connecting', (serverURL: string) => { + this.emit(AvailableEvents.connecting, serverURL) + }); + ns.on('disconnect', (serverURL: string) => { + this.emit(AvailableEvents.disconnect, serverURL) + }); + ns.on('error', (e: NatsError) => { + this.emit(AvailableEvents.error, NatsTypescriptTemplateError.errorForCode(ErrorCode.INTERNAL_NATS_TS_ERROR, e)) + }); + ns.on('pingcount', () => { + this.emit(AvailableEvents.pingcount) + }); + ns.on('pingtimer', () => { + this.emit(AvailableEvents.pingtimer) + }); + ns.on('reconnect', (connection: Client, serverURL: string, info: ServerInfo) => { + this.emit(AvailableEvents.reconnect, connection, serverURL, info) + }); + ns.on('reconnecting', (serverURL: string) => { + this.emit(AvailableEvents.reconnecting, serverURL) + }); + ns.on('serversChanged', (e: ServersChangedEvent) => { + this.emit(AvailableEvents.serversChanged, e) + }); + ns.on('subscribe', (e: SubEvent) => { + this.emit(AvailableEvents.subscribe, e) + }); + ns.on('unsubscribe', (e: SubEvent) => { + this.emit(AvailableEvents.unsubscribe, e) + }); + ns.on('yield', () => { + this.emit(AvailableEvents.yield) + }); + } + + /** + * Try to connect to the NATS server with user credentials + */ + async connectWithUserCreds(userCreds: string, options?: NatsConnectionOptions){ + await this.connect({ + userCreds: userCreds, + ... options + }); + } + /** + * Try to connect to the NATS server with user and password + */ + async connectWithUserPass(user: string, pass: string, options?: NatsConnectionOptions){ + await this.connect({ + user: user, + pass: pass, + ... options + }); + } + + /** + * Try to connect to the NATS server which has no authentication + */ + async connectToHost(host: string, options?: NatsConnectionOptions){ + await this.connect({ + servers: [host], + ... options + }); + } + + /** + * Try to connect to the NATS server with nkey authentication + */ + async connectWithNkey(publicNkey: string, seed: string, options?: NatsConnectionOptions){ + await this.connect({ + nkey: publicNkey, + nonceSigner: (nonce: string): Buffer => { + const sk = fromSeed(Buffer.from(seed)); + return sk.sign(Buffer.from(nonce)); + }, + ... options + }); + } + +{% endmacro %} \ No newline at end of file diff --git a/partials/index/Subscribe.njk b/partials/index/Subscribe.njk new file mode 100644 index 000000000..c14fc3890 --- /dev/null +++ b/partials/index/Subscribe.njk @@ -0,0 +1,35 @@ + +{% macro subscribe(defaultContentType, channelName, message, messageDescription, channelParameters) %} + /** + * {{messageDescription}} + * @param onDataCallback Called when message received. + */ + public subscribeTo{{channelName | pascalCase }}( + onDataCallback : (err?: NatsTypescriptTemplateError, msg?: {{message | getMessageType}}{% if channelParameters | length %}, {{channelParameters | realizeParametersForChannel(false)}}{% endif %}) => void + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannel}} + {% endif %}, + options?: SubscriptionOptions + ): Promise { + {%- if message.contentType() | isBinaryPayload(defaultContentType) %} + const nc: Client = this.binaryClient!; + {%- endif %} + {%- if message.contentType() | isStringPayload(defaultContentType) %} + const nc: Client = this.stringClient!; + {%- endif %} + {%- if message.contentType() | isJsonPayload(defaultContentType) %} + const nc: Client = this.jsonClient!; + {%- endif %} + if(nc){ + return {{ channelName | camelCase }}Channel.subscribe( + onDataCallback, nc + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}, + options + ); + }else{ + return Promise.reject(NatsTypescriptTemplateError.errorForCode(ErrorCode.NOT_CONNECTED)); + } + } +{% endmacro %} diff --git a/partials/tests/integration/Publish.njk b/partials/tests/integration/Publish.njk new file mode 100644 index 000000000..a4f2f8171 --- /dev/null +++ b/partials/tests/integration/Publish.njk @@ -0,0 +1,44 @@ + +{% macro publish(defaultContentType, channelName, message, messageDescription, channelParameters) %} + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: TestClient.{{message | getMessageType}} | undefined = undefined; +{%- for paramName, param in channelParameters %} +var recieved{{paramName | pascalCase }} : {{param.schema().type() | toTsType}} | undefined = undefined +{% endfor %} + +var publishMessage: TestClient.{{message | getMessageType}} = {{message.payload().json() | generateExample | safe}}; +{%- for paramName, param in channelParameters %} +var {{paramName | pascalCase }}ToSend: {{param.schema().type() | toTsType}} = {{param.schema().json() | generateExample | safe}} +{% endfor %} + +const tryAndWaitForResponse = new Promise(resolve => { + setTimeout(resolve, 100); +}); + + +const replySubscription = await testClient.subscribeTo{{channelName | pascalCase}}((err, msg + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}) => { + receivedError = err; + receivedMsg = msg; + {%- for paramName, param in channelParameters %} + recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }} = {{paramName}} + {% endfor %} + } + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %} +); +await client.publishTo{{channelName | pascalCase}}(publishMessage + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %}); +await tryAndWaitForResponse; +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(publishMessage); +{%- for paramName, param in channelParameters %} +expect(recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }}).to.be.equal({{paramName | pascalCase }}ToSend); +{% endfor %} +{% endmacro %} diff --git a/partials/tests/integration/Reply.njk b/partials/tests/integration/Reply.njk new file mode 100644 index 000000000..b9f39d3ea --- /dev/null +++ b/partials/tests/integration/Reply.njk @@ -0,0 +1,42 @@ + +{% macro reply(defaultContentType, channelName, replyMessage, receiveMessage, messageDescription, channelParameters, params) %} +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: TestClient.{{receiveMessage | getMessageType}} | undefined = undefined; +{%- for paramName, param in channelParameters %} +var recieved{{paramName | pascalCase }} : {{param.schema().type() | toTsType}} | undefined = undefined +{% endfor %} + +var replyMessage: Client.{{replyMessage | getMessageType}} = {{replyMessage.payload().json() | generateExample | safe}}; +var receiveMessage: TestClient.{{receiveMessage | getMessageType}} = {{receiveMessage.payload().json() | generateExample | safe}}; +{%- for paramName, param in channelParameters %} +var {{paramName | pascalCase }}ToSend: {{param.schema().type() | toTsType}} = {{param.schema().json() | generateExample | safe}} +{% endfor %} + +const replySubscription = await client.replyTo{{channelName | pascalCase}}((err, msg + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}) => { + return new Promise((resolve, reject) => { + receivedError = err; + receivedMsg = msg; + {%- for paramName, param in channelParameters %} + recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }} = {{paramName}} + {% endfor %} + resolve(replyMessage); + })}, + (err) => {console.log(err)} + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %} +); +var reply = await testClient.request{{channelName | pascalCase}}(receiveMessage + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %}); +expect(reply).to.be.deep.equal(replyMessage) +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(receiveMessage); +{%- for paramName, param in channelParameters %} +expect(recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }}).to.be.equal({{paramName | pascalCase }}ToSend); +{% endfor %} +{% endmacro %} diff --git a/partials/tests/integration/Request.njk b/partials/tests/integration/Request.njk new file mode 100644 index 000000000..27e40e2ad --- /dev/null +++ b/partials/tests/integration/Request.njk @@ -0,0 +1,43 @@ + +{% macro request(defaultContentType, channelName, requestMessage, replyMessage, messageDescription, channelParameters) %} +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: Client.{{requestMessage | getMessageType}} | undefined = undefined; +{%- for paramName, param in channelParameters %} +var recieved{{paramName | pascalCase }} : {{param.schema().type() | toTsType}} | undefined = undefined +{% endfor %} + + +var replyMessage: TestClient.{{replyMessage | getMessageType}} = {{replyMessage.payload().json() | generateExample | safe}}; +var requestMessage: Client.{{requestMessage | getMessageType}} = {{requestMessage.payload().json() | generateExample | safe}}; +{%- for paramName, param in channelParameters %} +var {{paramName | pascalCase }}ToSend: {{param.schema().type() | toTsType}} = {{param.schema().json() | generateExample | safe}} +{% endfor %} + +const replySubscription = await testClient.replyTo{{channelName | pascalCase}}((err, msg + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}) => { + return new Promise((resolve, reject) => { + receivedError = err; + receivedMsg = msg; + {%- for paramName, param in channelParameters %} + recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }} = {{paramName}} + {% endfor %} + resolve(replyMessage); + })}, + (err) => {console.log(err)} + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %} +); +var reply = await client.request{{channelName | pascalCase}}(requestMessage + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %}); +expect(reply).to.be.deep.equal(replyMessage) +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(requestMessage); +{%- for paramName, param in channelParameters %} +expect(recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }}).to.be.equal({{paramName | pascalCase }}ToSend); +{% endfor %} +{% endmacro %} diff --git a/partials/tests/integration/Subscribe.njk b/partials/tests/integration/Subscribe.njk new file mode 100644 index 000000000..c3b72e5e0 --- /dev/null +++ b/partials/tests/integration/Subscribe.njk @@ -0,0 +1,43 @@ + +{% macro subscribe(defaultContentType, channelName, message, messageDescription, channelParameters) %} + +var receivedError: NatsTypescriptTemplateError | undefined = undefined; +var receivedMsg: Client.{{message | getMessageType}} | undefined = undefined; +{%- for paramName, param in channelParameters %} +var recieved{{paramName | pascalCase }} : {{param.schema().type() | toTsType}} | undefined = undefined +{% endfor %} + +var publishMessage: Client.{{message | getMessageType}} = {{message.payload().json() | generateExample | safe}}; +{%- for paramName, param in channelParameters %} +var {{paramName | pascalCase }}ToSend: {{param.schema().type() | toTsType}} = {{param.schema().json() | generateExample | safe}} +{% endfor %} + +const tryAndWaitForResponse = new Promise(resolve => { + setTimeout(resolve, 100); +}); + +const replySubscription = await client.subscribeTo{{channelName | pascalCase}}((err, msg + {% if channelParameters | length %} + ,{{channelParameters | realizeParametersForChannelWithoutType}} + {% endif %}) => { + receivedError = err; + receivedMsg = msg; + {%- for paramName, param in channelParameters %} + recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }} = {{paramName}} + {% endfor %} + } + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %} +); +await testClient.publishTo{{channelName | pascalCase}}(publishMessage + {%- for paramName, param in channelParameters %} + , {{paramName | pascalCase }}ToSend + {% endfor %}); +await tryAndWaitForResponse; +expect(receivedError).to.be.undefined; +expect(receivedMsg).to.be.deep.equal(publishMessage); +{%- for paramName, param in channelParameters %} +expect(recieved{{paramName | realizeParameterForChannelWithoutType | pascalCase }}).to.be.equal({{paramName | pascalCase }}ToSend); +{% endfor %} +{% endmacro %} diff --git a/template/README.md.njk b/template/README.md.njk new file mode 100644 index 000000000..c17b3c819 --- /dev/null +++ b/template/README.md.njk @@ -0,0 +1,7 @@ +# {{ asyncapi.info().title() }} + +{{ asyncapi.info().description() | safe }} + + +Available nats encodings: +https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings diff --git a/template/package.json.njk b/template/package.json.njk new file mode 100644 index 000000000..651ebf1b8 --- /dev/null +++ b/template/package.json.njk @@ -0,0 +1,40 @@ +{ +{%- set name = "NatsTSclient" %} +{%- set version = "1.0.0" %} +{%- set description = "" %} + {%- if asyncapi.info() | length %} + {%- if asyncapi.info().title() | length %} + {% set name = asyncapi.info().title() | kebabCase %} + {%- endif %} + {%- if asyncapi.info().description() | length %} + {% set description = asyncapi.info().description() | oneLine %} + {%- endif %} + {%- if asyncapi.info().version() | length %} + {% set username = asyncapi.info().version() %} + {%- endif %} + {%- endif %} + "name": "{{name}}", + "description": "{{description}}", + "version": "{{version}}", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "watch": "tsc --watch", + "build": "tsc", + "test:integration": "./node_modules/.bin/mocha -r ts-node/register src/tests/**/*.spec.ts" + }, + "dependencies": { + "@types/klaw-sync": "^6.0.0", + "@types/node": "13.9.5", + "ts-nats": "1.2.4", + "typescript": "3.4.3", + "ts-nkeys":"1.0.16" + }, + "devDependencies": { + "ts-node": "^8.10.2", + "@types/mocha": "^8.0.4", + "@types/chai": "^4.2.14", + "chai": "^4.2.0", + "mocha": "^8.2.1" + } +} diff --git a/template/src/NatsTypescriptTemplateError.ts b/template/src/NatsTypescriptTemplateError.ts new file mode 100644 index 000000000..07ad37c3e --- /dev/null +++ b/template/src/NatsTypescriptTemplateError.ts @@ -0,0 +1,70 @@ + +import * as util from 'util'; + +export enum ErrorCode { + NOT_CONNECTED = 'NOT_CONNECTED', + INTERNAL_NATS_TS_ERROR = 'INTERNAL_NATS_TS_ERROR', + HOOK_ERROR = 'HOOK_ERROR' +} + +/** @internal **/ +export class Messages { + static messages = new Messages(); + messages: { [key: string]: string } = {}; + + private constructor() { + this.messages[ErrorCode.NOT_CONNECTED] = 'The client is not connected'; + this.messages[ErrorCode.INTERNAL_NATS_TS_ERROR] = 'An error occured while trying to use the Nats Typescript library'; + this.messages[ErrorCode.HOOK_ERROR] = 'An error occured while trying to call one of the hooks.'; + } + + static getMessage(s: string): string { + return Messages.messages.getMessage(s); + } + + getMessage(s: string): string { + let v = this.messages[s]; + if (!v) { + v = s; + } + return v; + } +} +export class NatsTypescriptTemplateError implements Error { + + name: string; + message: string; + code: string; + chainedError?: Error; + + /** + * @param {String} message + * @param {String} code + * @param {Error} [chainedError] + * @constructor + * + * @api private + * @internal + */ + constructor(message: string, code: string, chainedError?: Error) { + Error.captureStackTrace(this, this.constructor); + this.name = 'NatsTypescriptTemplateError'; + this.message = message; + this.code = code; + this.chainedError = chainedError; + + util.inherits(NatsTypescriptTemplateError, Error); + } + + /** + * @param code + * @param chainedError + * @api private + * @internal + */ + static errorForCode(code: string, chainedError?: Error): NatsTypescriptTemplateError { + let m = Messages.getMessage(code); + return new NatsTypescriptTemplateError(m, code, chainedError); + } +} + diff --git a/template/src/channels/$$channel$$.ts.njk b/template/src/channels/$$channel$$.ts.njk new file mode 100644 index 000000000..741caf63a --- /dev/null +++ b/template/src/channels/$$channel$$.ts.njk @@ -0,0 +1,35 @@ + +{%- from "../../../partials/channel/Publish.njk" import publish %} +{%- from "../../../partials/channel/Reply.njk" import reply %} +{%- from "../../../partials/channel/Request.njk" import request %} +{%- from "../../../partials/channel/Subscribe.njk" import subscribe %} +{%- if channel.hasPublish() %} +{%- if channel.publish().message(0).payload() | messageHasNotNullPayload %} +import * as {{ channel.publish().message(0).uid() | pascalCase }}Message from '../messages/{{ channel.publish().message(0).uid() | pascalCase}}' +{%- endif %} +{%- endif %} +{%- if channel.hasSubscribe() %} +{%- if channel.subscribe().message(0).payload() | messageHasNotNullPayload %} +import * as {{ channel.subscribe().message(0).uid() | pascalCase }}Message from '../messages/{{ channel.subscribe().message(0).uid() | pascalCase}}' +{%- endif %} +{%- endif %} +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../NatsTypescriptTemplateError'; +import { Hooks } from '../hooks'; +{%- if channel | isRequestReply %} + {%- if channel | isRequester %} + {{ request(channelName, channel.parameters(), channel.subscribe().message(0), channel.publish().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} + {%- if channel | isReplier %} + {{ reply(channelName, channel.parameters(), channel.subscribe().message(0), channel.publish().message(0), asyncapi.server(params.server), params, asyncapi.defaultContentType()) }} + {%- endif %} +{%- endif %} + +{%- if channel | isPubsub %} + {%- if channel.hasSubscribe() %} + {{ publish(channelName, channel.parameters(), channel.subscribe().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} + {%- if channel.hasPublish() %} + {{ subscribe(channelName, channel.parameters(), channel.publish().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} +{%- endif %} diff --git a/template/src/hooks.ts b/template/src/hooks.ts new file mode 100644 index 000000000..d4528c513 --- /dev/null +++ b/template/src/hooks.ts @@ -0,0 +1,57 @@ +export enum AvailableHooks { + receivedData = 'receivedData', + BeforeSendingData = 'BeforeSendingData' +} +export type receivedDataHook = (receivedData: any) => string; +export type BeforeSendingDataHook = (messageToSend: any) => string; +export class Hooks { + private static instance: Hooks; + + private hooks: { + BeforeSendingData: BeforeSendingDataHook[]; + receivedData: receivedDataHook[]; + }; + private constructor() { + this.hooks = { + BeforeSendingData: [], + receivedData: [] + } + } + public static getInstance(): Hooks { + if (!Hooks.instance) { + Hooks.instance = new Hooks(); + } + return Hooks.instance; + } + + + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerBeforeSendingData(hook: BeforeSendingDataHook) { + this.hooks[AvailableHooks.BeforeSendingData] + ? this.hooks[AvailableHooks.BeforeSendingData].push(hook) + : [hook]; + } + + /** + * Register a hook for BeforeSendingData + * @param hook + */ + public async registerreceivedData(hook: receivedDataHook) { + this.hooks[AvailableHooks.receivedData] + ? this.hooks[AvailableHooks.receivedData].push(hook) + : [hook]; + } + + + public getreceivedDataHook(): receivedDataHook[] { + return this.hooks[AvailableHooks.receivedData]; + } + + public getBeforeSendingDataHook(): BeforeSendingDataHook[] { + return this.hooks[AvailableHooks.BeforeSendingData]; + } +} \ No newline at end of file diff --git a/template/src/index.ts.njk b/template/src/index.ts.njk new file mode 100644 index 000000000..187337f13 --- /dev/null +++ b/template/src/index.ts.njk @@ -0,0 +1,98 @@ + +{%- from "../../partials/index/Publish.njk" import publish %} +{%- from "../../partials/index/Reply.njk" import reply %} +{%- from "../../partials/index/Request.njk" import request %} +{%- from "../../partials/index/Subscribe.njk" import subscribe %} +{%- from "../../partials/index/Standard.njk" import standard %} + + + +import {fromSeed} from 'ts-nkeys'; +import {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} from './hooks'; +export {AvailableHooks, receivedDataHook, BeforeSendingDataHook, Hooks} +import * as TestClient from './tests/testclient/'; +export {% raw %}{{% endraw %} TestClient {% raw %}}{% endraw %}; +import {ErrorCode, NatsTypescriptTemplateError} from './NatsTypescriptTemplateError'; +export {ErrorCode, NatsTypescriptTemplateError} +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; + +export {Client, ServerInfo, ServersChangedEvent, SubEvent} +{%- for channelName, message in asyncapi.channels() %} +import * as {{ channelName | camelCase }}Channel from "./channels/{{ channelName | pascalCase | firstUpperCase }}"; +export {% raw %}{{% endraw %}{{ channelName | camelCase }}Channel}; +{%- endfor %} + +{%- for messageName, message in asyncapi.allMessages() %} +{%- if message.payload() | messageHasNotNullPayload %} +import * as {{ messageName | pascalCase }}Message from "./messages/{{ messageName | pascalCase }}"; +export {% raw %}{{% endraw %}{{ messageName | pascalCase }}Message}; +{%- endif %} +{%- endfor %} + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiClient extends events.EventEmitter{ + {{standard(asyncapi)}} + {%- for channelName, channel in asyncapi.channels() %} + {%- if channel | isRequestReply %} + {%- if channel | isRequester %} + {{request(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.publish().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- if channel | isReplier %} + {{reply(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.publish().message(0), channel.description(), channel.parameters(), params)}} + {%- endif %} + {%- endif %} + + {%- if channel | isPubsub %} + {%- if channel.hasSubscribe() %} + {{publish(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- if channel.hasPublish() %} + {{subscribe(asyncapi.defaultContentType(), channelName, channel.publish().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- endif %} + {%- endfor %} +} diff --git a/template/src/tests/$$channel$$.spec.ts.njk b/template/src/tests/$$channel$$.spec.ts.njk new file mode 100644 index 000000000..24672161d --- /dev/null +++ b/template/src/tests/$$channel$$.spec.ts.njk @@ -0,0 +1,58 @@ + +{%- from "../../../partials/tests/integration/Publish.njk" import publish %} +{%- from "../../../partials/tests/integration/Reply.njk" import reply %} +{%- from "../../../partials/tests/integration/Request.njk" import request %} +{%- from "../../../partials/tests/integration/Subscribe.njk" import subscribe %} + +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import * as Client from '../index' +import * as TestClient from './testclient/index' +import { NatsTypescriptTemplateError } from '../NatsTypescriptTemplateError'; + +describe('{{channelName}} can talk to it self', () => { + var client: Client.NatsAsyncApiClient; + var testClient: TestClient.NatsAsyncApiTestClient; + before(async () => { + client = new Client.NatsAsyncApiClient(); + testClient = new TestClient.NatsAsyncApiTestClient(); + const natsHost = process.env.NATS_HOST || "0.0.0.0" + const natsPort = process.env.NATS_PORT || "4222" + const natsUrl = `${natsHost}:${natsPort}` + await client.connectToHost(natsUrl); + await testClient.connectToHost(natsUrl); + }); + + it('Clients can connect', () => { + expect(client.isClosed()).to.be.false; + expect(testClient.isClosed()).to.be.false; + }); + + it('can send message', async () => { + {%- if channel | isRequestReply %} + {%- if channel | isRequester %} + {{request(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.publish().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- if channel | isReplier %} + {{reply(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.publish().message(0), channel.description(), channel.parameters(), params)}} + {%- endif %} + {%- endif %} + + {%- if channel | isPubsub %} + {%- if channel.hasSubscribe() %} + {{publish(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- if channel.hasPublish() %} + {{subscribe(asyncapi.defaultContentType(), channelName, channel.publish().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- endif %} + }); + + it('Can shutdown', async () => { + await client.disconnect() + await testClient.disconnect() + expect(client.isClosed()).to.be.true; + expect(testClient.isClosed()).to.be.true; + }); + +}); \ No newline at end of file diff --git a/template/src/tests/testclient/index.ts.njk b/template/src/tests/testclient/index.ts.njk new file mode 100644 index 000000000..1dd9f234f --- /dev/null +++ b/template/src/tests/testclient/index.ts.njk @@ -0,0 +1,92 @@ + +{%- from "../../../../partials/index/Publish.njk" import publish %} +{%- from "../../../../partials/index/Reply.njk" import reply %} +{%- from "../../../../partials/index/Request.njk" import request %} +{%- from "../../../../partials/index/Subscribe.njk" import subscribe %} +{%- from "../../../../partials/index/Standard.njk" import standard %} + +import {fromSeed} from 'ts-nkeys'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../NatsTypescriptTemplateError'; +import { + Client, + NatsConnectionOptions, + connect, + Payload, + NatsError, + Subscription, + ServersChangedEvent, + SubEvent, + ServerInfo, + SubscriptionOptions + } from 'ts-nats'; + +{%- for channelName, message in asyncapi.channels() %} +import * as {{ channelName | camelCase }}Channel from "./testchannels/{{ channelName | pascalCase | firstUpperCase }}"; +export {% raw %}{{% endraw %}{{ channelName | camelCase }}Channel}; +{%- endfor %} + +{%- for messageName, message in asyncapi.allMessages() %} +{%- if message.payload() | messageHasNotNullPayload %} +import * as {{ messageName | pascalCase }}Message from "../../messages/{{ messageName | pascalCase }}"; +export {% raw %}{{% endraw %}{{ messageName | pascalCase }}Message}; +{%- endif %} +{%- endfor %} + + + +import * as events from 'events'; +export enum AvailableEvents { + permissionError = 'permissionError', + close = 'close', + connect = 'connect', + connecting = 'connecting', + disconnect = 'disconnect', + error = 'error', + pingcount = 'pingcount', + pingtimer = 'pingtimer', + reconnect = 'reconnect', + reconnecting = 'reconnecting', + serversChanged = 'serversChanged', + subscribe = 'subscribe', + unsubscribe = 'unsubscribe', + yield = 'yield' +} +export declare interface NatsAsyncApiTestClient { + on(event: AvailableEvents.permissionError, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.close, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.connect, listener: (connection: Client, serverURL: string, info: ServerInfo) => void): this; + on(event: AvailableEvents.connecting, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.disconnect, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.error, listener: (error: NatsTypescriptTemplateError) => void): this; + on(event: AvailableEvents.pingcount, listener: () => void): this; + on(event: AvailableEvents.pingtimer, listener: () => void): this; + on(event: AvailableEvents.reconnect, listener: (connection: Client, serverURL: string, info: ServerInfo)=> void): this; + on(event: AvailableEvents.reconnecting, listener: (serverURL: string) => void): this; + on(event: AvailableEvents.serversChanged, listener: (e: ServersChangedEvent) => void): this; + on(event: AvailableEvents.subscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.unsubscribe, listener: (e: SubEvent) => void): this; + on(event: AvailableEvents.yield, listener: () => void): this; +} +export class NatsAsyncApiTestClient extends events.EventEmitter{ + {{standard(asyncapi)}} + {%- for channelName, channel in asyncapi.channels() %} + {%- if channel | isRequestReply %} + {%- if channel | isRequester %} + {{ reply(asyncapi.defaultContentType(), channelName, channel.publish().message(0), channel.subscribe().message(0), channel.description(), channel.parameters(), params)}} + {%- endif %} + {%- if channel | isReplier %} + {{ request(asyncapi.defaultContentType(), channelName, channel.publish().message(0), channel.subscribe().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- endif %} + + {%- if channel | isPubsub %} + {%- if channel.hasSubscribe() %} + {{ subscribe(asyncapi.defaultContentType(), channelName, channel.subscribe().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- if channel.hasPublish() %} + {{ publish(asyncapi.defaultContentType(), channelName, channel.publish().message(0), channel.description(), channel.parameters())}} + {%- endif %} + {%- endif %} + {%- endfor %} + +} \ No newline at end of file diff --git a/template/src/tests/testclient/testchannels/$$channel$$.ts.njk b/template/src/tests/testclient/testchannels/$$channel$$.ts.njk new file mode 100644 index 000000000..ef30c6975 --- /dev/null +++ b/template/src/tests/testclient/testchannels/$$channel$$.ts.njk @@ -0,0 +1,37 @@ + +{%- from "../../../../../partials/channel/Publish.njk" import publish %} +{%- from "../../../../../partials/channel/Reply.njk" import reply %} +{%- from "../../../../../partials/channel/Request.njk" import request %} +{%- from "../../../../../partials/channel/Subscribe.njk" import subscribe %} +{%- if channel.hasPublish() %} +{%- if channel.publish().message(0).payload() | messageHasNotNullPayload %} +import * as {{ channel.publish().message(0).uid() | pascalCase }}Message from '../../../messages/{{ channel.publish().message(0).uid() | pascalCase}}'; +{%- endif %} +{%- endif %} +{%- if channel.hasSubscribe() %} +{%- if channel.subscribe().message(0).payload() | messageHasNotNullPayload %} +import * as {{ channel.subscribe().message(0).uid() | pascalCase }}Message from '../../../messages/{{ channel.subscribe().message(0).uid() | pascalCase}}'; +{%- endif %} +{%- endif %} +import { Client, NatsError, Subscription, SubscriptionOptions, Payload } from 'ts-nats'; +import {ErrorCode, NatsTypescriptTemplateError} from '../../../NatsTypescriptTemplateError'; +import { Hooks } from '../../../hooks'; + + +{%- if channel | isRequestReply %} + {%- if channel | isRequester %} + {{ reply(channelName, channel.parameters(), channel.publish().message(0), channel.subscribe().message(0), asyncapi.server(params.server), params, asyncapi.defaultContentType()) }} + {%- endif %} + {%- if channel | isReplier %} + {{ request(channelName, channel.parameters(), channel.publish().message(0), channel.subscribe().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} +{%- endif %} + +{%- if channel | isPubsub %} + {%- if channel.hasSubscribe() %} + {{ subscribe(channelName, channel.parameters(), channel.subscribe().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} + {%- if channel.hasPublish() %} + {{ publish(channelName, channel.parameters(), channel.publish().message(0), asyncapi.server(params.server), asyncapi.defaultContentType()) }} + {%- endif %} +{%- endif %} diff --git a/template/tsconfig.json b/template/tsconfig.json new file mode 100644 index 000000000..75097457a --- /dev/null +++ b/template/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "declaration": true, + "strict": true, + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "outDir": "dist/", + "baseUrl": "./src" + }, + "include": ["src"], + "exclude": ["node_modules", "**/*.spec.ts"] +}