diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1916cbe --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +quote_type = single +trim_semicolon = true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cd14ad4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI +on: [push] +jobs: + CI: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: "14" + - name: Restore Dependencies + uses: actions/cache@v2 + id: node-cache + with: + # https://dev.to/mpocock1/how-to-cache-nodemodules-in-github-actions-with-yarn-24eh + path: '**/node_modules' + key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + - name: Install Dependencies + run: yarn install + - name: Build Project + run: yarn run build + - name: Run Tests + run: yarn run test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f06235c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/README.md b/README.md new file mode 100644 index 0000000..18d1f98 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ + +# shelljs-live + +Execute a shell command while piping output directly to your console. + +Motivated by [shelljs] exec's [inability to preserve colors](https://github.com/shelljs/shelljs/issues/86). +Also, great for watcher tasks, as output is not buffered. + +Very portable (uses [cross-spawn]), especially when specifying `command` as an array of strings (more below). + +## Installation + +```sh +npm install shelljs shelljs-live +``` + +The `shelljs` package is a peerDependency of `shelljs-live` and must be installed. + +## Traditional API + +``` +live(command [, options] [, callback]) => statusCode +``` + +- `command` - A string **OR** an array of strings: + - If a string, run as a shell statement. The shell might expand globs or have opinions about escaping. This is not very portable. + - If an *array* of strings, all arguments are piped directly to a command and no escaping is necessary. **This is recommended.** +- `options` - *Optional*. [More info](#options). +- `callback` - *Optional*. Called on success/failure. Receives the `statusCode`. Implies the `async:true` option. +- `statusCode` - A number, or in some cases `null`. Success means `statusCode === 0`. + +Synchronous usage: + +```js +const { live } = require('shelljs-live') + +const statusCode = live(['ps', '-ax']) // live('ps -ax') works too. not recommended +if (statusCode === 0) { + console.log('Success') +} else { + console.log('Failure') +} +``` + +Asynchronous usage: + +```js +const { live } = require('shelljs-live') + +live(['ps', '-ax'], (statusCode) => { + if (statusCode === 0) { + console.log('Success') + } else { + console.log('Failure') + } +}) +``` + +## Promise API + +``` +live(command [, options]) => promise +``` + +- `command`: A string **OR** an array of strings: + - If a string, run as a shell statement. The shell might expand globs or have opinions about escaping. This is not very portable. + - If an *array* of strings, all arguments are piped directly to a command and no escaping is necessary. **This is recommended.** +- `options`: *Optional*. [More info](#options). +- `promise`: A [Promise] that triggers success when status code equals `0`, failure otherwise. Neither handler receives the status code. + +Usage: + +```js +const { live } = require('shelljs-live/promise') + +live(['ps', '-ax']).then(() => { + console.log('Success') +}, () => { + console.log('Failure') +}) +``` + +Or if you want to use `await` and don't care about handling errors: + +```js +const { live } = require('shelljs-live/promise') + +await live(['ps', '-ax']) +console.log('Success') +``` + +## Options + +- `async`: Asynchronous execution. If a callback is provided, or using the Promise API, it will be set to true, regardless of the passed value (default: `false`). +- `fatal`: Exit upon error (default: `false`, inherits from [ShellJS Config][shelljs-config]). +- `silent`: Do not echo program output to console (default: `false`, inherits from [ShellJS Config][shelljs-config]). + +Any other option, such as `cwd`, is passed directly to [spawn]. + + +[shelljs]: https://documentup.com/shelljs/shelljs +[shelljs-config]: https://documentup.com/shelljs/shelljs#configuration +[cross-spawn]: https://www.npmjs.com/package/cross-spawn +[Promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise +[spawn]: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options diff --git a/package.json b/package.json new file mode 100644 index 0000000..a404b37 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "shelljs-live", + "version": "0.0.1", + "repository": "https://github.com/arshaw/shelljs-live.git", + "author": "Adam Shaw", + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": "./dist/index.js", + "./promise": "./dist/promise.js" + }, + "scripts": { + "clean": "rm -rf dist", + "build": "tsc", + "watch": "tsc --watch", + "test": "./test.sh" + }, + "peerDependencies": { + "shelljs": "^0.8.4" + }, + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "devDependencies": { + "@types/cross-spawn": "^6.0.2", + "@types/shelljs": "^0.8.9", + "shelljs": "^0.8.4", + "typescript": "^4.4.3", + "yargs": "^17.1.1" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f7ca6ef --- /dev/null +++ b/src/index.ts @@ -0,0 +1,76 @@ +import { SpawnOptions } from 'child_process' +import * as spawn from 'cross-spawn' +import { config } from 'shelljs' + +export type Callback = (status: number | null) => void +export type Options = SpawnOptions & { async?: boolean, fatal?: boolean, silent?: boolean } + +export function live(command: string | string[], options?: Options): number | null +export function live(command: string | string[], callback: Callback): number | null +export function live( + command: string | string[], + options: Options | undefined, + callback: Callback, +): number | null +export function live( + command: string | string[], + optionsOrCallback?: Options | Callback, + callback?: Callback, +): number | null { + let options: Options + + if (typeof optionsOrCallback === 'function') { + callback = optionsOrCallback + options = {} + } else { + options = optionsOrCallback || {} + } + + let command0: string + let args: string[] + let shell: boolean + + if (Array.isArray(command)) { + command0 = command[0] + args = command.slice(1) + shell = false + } else { + command0 = command + args = [] + shell = true + } + + if (!command0) { + throw new Error('Must specify a command') + } + + const fatal = options.fatal ?? config.fatal + const silent = options.silent ?? config.silent + const spawnOptions: SpawnOptions = { + ...(silent ? {} : { stdio: 'inherit' }), + ...options, + shell, + } + + function handleStatus(status: number | null) { + if (status === null || status !== 0) { + if (fatal) { + console.error(`Command '${command0}' failed with status code ${status}`) + process.exit(status || 1) + } + } + if (callback) { + callback(status) + } + } + + if (options.async || callback) { + const childProcess = spawn(command0, args, spawnOptions) + childProcess.on('close', handleStatus) + return null + } else { + const { status } = spawn.sync(command0, args, spawnOptions) + handleStatus(status) + return status + } +} diff --git a/src/promise.ts b/src/promise.ts new file mode 100644 index 0000000..4b463e7 --- /dev/null +++ b/src/promise.ts @@ -0,0 +1,15 @@ +import { live as origLive, Options } from './' + +export function live(tokens: string[], options?: Options): Promise { + return new Promise((resolve, reject) => { + origLive(tokens, options, (status) => { + if (status === 0) { + resolve() + } else { + reject(new Error(`Command '${tokens[0]}' failed with status code ${status}`)) + } + }) + }) +} + +export { Options } from './' diff --git a/test.js b/test.js new file mode 100644 index 0000000..30516c7 --- /dev/null +++ b/test.js @@ -0,0 +1,88 @@ +const yargs = require('yargs/yargs') +const { hideBin } = require('yargs/helpers') +const shell = require('shelljs') +const { live } = require('./dist/index') +const { live: promiseLive } = require('./dist/promise') + +const argv = yargs(hideBin(process.argv)).argv +shell.config.silent = Boolean(argv.silent) +shell.config.fatal = Boolean(argv.fatal) + +// TODO: test silent/fatal passed-in as options + +let successStatusA = live(argv.shell ? 'ls -al && cd .' : ['ls', '-al']) +if (successStatusA !== 0) { + console.error('should succeed') + process.exit(successStatusA) +} + +let successStatusB = live(argv.shell ? 'ls -al && cd .' : ['ls', '-al'], { + cwd: argv.cwd || '.' +}) +if (successStatusB !== 0) { + console.error('should succeed in different CWD') + process.exit(successStatusB) +} + +let failureStatusA = live(['asdfasdfasdf']) +if (failureStatusA === 0) { + console.error('status should be non-zero when command does not exist') + process.exit(1) +} + +let failureStatusB = live(['ls', 'asdfasdfasdf']) +if (failureStatusB === 0) { + console.error('status should be non-zero when command fails') + process.exit(1) +} + +function testSuccessAsync() { + let start = Date.now() + return new Promise((resolve, reject) => { + live(['sleep', '1'], (status) => { + let end = Date.now() + let dur = end - start + if (status !== 0) { + reject(new Error('async did not succeed')) + } else if (dur < 1000) { + reject(new Error('async is not async')) + } else { + resolve() + } + }) + }) +} + +function testSuccessPromise() { + let start = Date.now() + return promiseLive(['sleep', '1']).then(() => { + let end = Date.now() + let dur = end - start + if (dur < 1000) { + throw new new Error('promise is not async') + } + }, () => { + throw new Error('promise did not fail') + }) +} + +function testFailurePromise() { + return promiseLive(['ls', 'asdfasdfasdf']).then(() => { + throw new Error('async should fail') + }, () => { + // handle error by doing nothing + }) +} + +Promise.all([ + testSuccessAsync(), + testSuccessPromise(), + testFailurePromise(), +]).then(() => { + if (!argv.silent) { + console.log('Successfully ran all tests') + } +}, (err) => { + console.error(err.toString()) + process.exit(1) +}) diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..8142da0 --- /dev/null +++ b/test.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# start in root +cd "`dirname $0`" + +# check a failure run +resD=$(node ./test.js --fatal 2> /dev/null) +exitCode=$? +if [ "$exitCode" == 0 ]; then + echo "Failure code should be given" + exit 1 +fi + +# check successful run +resA=$(node ./test.js 2> /dev/null) +exitCode=$? +if [ "$exitCode" != 0 ]; then + echo "Failure A" + exit 1 +fi + +# check another successful run, +# but run a test using the cwd as 'src' +resB=$(node ./test.js --cwd src 2> /dev/null) +exitCode=$? +if [ "$exitCode" != 0 ]; then + echo "Failure B" + exit 1 +fi +if [ "$resA" == "$resB" ]; then + echo "Failure, output should differ with different cwd" + exit 1 +fi + +# check shell evaluation +resC=$(node ./test.js --shell src 2> /dev/null) +exitCode=$? +if [ "$exitCode" != 0 ]; then + echo "Failure C" + exit 1 +fi +if [ "$resA" != "$resC" ]; then + echo "Failure, output should be same whether using shell or not" + exit 1 +fi + +# check a silent run +resC=$(node ./test.js --silent) +if [ -n "$resC" ]; then + echo "Failure, output should be silent" + exit 1 +fi + +echo "Successfully ran all tests" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a972eed --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ES2019", + "module": "CommonJS", + "moduleResolution": "Node", + "declaration": true, + "rootDir": "src", + "outDir": "dist" + }, + "include": [ + "src/**/*" + ] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..c100121 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,310 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/cross-spawn@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" + integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== + dependencies: + "@types/node" "*" + +"@types/glob@*": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "16.9.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.6.tgz#040a64d7faf9e5d9e940357125f0963012e66f04" + integrity sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ== + +"@types/shelljs@^0.8.9": + version "0.8.9" + resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.9.tgz#45dd8501aa9882976ca3610517dac3831c2fbbf4" + integrity sha512-flVe1dvlrCyQJN/SGrnBxqHG+RzXrVKsmjD8WS/qYHpq5UPjfq7UWFBENP0ZuOl0g6OpAlL6iBoLSvKYUUmyQw== + dependencies: + "@types/glob" "*" + "@types/node" "*" + +ansi-regex@^5.0.0: + 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: + 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" + +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== + +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" + +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 sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +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== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +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@^7.0.0: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + 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" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + 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== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-core-module@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" + integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== + dependencies: + has "^1.0.3" + +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== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +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 sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +resolve@^1.1.6: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shelljs@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +typescript@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== + +which@^2.0.1: + 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" + +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 sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +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.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@^17.1.1: + version "17.1.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" + integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== + 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"