diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..4969474 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [julusian] diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml new file mode 100644 index 0000000..7fa41dd --- /dev/null +++ b/.github/workflows/node.yaml @@ -0,0 +1,148 @@ +name: Prebuild + +on: + push: + # tags: + # - v* + +env: + NAPI_VERSION: 7 + BINDING_NAME: midi + +jobs: + build-and-test: + name: Build ${{ matrix.arch }} on ${{ matrix.os }} ${{ matrix.libc }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + # windows + - os: windows-2019 + arch: x64 + is-native: true + - os: windows-2019 + arch: ia32 + is-native: false + # macos + - os: macos-11 + arch: arm64 + is-native: false + - os: macos-10.15 + arch: x64 + is-native: true + # linux + - os: ubuntu-18.04 + arch: x64 + is-native: true + # linux-libc + - os: ubuntu-latest + arch: arm64 + is-native: false + docker-arch: linux/arm64 + docker-image: node:14-buster + - os: ubuntu-latest + arch: arm + is-native: false + docker-arch: linux/arm/v7 + docker-image: node:14-buster + # linux-musl + - os: ubuntu-latest + arch: x64 + is-native: false + docker-arch: linux/amd64 + docker-image: node:14-alpine + libc: musl + + steps: + - uses: actions/checkout@v2 + - name: Checkout submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libasound2-dev + + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + + - name: rebuild + if: ${{ !matrix.docker-arch }} + shell: bash + run: | + yarn + + # if [ -n "${{ matrix.is-native }}" ]; then + # yarn test + # fi + + yarn rebuild --arch=${{ matrix.arch }} + yarn pkg-prebuilds-copy --source build/Release/$BINDING_NAME.node --name=$BINDING_NAME --strip --napi_version=$NAPI_VERSION --arch=${{ matrix.arch }} + env: + CI: true + npm_config_build_from_source: true + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + if: matrix.docker-arch + - name: rebuild (in docker) + uses: addnab/docker-run-action@v3 + if: matrix.docker-arch + with: + image: ${{ matrix.docker-image }} + # shell: bash + options: --platform=${{ matrix.docker-arch }} -v ${{ github.workspace }}:/work -e CI=1 -e npm_config_build_from_source=1 -e NAPI_VERSION -e BINDING_NAME + run: | + if command -v apt-get &> /dev/null + then + apt-get update + apt-get install -y libasound2-dev + elif command -v apk &> /dev/null + then + apk update + apk add python3 make g++ gcc alsa-lib-dev + fi + + cd /work + + yarn + # yarn test + + yarn pkg-prebuilds-copy --source build/Release/$BINDING_NAME.node --name=$BINDING_NAME --strip --napi_version=$NAPI_VERSION --arch=${{ matrix.arch }} --libc=${{ matrix.libc }} + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.libc }}-prebuilds + path: prebuilds + retention-days: 1 + + bundle: + name: Bundle prebuilds + needs: build-and-test + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + path: tmp + + - name: Display structure of downloaded files + run: | + mkdir prebuilds + mv tmp/*/* prebuilds/ + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: all-prebuilds + path: prebuilds + retention-days: 7 diff --git a/.gitignore b/.gitignore index cc28915..51f8b23 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ node_modules/ .vscode/ .vs/ +prebuilds/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 17bf86c..b9060d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "vendor/rtmidi"] path = vendor/rtmidi - url = https://github.com/justinlatimer/rtmidi.git + url = https://github.com/thestk/rtmidi.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e6e47eb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: node_js -node_js: - - 10 - - 12 - - 14 - - 15 -os: - - linux - - osx - - windows -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libasound2-dev -notifications: - email: false -script: 'true' diff --git a/LICENSE b/LICENSE index a2adfa2..e2c5efc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (C) 2011-2021 by Justin Latimer. +Copyright (C) 2022 by Julian Waller. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 4993d3c..b1700cd 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,25 @@ ♪ ♫ ♩ ♬ -# node-midi +# @julusian/midi A node.js wrapper for the RtMidi C++ library that provides realtime MIDI I/O. RtMidi supports Linux (ALSA & Jack), Macintosh OS X (CoreMidi), and Windows (Multimedia). -[![Build Status](https://travis-ci.com/justinlatimer/node-midi.svg?branch=master)](https://travis-ci.com/github/justinlatimer/node-midi) - -## Prerequisites - -### OSX - -* Some version of Xcode (or Command Line Tools) -* Python (for node-gyp) - -### Windows - -* Microsoft Visual C++ (the Express edition works fine) -* Python (for node-gyp) - -### Linux - -* A C++ compiler -* You must have installed and configured ALSA. Without it this module will **NOT** build. -* Install the libasound2-dev package. -* Python (for node-gyp) +This is an api compatible alternative to [midi](https://www.npmjs.com/package/midi), updated to work with modern nodejs. ## Installation -Installation uses node-gyp and requires Python 2.7.2 or higher. +Prebuilds are available for all common platforms. If you are using an uncommon platform you may need a C++ compiler and Python 3. From npm: ```bash -$ npm install midi +$ npm install @julusian/midi ``` From source: ```bash -$ git clone https://github.com/justinlatimer/node-midi.git +$ git clone https://github.com/julusian/node-midi.git $ cd node-midi/ $ npm install ``` @@ -54,7 +35,7 @@ For list of midi status codes, see http://www.midi.org/techspecs/midimessages.ph ### Input ```js -const midi = require('midi'); +const midi = require('@julusian/midi'); // Set up a new input. const input = new midi.Input(); @@ -97,7 +78,7 @@ setTimeout(function() { ### Output ```js -const midi = require('midi'); +const midi = require('@julusian/midi'); // Set up a new output. const output = new midi.Output(); @@ -126,7 +107,7 @@ connect to. This can be done simply by calling openVirtualPort(portName) instead of openPort(portNumber). ```js -const midi = require('midi'); +const midi = require('@julusian/midi'); // Set up a new input. const input = new midi.Input(); @@ -191,12 +172,13 @@ require('fs').createReadStream('something.bin').pipe(stream2); ## Maintainers - * Justin Latimer - [@justinlatimer](https://github.com/justinlatimer) - * Elijah Insua - [@tmpvar](https://github.com/tmpvar) - * Andrew Morton - [@drewish](https://github.com/drewish) + * Julian Waller - [@julusian](https://github.com/julusian) ## Contributors + * Justin Latimer - [@justinlatimer](https://github.com/justinlatimer) + * Elijah Insua - [@tmpvar](https://github.com/tmpvar) + * Andrew Morton - [@drewish](https://github.com/drewish) * Luc Deschenaux - [@luxigo](https://github.com/luxigo) * Michael Alyn Miller - [@malyn](https://github.com/malyn) * Hugo Hromic - [@hhromic](https://github.com/hhromic) @@ -204,6 +186,7 @@ require('fs').createReadStream('something.bin').pipe(stream2); ## License Copyright (C) 2011-2021 by Justin Latimer. +Copyright (C) 2022 by Julian Waller. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/binding-options.js b/binding-options.js new file mode 100644 index 0000000..7e05134 --- /dev/null +++ b/binding-options.js @@ -0,0 +1,4 @@ +module.exports = { + name: 'midi', + napi_versions: [7], +} diff --git a/binding.gyp b/binding.gyp index fecb88a..cb1a5f8 100644 --- a/binding.gyp +++ b/binding.gyp @@ -2,8 +2,17 @@ 'targets': [ { 'target_name': 'midi', + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', + 'CLANG_CXX_LIBRARY': 'libc++', + 'MACOSX_DEPLOYMENT_TARGET': '10.7', + }, + 'msvs_settings': { + 'VCCLCompilerTool': { 'ExceptionHandling': 1 }, + }, 'include_dirs': [ - " + +import * as Stream from 'stream'; +import * as EventEmitter from 'events'; + +/** + * An array of numbers corresponding to the MIDI bytes: [status, data1, data2]. + * See https://www.cs.cf.ac.uk/Dave/Multimedia/node158.html for more info. + */ +export type MidiMessage = [number, number, number]; +export type MidiCallback = (deltaTime: number, message: MidiMessage) => void; + +export class Input extends EventEmitter { + /** Close the midi port */ + closePort(): void; + /** Count the available input ports */ + getPortCount(): number; + /** Get the name of a specified input port */ + getPortName(port: number): string; + isPortOpen(): boolean + /** + * Sysex, timing, and active sensing messages are ignored by default. To + * enable these message types, pass false for the appropriate type in the + * function below. Order: (Sysex, Timing, Active Sensing) For example if + * you want to receive only MIDI Clock beats you should use + * input.ignoreTypes(true, false, true) + */ + ignoreTypes(sysex: boolean, timing: boolean, activeSensing: boolean): void; + /** Open the specified input port */ + openPort(port: number): void; + /** + * Instead of opening a connection to an existing MIDI device, on Mac OS X + * and Linux with ALSA you can create a virtual device that other software + * may connect to. This can be done simply by calling + * openVirtualPort(portName) instead of openPort(portNumber). + */ + openVirtualPort(port: string): void; + + on(event: 'message', callback: MidiCallback): this; +} + +export class Output { + /** Close the midi port */ + closePort(): void; + /** Count the available output ports */ + getPortCount(): number; + /** Get the name of a specified output port */ + getPortName(port: number): string; + isPortOpen(): boolean + /** Open the specified output port */ + openPort(port: number): void; + /** + * Instead of opening a connection to an existing MIDI device, on Mac OS X + * and Linux with ALSA you can create a virtual device that other software + * may connect to. This can be done simply by calling + * openVirtualPort(portName) instead of openPort(portNumber). + */ + openVirtualPort(port: string): void; + /** Send a MIDI message */ + send(message: MidiMessage): void; + /** Send a MIDI message */ + sendMessage(message: MidiMessage): void; +} + +/** @deprecated */ +export const input: typeof Input; +/** @deprecated */ +export const output: typeof Output; + +export function createReadStream(input?: Input): Stream; + +export function createWriteStream(output?: Output): Stream; \ No newline at end of file diff --git a/midi.js b/midi.js index e34df71..e0a32fd 100644 --- a/midi.js +++ b/midi.js @@ -1,18 +1,85 @@ -var midi = require('bindings')('midi'); -var Stream = require('stream'); +const midi = require("pkg-prebuilds/bindings")( + __dirname, + require("./binding-options") +); +const Stream = require('stream'); // MIDI input inherits from EventEmitter -var EventEmitter = require('events').EventEmitter; -midi.Input.prototype.__proto__ = EventEmitter.prototype; +const { EventEmitter } = require('events'); + +class Input extends EventEmitter { + constructor() { + super() + + this.input = new midi.Input((deltaTime, message) => { + this.emit('message', deltaTime, Array.from(message.values())) + }) + } + + closePort() { + return this.input.closePort() + } + getPortCount() { + return this.input.getPortCount() + } + getPortName(port) { + return this.input.getPortName(port) + } + isPortOpen() { + return this.input.isPortOpen() + } + ignoreTypes(sysex, timing, activeSensing) { + return this.input.ignoreTypes(sysex, timing, activeSensing) + } + openPort(port) { + return this.input.openPort(port) + } + openVirtualPort(port) { + return this.input.openVirtualPort(port) + } +} + +class Output { + constructor() { + this.output = new midi.Output() + } + + closePort() { + return this.output.closePort() + } + getPortCount() { + return this.output.getPortCount() + } + getPortName(port) { + return this.output.getPortName(port) + } + isPortOpen() { + return this.output.isPortOpen() + } + openPort(port) { + return this.output.openPort(port) + } + openVirtualPort(port) { + return this.output.openVirtualPort(port) + } + send(message) { + return this.sendMessage(message) + } + sendMessage(message) { + if (Array.isArray(message)) { + message = Buffer.from(message) + } + if (!Buffer.isBuffer(message)) { + throw new Error('First argument must be an array or Buffer') + } -// Backwards compatibility. -midi.input = midi.Input; -midi.output = midi.Output; + return this.output.sendMessage(message) + } +} -module.exports = midi; -midi.createReadStream = function(input) { - input = input || new midi.Input(); +function createReadStream(input) { + input = input || new Input(); var stream = new Stream(); stream.readable = true; stream.paused = false; @@ -41,9 +108,8 @@ midi.createReadStream = function(input) { return stream; }; - -midi.createWriteStream = function(output) { - output = output || new midi.Output(); +function createWriteStream(output) { + output = output || new Output(); var stream = new Stream(); stream.writable = true; stream.paused = false; @@ -71,3 +137,15 @@ midi.createWriteStream = function(output) { return stream; }; + +module.exports = { + Input, + Output, + + createReadStream, + createWriteStream, + + // Backwards compatibility. + input: Input, + output: Output, +}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index c240e5a..0000000 --- a/package-lock.json +++ /dev/null @@ -1,840 +0,0 @@ -{ - "name": "midi", - "version": "2.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@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.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "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 - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "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" - } - } - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "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.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } - } - }, - "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 - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "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 - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "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 - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "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.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "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 - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "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.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "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 - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "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": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "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.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "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": "9.0.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.0.3.tgz", - "integrity": "sha512-hnYFrSefHxYS2XFGtN01x8un0EwNu2bzKvhpRFhgoybIvMaOkkL60IVPmkb5h6XDmUl4IMSB+rT5cIO4/4bJgg==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.23", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" - }, - "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "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 - }, - "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.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "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 - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "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.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "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 - }, - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "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": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "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" - } - }, - "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" - } - }, - "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.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "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" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/package.json b/package.json index 747d25a..5886315 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,25 @@ { - "name": "midi", - "version": "2.0.0", + "name": "@julusian/midi", + "version": "3.0.0-2", "scripts": { + "install": "pkg-prebuilds-verify ./binding-options.js || node-gyp rebuild", + "build": "node-gyp build", + "rebuild": "node-gyp clean configure build", "test": "mocha test/unit/*.js && node test/virtual-loopback-test-automated.js" }, "main": "midi.js", + "types": "midi.d.ts", "description": "MIDI hardware IO", "author": { - "name": "Justin Latimer", - "email": "justinlatimer@gmail.com", - "url": "http://www.justinlatimer.com/" + "name": "Julian Waller", + "email": "git@julusian.co.uk" }, "contributors": [ + { + "name": "Justin Latimer", + "email": "justinlatimer@gmail.com", + "url": "http://www.justinlatimer.com/" + }, { "name": "Elijah Insua", "email": "tmpvar@gmail.com" @@ -34,11 +42,16 @@ ], "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14.15" + }, + "binary": { + "napi_versions": [ + 7 + ] }, "dependencies": { - "bindings": "~1.5.0", - "nan": "^2.14.2" + "node-addon-api": "^5.0.0", + "pkg-prebuilds": "^0.1.0" }, "devDependencies": { "mocha": "^9.0.0", @@ -46,13 +59,16 @@ }, "repository": { "type": "git", - "url": "https://github.com/justinlatimer/node-midi.git" + "url": "https://github.com/julusian/node-midi.git" }, "files": [ "midi.js", + "midi.d.ts", "binding.gyp", + "binding-options.js", "src/", - "test/", - "vendor/" + "vendor/rtmidi/RtMidi.cpp", + "vendor/rtmidi/RtMidi.h", + "prebuilds/" ] } diff --git a/src/input.cpp b/src/input.cpp index de9b168..ed671cb 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,244 +1,303 @@ -#include +#include #include -#include #include "RtMidi.h" #include "input.h" -const char* symbol_emit = "emit"; -const char* symbol_message = "message"; +const char *symbol_emit = "emit"; +const char *symbol_message = "message"; -void NodeMidiInput::Init(v8::Local target) +std::unique_ptr NodeMidiInput::Init(const Napi::Env &env, Napi::Object exports) { - Nan::HandleScope scope; + Napi::HandleScope scope(env); - v8::Local t = Nan::New(NodeMidiInput::New); + Napi::Function func = DefineClass(env, "NodeMidiInput", { + InstanceMethod<&NodeMidiInput::GetPortCount>("getPortCount", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiInput::GetPortName>("getPortName", static_cast(napi_writable | napi_configurable)), - s_ct.Reset(t); - t->SetClassName(Nan::New("NodeMidiInput").ToLocalChecked()); - t->InstanceTemplate()->SetInternalFieldCount(1); + InstanceMethod<&NodeMidiInput::OpenPort>("openPort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiInput::OpenVirtualPort>("openVirtualPort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiInput::ClosePort>("closePort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiInput::IsPortOpen>("isPortOpen", static_cast(napi_writable | napi_configurable)), - Nan::SetPrototypeMethod(t, "getPortCount", GetPortCount); - Nan::SetPrototypeMethod(t, "getPortName", GetPortName); + InstanceMethod<&NodeMidiInput::IgnoreTypes>("ignoreTypes", static_cast(napi_writable | napi_configurable)), + }); - Nan::SetPrototypeMethod(t, "openPort", OpenPort); - Nan::SetPrototypeMethod(t, "openVirtualPort", OpenVirtualPort); - Nan::SetPrototypeMethod(t, "closePort", ClosePort); - Nan::SetPrototypeMethod(t, "isPortOpen", IsPortOpen); + // Create a persistent reference to the class constructor + std::unique_ptr constructor = std::make_unique(); + *constructor = Napi::Persistent(func); + exports.Set("Input", func); - Nan::SetPrototypeMethod(t, "ignoreTypes", IgnoreTypes); - - Nan::Set(target, Nan::New("Input").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked()); + return constructor; } -NodeMidiInput::NodeMidiInput() +NodeMidiInput::NodeMidiInput(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { - try { - in = new RtMidiIn(); + if (info.Length() == 0 || !info[0].IsFunction()) + { + Napi::Error::New(info.Env(), "Expected a callback").ThrowAsJavaScriptException(); + return; + } + + try + { + handle.reset(new RtMidiIn()); + + handle->setBufferSize(2048, 4); } - catch(RtMidiError& e) { - in = NULL; + catch (RtMidiError &e) + { + handle.reset(); + Napi::Error::New(info.Env(), "Failed to initialise RtMidi").ThrowAsJavaScriptException(); + return; } - configured = false; - uv_mutex_init(&message_mutex); + + emitMessage = Napi::Persistent(info[0].As()); } NodeMidiInput::~NodeMidiInput() { - if (in) { - cleanUp(); - delete in; - } - uv_mutex_destroy(&message_mutex); + cleanup(); } -void NodeMidiInput::cleanUp() +void NodeMidiInput::setupCallback(const Napi::Env &env) { - if (this->configured) { - this->Unref(); - try { - this->in->cancelCallback(); - this->in->closePort(); - } - catch(RtMidiError& e) { - ; - } - uv_close((uv_handle_t*)&this->message_async, NULL); - this->configured = false; + if (!configured) + { + configured = true; + + handleMessage = TSFN_t::New( + env, + emitMessage.Value(), + "Midi Input", + 0, + 1); + + handle->setCallback(&NodeMidiInput::Callback, this); } } -NAUV_WORK_CB(NodeMidiInput::EmitMessage) +void NodeMidiInput::cleanup() { - Nan::HandleScope scope; - NodeMidiInput *input = static_cast(async->data); - uv_mutex_lock(&input->message_mutex); - v8::Local emitFunction = Nan::Get(input->handle(), Nan::New(symbol_emit).ToLocalChecked()).ToLocalChecked().As(); - while (!input->message_queue.empty()) - { - MidiMessage* message = input->message_queue.front(); - v8::Local info[3]; - info[0] = Nan::New(symbol_message).ToLocalChecked(); - info[1] = Nan::New(message->deltaTime); - int32_t count = (int32_t)message->message.size(); - v8::Local data = Nan::New(count); - for (int32_t i = 0; i < count; ++i) { - Nan::Set(data, Nan::New(i), Nan::New(message->message[i])); - } - info[2] = data; - Nan::Callback callback_emit(emitFunction); - callback_emit.Call(input->handle(), 3, info); - input->message_queue.pop(); - delete message; + handle->closePort(); + + if (configured) + { + configured = false; + + handle->cancelCallback(); + handleMessage.Abort(); + handleMessage.Release(); } - uv_mutex_unlock(&input->message_mutex); } void NodeMidiInput::Callback(double deltaTime, std::vector *message, void *userData) { - NodeMidiInput *input = static_cast(userData); - MidiMessage* data = new MidiMessage(); + NodeMidiInput *input = static_cast(userData); + + MidiMessage *data = new MidiMessage(); data->deltaTime = deltaTime; - data->message = *message; - uv_mutex_lock(&input->message_mutex); - input->message_queue.push(data); - uv_mutex_unlock(&input->message_mutex); - uv_async_send(&input->message_async); + data->messageLength = message->size(); + data->message = new unsigned char[data->messageLength]; + memcpy(data->message, message->data(), data->messageLength * sizeof(unsigned char)); + + // Forward to CallbackJs + input->handleMessage.NonBlockingCall(data); } -NAN_METHOD(NodeMidiInput::New) +void deleteArray(const Napi::Env &env, unsigned char *ptr) { - Nan::HandleScope scope; + delete[] ptr; +} + +void NodeMidiInput::CallbackJs(Napi::Env env, Napi::Function callback, void *context, MidiMessage *data) +{ + if (env != nullptr) + { + Napi::Value deltaTime = Napi::Number::New(env, data->deltaTime); - if (!info.IsConstructCall()) { - return Nan::ThrowTypeError("Use the new operator to create instances of this object."); + Napi::Value message = Napi::Buffer::New(env, data->message, data->messageLength, deleteArray); + // data->message is now owned by the buffer + data->message = nullptr; + + callback.Call({deltaTime, message}); } - NodeMidiInput* input = new NodeMidiInput(); - input->message_async.data = input; - input->Wrap(info.This()); + if (data != nullptr) + { + if (data->message != nullptr) + { + delete[] data->message; + } - info.GetReturnValue().Set(info.This()); + // We're finished with the data. + delete data; + } } -NAN_METHOD(NodeMidiInput::GetPortCount) +Napi::Value NodeMidiInput::GetPortCount(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); - v8::Local result = Nan::New(input->in ? input->in->getPortCount() : 0); - info.GetReturnValue().Set(result); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } + + return Napi::Number::New(env, handle->getPortCount()); } -NAN_METHOD(NodeMidiInput::GetPortName) +Napi::Value NodeMidiInput::GetPortName(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); - if (info.Length() == 0 || !info[0]->IsUint32()) { - return Nan::ThrowTypeError("First argument must be an integer"); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } + + if (info.Length() == 0 || !info[0].IsNumber()) + { + Napi::TypeError::New(env, "First argument must be an integer").ThrowAsJavaScriptException(); + return env.Null(); } - unsigned int portNumber = Nan::To(info[0]).FromJust(); - try { - v8::Local result = Nan::New(input->in ? input->in->getPortName(portNumber).c_str() : "").ToLocalChecked(); - info.GetReturnValue().Set(result); + unsigned int portNumber = info[0].ToNumber(); + try + { + return Napi::String::New(env, handle->getPortName(portNumber)); } - catch(RtMidiError& e) { - info.GetReturnValue().Set(Nan::New("").ToLocalChecked()); + catch (RtMidiError &e) + { + Napi::TypeError::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); + return env.Null(); } } -NAN_METHOD(NodeMidiInput::OpenPort) +Napi::Value NodeMidiInput::OpenPort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!input->in) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - if (info.Length() == 0 || !info[0]->IsUint32()) { - return Nan::ThrowTypeError("First argument must be an integer"); + if (info.Length() == 0 || !info[0].IsNumber()) + { + Napi::TypeError::New(env, "First argument must be an integer").ThrowAsJavaScriptException(); + return env.Null(); } - unsigned int portNumber = Nan::To(info[0]).FromJust(); - if (portNumber >= input->in->getPortCount()) { - return Nan::ThrowRangeError("Invalid MIDI port number"); + + unsigned int portNumber = info[0].ToNumber(); + if (portNumber >= handle->getPortCount()) + { + Napi::RangeError::New(env, "Invalid MIDI port number").ThrowAsJavaScriptException(); + return env.Null(); } - input->Ref(); - uv_async_init(uv_default_loop(), &input->message_async, NodeMidiInput::EmitMessage); - try { - input->in->setCallback(&NodeMidiInput::Callback, Nan::ObjectWrap::Unwrap(info.This())); - input->configured = true; - input->in->openPort(portNumber); + try + { + setupCallback(env); + handle->openPort(portNumber); } - catch(RtMidiError& e) { - ; + catch (RtMidiError &e) + { + Napi::Error::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); } - return; + + return env.Null(); } -NAN_METHOD(NodeMidiInput::OpenVirtualPort) +Napi::Value NodeMidiInput::OpenVirtualPort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!input->in) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - if (info.Length() == 0 || !info[0]->IsString()) { - return Nan::ThrowTypeError("First argument must be a string"); + if (info.Length() == 0 || !info[0].IsString()) + { + Napi::TypeError::New(env, "First argument must be a string").ThrowAsJavaScriptException(); + return env.Null(); } - std::string name(*Nan::Utf8String(info[0])); + std::string name = info[0].ToString(); - input->Ref(); - uv_async_init(uv_default_loop(), &input->message_async, NodeMidiInput::EmitMessage); - try { - input->in->setCallback(&NodeMidiInput::Callback, Nan::ObjectWrap::Unwrap(info.This())); - input->configured = true; - input->in->openVirtualPort(name); + try + { + setupCallback(env); + handle->openVirtualPort(name); } - catch(RtMidiError& e) { - ; + catch (RtMidiError &e) + { + Napi::Error::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); } - return; + + return env.Null(); } -NAN_METHOD(NodeMidiInput::ClosePort) +Napi::Value NodeMidiInput::ClosePort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!input->in) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - input->cleanUp(); - - return; + cleanup(); + return env.Null(); } -NAN_METHOD(NodeMidiInput::IsPortOpen) +Napi::Value NodeMidiInput::IsPortOpen(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!input->in) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - v8::Local result = Nan::New(input->in->isPortOpen()); - info.GetReturnValue().Set(result); + return Napi::Boolean::New(env, handle->isPortOpen()); } -NAN_METHOD(NodeMidiInput::IgnoreTypes) +Napi::Value NodeMidiInput::IgnoreTypes(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiInput* input = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!input->in) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - if (info.Length() != 3 || !info[0]->IsBoolean() || !info[1]->IsBoolean() || !info[2]->IsBoolean()) { - return Nan::ThrowTypeError("Arguments must be boolean"); + if (info.Length() != 3 || !info[0].IsBoolean() || !info[1].IsBoolean() || !info[2].IsBoolean()) + { + Napi::TypeError::New(env, "Arguments must be boolean").ThrowAsJavaScriptException(); + return env.Null(); } - bool filter_sysex = Nan::To(info[0]).FromJust(); - bool filter_timing = Nan::To(info[1]).FromJust(); - bool filter_sensing = Nan::To(info[2]).FromJust(); - input->in->ignoreTypes(filter_sysex, filter_timing, filter_sensing); - return; + bool filter_sysex = info[0].ToBoolean(); + bool filter_timing = info[1].ToBoolean(); + bool filter_sensing = info[2].ToBoolean(); + handle->ignoreTypes(filter_sysex, filter_timing, filter_sensing); + + return env.Null(); } diff --git a/src/input.h b/src/input.h index 07d9631..dab1c48 100644 --- a/src/input.h +++ b/src/input.h @@ -1,50 +1,51 @@ #ifndef NODE_MIDI_INPUT_H #define NODE_MIDI_INPUT_H -#include +#include #include -#include #include "RtMidi.h" -class NodeMidiInput : public Nan::ObjectWrap +class NodeMidiInput : public Napi::ObjectWrap { private: - RtMidiIn* in; - bool configured; - -public: - uv_async_t message_async; - uv_mutex_t message_mutex; - struct MidiMessage { double deltaTime; - std::vector message; + unsigned char *message; + size_t messageLength; }; - std::queue message_queue; - static Nan::Persistent s_ct; - static void Init(v8::Local target); + static void CallbackJs(Napi::Env env, Napi::Function callback, void *context, MidiMessage *data); + using TSFN_t = Napi::TypedThreadSafeFunction; + + std::unique_ptr handle; + + TSFN_t handleMessage; + Napi::FunctionReference emitMessage; + bool configured = false; - NodeMidiInput(); + void setupCallback(const Napi::Env &env); + void cleanup(); + +public: + static std::unique_ptr + Init(const Napi::Env &env, Napi::Object target); + + NodeMidiInput(const Napi::CallbackInfo &info); ~NodeMidiInput(); - void cleanUp(); - static NAUV_WORK_CB(EmitMessage); static void Callback(double deltaTime, std::vector *message, void *userData); - static NAN_METHOD(New); - - static NAN_METHOD(GetPortCount); - static NAN_METHOD(GetPortName); + Napi::Value GetPortCount(const Napi::CallbackInfo &info); + Napi::Value GetPortName(const Napi::CallbackInfo &info); - static NAN_METHOD(OpenPort); - static NAN_METHOD(OpenVirtualPort); - static NAN_METHOD(ClosePort); - static NAN_METHOD(IsPortOpen); + Napi::Value OpenPort(const Napi::CallbackInfo &info); + Napi::Value OpenVirtualPort(const Napi::CallbackInfo &info); + Napi::Value ClosePort(const Napi::CallbackInfo &info); + Napi::Value IsPortOpen(const Napi::CallbackInfo &info); - static NAN_METHOD(IgnoreTypes); + Napi::Value IgnoreTypes(const Napi::CallbackInfo &info); }; #endif // NODE_MIDI_INPUT_H diff --git a/src/midi.cpp b/src/midi.cpp index d49fcc3..9ad063f 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -1,14 +1,28 @@ -#include +#include #include "input.h" #include "output.h" -Nan::Persistent NodeMidiInput::s_ct; -Nan::Persistent NodeMidiOutput::s_ct; +struct MidiInstanceData +{ + std::unique_ptr output; + std::unique_ptr input; +}; -NAN_MODULE_INIT(InitAll) { - NodeMidiOutput::Init(target); - NodeMidiInput::Init(target); +Napi::Object InitAll(Napi::Env env, Napi::Object exports) +{ + auto outputRef = NodeMidiOutput::Init(env, exports); + auto inputRef = NodeMidiInput::Init(env, exports); + + // Store the constructor as the add-on instance data. This will allow this + // add-on to support multiple instances of itself running on multiple worker + // threads, as well as multiple instances of itself running in different + // contexts on the same thread. + env.SetInstanceData(new MidiInstanceData{ + std::move(outputRef), + std::move(inputRef)}); + + return exports; } -NODE_MODULE(midi, InitAll) +NODE_API_MODULE(midi, InitAll) diff --git a/src/output.cpp b/src/output.cpp index 9fbca12..79e458b 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,180 +1,218 @@ -#include +#include #include "RtMidi.h" #include "output.h" -void NodeMidiOutput::Init(v8::Local target) +std::unique_ptr NodeMidiOutput::Init(const Napi::Env &env, Napi::Object exports) { - Nan::HandleScope scope; + Napi::HandleScope scope(env); - v8::Local t = Nan::New(NodeMidiOutput::New); + Napi::Function func = DefineClass(env, "NodeMidiOutput", { + InstanceMethod<&NodeMidiOutput::GetPortCount>("getPortCount", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiOutput::GetPortName>("getPortName", static_cast(napi_writable | napi_configurable)), - s_ct.Reset(t); - t->SetClassName(Nan::New("NodeMidiOutput").ToLocalChecked()); - t->InstanceTemplate()->SetInternalFieldCount(1); + InstanceMethod<&NodeMidiOutput::OpenPort>("openPort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiOutput::OpenVirtualPort>("openVirtualPort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiOutput::ClosePort>("closePort", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiOutput::IsPortOpen>("isPortOpen", static_cast(napi_writable | napi_configurable)), - Nan::SetPrototypeMethod(t, "getPortCount", GetPortCount); - Nan::SetPrototypeMethod(t, "getPortName", GetPortName); + InstanceMethod<&NodeMidiOutput::Send>("sendMessage", static_cast(napi_writable | napi_configurable)), + InstanceMethod<&NodeMidiOutput::Send>("send", static_cast(napi_writable | napi_configurable)), + }); - Nan::SetPrototypeMethod(t, "openPort", OpenPort); - Nan::SetPrototypeMethod(t, "openVirtualPort", OpenVirtualPort); - Nan::SetPrototypeMethod(t, "closePort", ClosePort); - Nan::SetPrototypeMethod(t, "isPortOpen", IsPortOpen); + // Create a persistent reference to the class constructor + std::unique_ptr constructor = std::make_unique(); + *constructor = Napi::Persistent(func); + exports.Set("Output", func); - Nan::SetPrototypeMethod(t, "sendMessage", Send); - Nan::SetPrototypeMethod(t, "send", Send); - - Nan::Set(target, Nan::New("Output").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked()); + return constructor; } -NodeMidiOutput::NodeMidiOutput() +NodeMidiOutput::NodeMidiOutput(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { - try { - out = new RtMidiOut(); + try + { + handle.reset(new RtMidiOut()); } - catch(RtMidiError &e) { - out = NULL; + catch (RtMidiError &e) + { + handle.reset(); + Napi::Error::New(info.Env(), "Failed to initialise RtMidi").ThrowAsJavaScriptException(); } } NodeMidiOutput::~NodeMidiOutput() { - if (out) { - delete out; - } + handle->closePort(); } -NAN_METHOD(NodeMidiOutput::New) +Napi::Value NodeMidiOutput::GetPortCount(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!info.IsConstructCall()) { - return Nan::ThrowTypeError("Use the new operator to create instances of this object."); + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); } - NodeMidiOutput* output = new NodeMidiOutput(); - output->Wrap(info.This()); - - info.GetReturnValue().Set(info.This()); + return Napi::Number::New(env, handle->getPortCount()); } -NAN_METHOD(NodeMidiOutput::GetPortCount) +Napi::Value NodeMidiOutput::GetPortName(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); - v8::Local result = Nan::New(output-> out ? output->out->getPortCount() : 0); - info.GetReturnValue().Set(result); -} + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); -NAN_METHOD(NodeMidiOutput::GetPortName) -{ - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); - if (info.Length() == 0 || !info[0]->IsUint32()) { - return Nan::ThrowTypeError("First argument must be an integer"); + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); } - unsigned int portNumber = Nan::To(info[0]).FromJust(); - try { - v8::Local result = Nan::New(output->out ? output->out->getPortName(portNumber).c_str() : "").ToLocalChecked(); - info.GetReturnValue().Set(result); + if (info.Length() == 0 || !info[0].IsNumber()) + { + Napi::TypeError::New(env, "First argument must be an integer").ThrowAsJavaScriptException(); + return env.Null(); } - catch(RtMidiError& e) { - info.GetReturnValue().Set(Nan::New("").ToLocalChecked()); + + unsigned int portNumber = info[0].ToNumber(); + try + { + return Napi::String::New(env, handle->getPortName(portNumber)); + } + catch (RtMidiError &e) + { + Napi::TypeError::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); + return env.Null(); } } -NAN_METHOD(NodeMidiOutput::OpenPort) +Napi::Value NodeMidiOutput::OpenPort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!output->out) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - if (info.Length() == 0 || !info[0]->IsUint32()) { - return Nan::ThrowTypeError("First argument must be an integer"); + if (info.Length() == 0 || !info[0].IsNumber()) + { + Napi::TypeError::New(env, "First argument must be an integer").ThrowAsJavaScriptException(); + return env.Null(); } - unsigned int portNumber = Nan::To(info[0]).FromJust(); - if (portNumber >= output->out->getPortCount()) { - return Nan::ThrowRangeError("Invalid MIDI port number"); + + unsigned int portNumber = info[0].ToNumber(); + if (portNumber >= handle->getPortCount()) + { + Napi::RangeError::New(env, "Invalid MIDI port number").ThrowAsJavaScriptException(); + return env.Null(); } - try { - output->out->openPort(portNumber); + try + { + handle->openPort(portNumber); } - catch(RtMidiError& e) { - ; + catch (RtMidiError &e) + { + Napi::Error::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); } - return; + + return env.Null(); } -NAN_METHOD(NodeMidiOutput::OpenVirtualPort) +Napi::Value NodeMidiOutput::OpenVirtualPort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!output->out) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - if (info.Length() == 0 || !info[0]->IsString()) { - return Nan::ThrowTypeError("First argument must be a string"); + if (info.Length() == 0 || !info[0].IsString()) + { + Napi::TypeError::New(env, "First argument must be a string").ThrowAsJavaScriptException(); + return env.Null(); } - std::string name(*Nan::Utf8String(info[0])); + std::string name = info[0].ToString(); - try { - output->out->openVirtualPort(name); + try + { + handle->openVirtualPort(name); } - catch(RtMidiError& e) { - ; + catch (RtMidiError &e) + { + Napi::Error::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); } - return; + + return env.Null(); } -NAN_METHOD(NodeMidiOutput::ClosePort) +Napi::Value NodeMidiOutput::ClosePort(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!output->out) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - output->out->closePort(); - return; + handle->closePort(); + return env.Null(); } -NAN_METHOD(NodeMidiOutput::IsPortOpen) +Napi::Value NodeMidiOutput::IsPortOpen(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!output->out) return; + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); + } - v8::Local result = Nan::New(output->out->isPortOpen()); - info.GetReturnValue().Set(result); + return Napi::Boolean::New(env, handle->isPortOpen()); } -NAN_METHOD(NodeMidiOutput::Send) +Napi::Value NodeMidiOutput::Send(const Napi::CallbackInfo &info) { - Nan::HandleScope scope; - NodeMidiOutput* output = Nan::ObjectWrap::Unwrap(info.This()); + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (!output->out) return; - - if (info.Length() == 0 || !info[0]->IsArray()) { - return Nan::ThrowTypeError("First argument must be an array"); + if (!handle) + { + Napi::Error::New(env, "RtMidi not initialised").ThrowAsJavaScriptException(); + return env.Null(); } - v8::Local message = Nan::To(info[0]).ToLocalChecked(); - int32_t messageLength = Nan::To(Nan::Get(message, Nan::New("length").ToLocalChecked()).ToLocalChecked()).FromJust(); - std::vector messageOutput; - for (int32_t i = 0; i != messageLength; ++i) { - messageOutput.push_back(Nan::To(Nan::Get(message, Nan::New(i)).ToLocalChecked()).FromJust()); + if (info.Length() == 0 || !info[0].IsBuffer()) + { + Napi::TypeError::New(env, "First argument must be a buffer").ThrowAsJavaScriptException(); + return env.Null(); } - try { - output->out->sendMessage(&messageOutput); + + Napi::Buffer buffer = info[0].As>(); + + try + { + handle->sendMessage(buffer.Data(), buffer.Length()); } - catch(RtMidiError& e) { - ; + catch (RtMidiError &e) + { + Napi::Error::New(env, "Internal RtMidi error").ThrowAsJavaScriptException(); } - return; + + return env.Null(); } diff --git a/src/output.h b/src/output.h index ea8746c..6d62cce 100644 --- a/src/output.h +++ b/src/output.h @@ -1,32 +1,30 @@ #ifndef NODE_MIDI_OUTPUT_H #define NODE_MIDI_OUTPUT_H -#include +#include #include "RtMidi.h" -class NodeMidiOutput : public Nan::ObjectWrap +class NodeMidiOutput : public Napi::ObjectWrap { private: - RtMidiOut* out; + std::unique_ptr handle; + public: - static Nan::Persistent s_ct; - static void Init(v8::Local target); + static std::unique_ptr Init(const Napi::Env &env, Napi::Object target); - NodeMidiOutput(); + NodeMidiOutput(const Napi::CallbackInfo &info); ~NodeMidiOutput(); - static NAN_METHOD(New); - - static NAN_METHOD(GetPortCount); - static NAN_METHOD(GetPortName); + Napi::Value GetPortCount(const Napi::CallbackInfo &info); + Napi::Value GetPortName(const Napi::CallbackInfo &info); - static NAN_METHOD(OpenPort); - static NAN_METHOD(OpenVirtualPort); - static NAN_METHOD(ClosePort); - static NAN_METHOD(IsPortOpen); + Napi::Value OpenPort(const Napi::CallbackInfo &info); + Napi::Value OpenVirtualPort(const Napi::CallbackInfo &info); + Napi::Value ClosePort(const Napi::CallbackInfo &info); + Napi::Value IsPortOpen(const Napi::CallbackInfo &info); - static NAN_METHOD(Send); + Napi::Value Send(const Napi::CallbackInfo &info); }; #endif // NODE_MIDI_OUTPUT_H diff --git a/test/unit/input.js b/test/unit/input.js index 78aa46b..e1ba9a1 100644 --- a/test/unit/input.js +++ b/test/unit/input.js @@ -15,7 +15,7 @@ describe('midi.Input', function() { it('should raise when not called with new', function() { (function() { Midi.Input(); - }).should.throw('Use the new operator to create instances of this object.'); + }).should.throw("Class constructor Input cannot be invoked without 'new'"); }); it('should be an emitter', function() { diff --git a/test/unit/output.js b/test/unit/output.js index e546834..9f6bb7c 100644 --- a/test/unit/output.js +++ b/test/unit/output.js @@ -16,7 +16,7 @@ describe('midi.Output', function() { it('should raise when not called with new', function() { (function() { Midi.Output(); - }).should.throw('Use the new operator to create instances of this object.'); + }).should.throw("Class constructor Output cannot be invoked without 'new'"); }); it('should not be an emitter', function() { @@ -97,7 +97,7 @@ describe('midi.Output', function() { it('should require an array argument', function() { (function() { output.send(); - }).should.throw('First argument must be an array'); + }).should.throw('First argument must be an array or Buffer'); }); }); @@ -107,7 +107,7 @@ describe('midi.Output', function() { it('should require an array argument', function() { (function() { output.sendMessage(); - }).should.throw('First argument must be an array'); + }).should.throw('First argument must be an array or Buffer'); }); }); }); diff --git a/vendor/rtmidi b/vendor/rtmidi index c01a721..84a9942 160000 --- a/vendor/rtmidi +++ b/vendor/rtmidi @@ -1 +1 @@ -Subproject commit c01a721217ab5b83a44e9b01f94cbea2e952a995 +Subproject commit 84a99422a3faf1ab417fe71c0903a48debb9376a diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..db6efd9 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,618 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +debug@4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mocha@^9.0.0: + version "9.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.3" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "4.2.1" + ms "2.1.3" + nanoid "3.3.1" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.2.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +node-addon-api@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" + integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-prebuilds@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/pkg-prebuilds/-/pkg-prebuilds-0.1.0.tgz#7ac38674146708e763a4581a0759d5e8594f61b6" + integrity sha512-ALsGSiwO6EDvjrrFRiv7Q6HZPrqCgTpNxQMFs3P4Ic25cP94DmLy0iGvZDlJmQBbq2IS8xkZrifwkoOHIetY9Q== + dependencies: + yargs "^17.5.1" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + integrity sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q== + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + integrity sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ== + +should-util@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== + +should@^13.2.3: + version "13.2.3" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== + dependencies: + should-equal "^2.0.0" + should-format "^3.0.3" + should-type "^1.4.0" + should-type-adaptors "^1.0.1" + should-util "^1.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.5.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==